The Type sos_Container

Containers provide a simple mechanism for synchronization, recovery, and clustering of objects. Each object of SOS belongs to exactly one container, which is determined when an object is created. Containers are handled similar to SOS objects; however, sos_Container is not a SOS class but an external type.[*]Furthermore, a container object cannot be created within another container, whereas all non-container objects must be created within a container. They are affiliated to that container throughout their lifetime. With the destruction of a container all objects that have been created within this container will be destroyed[*].

All operations that modify the value of an object require that the corresponding container has explicitly been opened for writing. An operation that reads the value of an object implicitly opens the corresponding container for reading, if it has not yet been opened.

Although sos_Container is not a SOS class, some of its operations can best be introduced in a SOS like class declaration:[*]

enum sos_Sync_mode {WAITING,TESTING};
enum sos_Open_result {OPENED,LOCKED,UNACCESSIBLE};
enum sos_Access_mode {READING,WRITING};
enum sos_Container_status {READABLE,WRITEABLE,UNAVAILABLE,DESTROYED};
enum sos_Existing_status {NOT_EXISTING, PERHAPS_EXISTING};

class sos_Container
{
public:

    static sos_Container create();

    sos_Container_status status();

    sos_Open_result open (sos_Access_mode, sos_Sync_mode);
    sos_Open_result access (sos_Access_mode, sos_Sync_mode);
    void close();
    void destroy();

    void commit();
    void reset();

    void clear();

    sos_Object root_object();
};
The create operation for containers differs from the create method for SOS classes because it has no parameter for the container in which the new container shall be allocated.

The status of a container, i.e. whether it is closed, opened for reading, or opened for writing, can be inspected by the status operation.

The open operation opens the container for either reading or writing, depending on the access mode parameter.

The (inter-process) synchronization strategy permits that a container may be either opened several times for reading or once for writing. A parameter specifies the desired reaction if the container cannot be opened: the open operation may then either wait or return immediately with an error code. From the applications point of view, the sole purpose of opening a container is synchronization.

When a container is opened with read permission, it can be upgraded to write permission and vice versa using the access operation. The container must have been opened and the new access mode is given by a parameter. Calls to access are synchronized in the same way as calls to open.

A close operation on a container makes it accessible to other processes according to the synchronization strategy. Additionally, closing a container which is opened for writing implies a commit on this container.

Destruction of a container is accomplished by destroy. Destruction of a container requires exclusive access to it, i.e. the container must be opened for writing. Like all other modifications on containers the destroy operation must be committed to remove the container persistently.

When a container is opened for writing, a (conceptual) copy of it is made and all changes will be made to the copy. The commit operation replaces the original container by its copy; with reset the changes made since the last commit operation are ignored. commit and reset must only be called on containers opened for writing.

Furthermore, a container opened for writing may be emptied using the clear operation. All objects created within the container are destroyed, but the container itself continues to exist.

The function root_object returns the object that was created as the first object in the container. The root object is particularly suited for objects acting as an entry point for a container from where other objects stored in the container can be reached. Note, that the association between a container and its root object is fixed from the moment on when this object is created in the container, and that this relation can never be changed. In case that an object that was created as the root object of a particular container is destroyed, the result of function root_object is undefined.

There exist some dedicated containers which neither must be destroyed nor can be created. These are the temporary container (named TEMP_CONTAINER) and the root container (named ROOT_CONTAINER). Each process has its own temporary container. The contents of a temporary container will be deleted when its associated process terminates, i.e. it is non-persistent. However, compared to persistent containers the access to the temporary container is more efficient. A temporary container is automatically opened for writing and neither close nor commit or reset are allowed on it.

The root container acts like any other persistent container but it has a fixed identity. The root object (see above) of the root container plays an even more special role because this is the only SOS object that can be accessed ``directly'', i.e. without knowledge of object references stored in another SOS object. This object is an instance of class Directory<sos_Object> (see Section [*]). It is named root directory because all (persistently) existing SOS objects must be reachable from this object. The root directory can be obtained by calling the static method root of the generic class Directory.

Usually applications require several containers to be opened. In order to avoid deadlocks when two applications try to gain access to the same set of containers, containers can be opened (and closed) in sets. Operations of the type sos_Container_set provide means for constructing sets of containers, and for opening, closing, committing, and resetting these container sets. These operations perform their actions atomically: either all containers in the set are opened or none is opened.

A detailed description of the interface is given in Appendix [*].