DRS: Distributed Repository System

By Mark Roth

 

 

 

 

 

– System Design and Achievements –

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Distributed Operating Systems II

Rochester Institute of Technology

Andrew T. Kitchen

May 20, 1999

 

 

System Overview

When working on projects in teams, it is often difficult and time consuming to coordinate simultaneous access to a large number of resources such as source code and documentation. The difficulty level increases with the team size, and with the amount of information that needs to be coordinated. Further complexity is introduced when team members are geographically separated from each other, as is often a reality in today’s modern business environment. These complexities introduce a communications barrier that often leads to degraded productivity in the form of duplicated efforts or clumsy resource sharing. Though shared file systems and mapped network drives provide a basic mechanism for sharing files, they are not a complete solution in that they have limited searching capabilities and limited file locking capabilities. In addition, issues such as file naming convention differences (e.g. MS-DOS’ 8.3 filename limit, or Windows NT’s allowing spaces in filenames) make it difficult for comprehensive file sharing in heterogeneous environments.

A distributed repository system would seem to be an ideal solution to this problem. The DRS is intended to be a scalable distributed system that allows clients to gain access to a generic repository of objects (such as documents and source code). These objects are stored on a number of repository servers that are interconnected. Though the objects are split between these servers, this fact is transparent to users of the system. Java RMI is used to provide open access to the repository for any client platform. The repository will also provide a locking service that allows users to claim temporary ownership of a version of an object so that it is not modified by other users.

Such a system is an example of a distributed application in the purest sense. According to Coulouris, et al., the key characteristics of a distributed system are "resource sharing, openness, concurrency, scalability, fault tolerance and transparency" (Coulouris, 10). A Distributed Repository system must deal with these issues as well as other issues such as security.

System Design

The design of the system can be broken down into three categories, the Data Store module, the Client/Server Module, and the Errand hierarchy. Each is described in the following sections. A detailed design diagram of each of these modules can be found in the Diagrams section, in UML format.

The Data Store Module

All of the classes in this group are intelligent data structures that together represent the state of a single repository. This repository is made accessible by starting an instance of the DRS server, as described in the next section. These classes all implement the java.io.Serializable interface, and thus objects of these classes can be easily transported over a network, or saved to disk.

A repository contains a UserDatabase that contains a list of Users that are permitted to log on to a server hosting this repository. A User object contains information such as login id, password, account enabled status, and the like. Each repository has its own user database, but a user can appear in more than one user database if so desired. However, if this is done, there is no synchronization between account information, and each account is treated as a distinct entity.

The Repository class itself contains a unique name for the repository, a reference to the user database, the root directory, and a universal prefix. A universal prefix allows partitioning of a huge, global repository system into manageable groups of a reasonable number of servers.

The remaining classes in this group represent the hierarchy of files and directories that appear in the repository. The RepositoryObject class forms the base of the class hierarchy, and provides attributes common to all repository objects, such as a name, the id of the server containing the object, and the directory containing the object. The RepositoryFile class represents objects in the repository that are files. Each file contains one or more versions. Each version consists of the version name, check-in time, the owner of the check-in, the parent version, who has a lock on the version, and the physical name of the file containing the version, to be found on the server containing the object. The RepositoryDirectory class represents a directory, which can contain any type of RepositoryObject, including other directories, making for the possibility of a directory hierarchy.

The Client/Server Module

Each of the classes in this module cooperates to perform services to a user or an application that wishes to use the services of the DRS. To access the DRS, a client launches DRSClient, or a similar application, which logs in to a specific server through RMI. The user must log on to a server containing her or his account information and home directory. Note that even though a user logs in through a single server, all the files and directories contained on the other servers are seamlessly accessible to the user as well.

The DRSClient class provides a simple text ftp-style command-line interface that allows a user to navigate the hierarchy of directories, files, and versions stored within a repository, and store and retrieve files to and from the repository.

The DRSServer interface, and related classes, embody the distributed repository system server itself. It provides it’s services through Java RMI, allowing for flexible expansion of its capabilities (more on this in the Errand Hierarchy section).

The FileSender and FileReceiver classes provide a standard way for files to be transferred to and from a server. Each can operate in either client mode or server mode, allowing the server to be the one that sets up a ServerSocket rather than the client. Files are transferred one block at a time, allowing for efficient transfer of files of any size.

The ServerList class maintains a list of repository names and the servers they are connected to. Throughout the lifetime of a server, this list is continually updated every time a new server is hooked into the system. This list allows clients to contact the server containing the file directly, instead of piping it through the static server linkage.

The Session class allows for tracking of user sessions with servers. When a user logs in to a server, a Session object is generated for that user, and that Session object must be used for each request the client sends.

To keep the state of the server persistent, the server reads the repository information from a file upon start-up and writes the information back to the same file upon shut-down. This is easily achieved through the use of Java serialization.

The Errand Hierarchy

When a client talks to a server, or when a server talks to another server, the client or server initiating the request is said to "run an errand" on a server. This hierarchy provides a flexible way to represent the errands that are run within the system.

At the root of the hierarchy is the abstract Errand class, which represents an errand that is to be run on a server. It provides a standard way to indicate that an errand has succeeded or failed, and embodies a Session object (present for authentication and authorization purposes) representing the session of the client or server requesting the errand to be run.

The Request class extends the Errand class, and represents a request from a client to a server. Sample requests include "md" (make a directory), "ls" (list the contents of a directory), and "lock" (lock a version of a file).

The Favor class also extends the Errand class, but represents a request from a server to another server. Sample favors include "synchronize repository" (synchronize the updated contents of a repository with other repositories within the system), and "merge server list" (add entries to the server list because new servers have joined the system). Many favors require updates to be propagated to all servers in the current universal prefix. To do this, the DRS Server is able to recursively forward a request to all hosts in the system, provided that each Favor supply a unique ID so that a server knows if it has seen that same favor request before. The Favor class supplies this unique ID by generating a random long integer (there is a very low probability that two simultaneous requests will generate the same number). The server maintains a list of the last 100 favor requests it has seen and makes sure not to process or forward the favor request if it has already done so in the past.

Requests and Favors are designed to be as low-level as possible. This allows for the development of many different user interfaces without the need to create too many new corresponding Request classes. Because of the object-oriented nature of this errand hierarchy, new requests and favors can be added to the system quickly and easily, making the system very flexible. All that needs to be done to add a feature to the system is to extend a class from Request or Favor and write code for the client to be able to make use of this new feature.

Server-Server and Client-Server Communication

During the execution of the system, there is communication that takes place between the servers and other servers. Administrators of the DRS servers are permitted to link servers together by using the "accept" and "link" commands, forming a linked graph of servers. When they do so, two sockets are opened between the servers, one for sending favor request and receiving replies, and one for receiving favor requests and sending replies. Only servers within the same universal prefix are permitted to be linked together in this manner. In addition, the servers will form their own links as users request files that are on other servers. Some of these links may be temporary. A server will never link to another server that is not within its graph unless explicitly told to do so using the "link" command. All client-server communication is performed using Java’s RMI facilities.

Achievements / Shortcomings

The overall goal, to design and implement a distributed repository system, was met. However, though the implementation of a production-quality full-fledged distributed repository system is beyond the scope of this project, it is still important to note the shortcomings of the current implementation so that the system can be built upon in the future. In general, shortcomings were on the implementation side, and not on the design side. The following sections discuss various aspects of the system, as related to DFS theory.

Goals

The DRS and the DFS have many goals in common. In particular, there is a great need for transparency on many different levels. In addition, security plays a vital role to ensure that users do not abuse the system. Flexibility is always an important goal in systems such as these, so that they can respond efficiently to both new and legacy environments. Stability is also a mutual goal. However, whereas the typical Distributed File System puts a large emphasis on efficiency, this is not a goal of the Distributed Repository System.

Transparency

One of the major goals of distributed systems in general is transparency to the end-user. Transparency is typically broken down into a number of categories. A plus next to the category indicates that DRS handles this category successfully. A minus indicates it does not. A slash indicates that DRS handles this category partially, but not fully.

Security

Security is a critical feature of any production DFS or DRS. Without proper security in place, users can read or tamper with other users’ files, or even accidentally modify portions of the system not originally intended. In its current implementation, DRS is severely lacking in security features.

One area that is lacking is in authorization. Currently, the user’s password is a plaintext commandline parameter to the DRS Client software. This is certainly not desirable, as passwords should never be visible to other users standing by. In addition, these same passwords are sent with every request over the network in plaintext format, and are stored in the repository file in plaintext when the server exits.

Server to server communication has security problems as well. Currently, servers blindly accept connections from any Java application. Someone with access to the DRS Java class files can easily build a fake server that will send favor requests to other servers since there is no authentication between servers.

Perhaps most importantly, there is no filesystem security. This means that every user has public read / write / delete access to every file and directory in the system. To make matters worse, a simple "rm" on a close-to-root directory can eliminate entire branches of the filesystem with no easy way to recover.

The only security feature that is implemented is preventing non-administrator users from instructing the server to accept connections from foreign servers and linking to other servers. It is important to note that most of these security issues can be resolved by making minor changes to the design of the system. For example, favors and requests can be sent through an encrypted socket instead of a normal socket, and filesystem access can be made more secure by creating a capability granting service, or by adding access control lists to RepositoryObjects.

Flexibility

In order to interface with many different types of systems, DRS is designed from the ground up to be flexible. The design section discusses several of the flexible aspects of the system. DRS is flexible in other ways as well. For example, because host names are stored as part of a repository object identification, servers can be taken down and restarted on arbitrary hosts by simply shutting down a server restarting it on another system, and reconnecting it to at least one server in the graph.

Stability

Several measures have been taken in the design of DRS to make it more stable. In particular, all requests from the client to the server are idempotent, so they can be received more than once without having a negative effect on the system. In addition, DRS’ approach to sharing is essentially immutable file semantics, which has the advantage that no two users can be modifying the same version of the same file at the same time. The only possibility of inconsistency is when two networks have been disconnected for a long time and file and directory names clash. In this case, the local server view takes precedence over the more global view, as to prevent loss of information to the local clients.

Efficiency

Efficiency beyond reasonable performance is not a major goal of the Distributed Repository System. This is because, like Andrew and Coda, DRS follows the upload/download file-access model, so the typical use of the repository system is to transfer files from the repository to the local file system, from which point a user can access them efficiently. That aside, there are certainly places within the current implementation of the system that can use a performance boost.

All communication between servers is currently done through TCP sockets. Though using UDP sockets may speed updates between servers and reduce network bandwidth, TCP sockets make for a more flexible system, allowing servers within the same universal prefix to be present on hosts not within the same local network. This comes, unfortunately, at the expense of performance. A good compromise may be to implement a combination of both techniques.

Another weak area in efficiency is in the directory updating. Whenever the directory structure changes, the entire repository structure is sent to all other servers. Though this makes it easy to verify all servers are seeing a consistent picture, it is extremely inefficient.

Summary

Overall, the system successfully demonstrates the possibility of creating a stable, flexible, Distributed Repository System. Most of the original goals were implemented, and though there are many features left to be desired, many of those are beyond the scope of a one-quarter project.

Appendices

Bibliography

Coulouris, George, et al. Distributed Systems: Concepts and Design. 2nd Ed. (Harlow, England: Addison-Wesley, 1996).