|
|
The organization of the data in the transient data store is a tree of data objects. This structure resembles very closely a typical file system with files and directory files, where directory files may contain also some data attributes. Each data object can potentially be a node of the tree and in addition also contain its own data members or properties. In the case of LHCb the distinction was made that all directory nodes in the transient data store are plain instances of the type DataObject and only end-leaves may contain data payload. This distinction however is artificial and not mandatory. As in the case of the file system, the identification (i.e. file name) is unique at the level of its container. The “full path” identification that uniquely identifies the object in the store is then made by concatenating the identifiers (names) of all the ancestor nodes with its own identifier. Most of the event data objects are very tiny data objects. For example, for each event there are hundreds if not thousands of hit objects and digits each of which is a few bytes long. Since these tiny objects should not be identified individually in the transient data store (the same arguments applies for the persistent store), these objects are placed into containers, which are identifiable. The tiny objects must be of the basic type ContainedObject. To support other framework features such as persistent C++ pointers contained objects must be placed in containers, which support a minimal interface and inherit from ObjectContainerBase. To summarize, the following types of objects exist in the transient data store:
Identifiable objects with data members (properties) which are also nodes from where other objects hang.
Normal identifiable objects
Simple objects which are contained in one identifiable object.
Following the analogy with the file system it is equivalent to say that in the data store are “directories with properties”, “files” and “records”. It is clear that a directory is a special type of “file”. Having this strong hierarchical structure between data objects (aggregation) does not preclude other kinds of relationships between the different objects.
The following pictures shows the dependencies and the collaboration of the objects residing in the transient data store:
Base class of any object, which may be hosted by the transient data store. The class encapsulated the triangle between the object address, the registry entry in the transient data store and the object.
Abstract base class managing a set of contained objects. When adding objects, the container class takes over ownership.
This class represents a container, where the contained objects are accessed by a key. Such a key can be any class, which is able to convert to and from a 32-bit (long) integer. To insert objects into the container, this implementation determines the key in the following way:
If the object is already keyed, the object's key is kept and cannot be modified.
If the object is NOT keyed, and a key is supplied, this key is used to register the object in the map and the same key is given to the object.
If the object is NOT keyed, and NO key is supplied, a key is generated by the map implementation and this key is given to the object.
It is not possible to insert two objects with the same key into the same container. This causes an exception. Access to objects is given two-fold:
Using iterators. This access is very efficient. The container however, may not be manipulated: No objects may not be inserted or removed using iterators.
Using object keys: This access patterns provides random access to objects.
The KeyedContainer class uses for further specialization a traits class. By specializing these traits extra behavior can be forced on request for special containers or special keys.
Base class for all non-identifyable objects which are addressable by persistent pointers (SmartRef or SmartRefVector). It guarantees the navigability from the contained object back to its container.