The e4_Storage class provides persistent storage of markers and elements reachable from those markers. The representation of the physical storage is hidden in a driver, selected at construction time. Drivers for various databases can be easily constructed. The e4Graph package comes with a driver for MetaKit based storage.
A user application may have any number of storages open at a given time, limited only by the available machine resources. Each storage can use a different driver, storing its data in a variety of representations such as flat files or relational databases. The e4_Storage class provides methods to retrieve the name and driver identifier that were used to open the storage.
The storage representation is reference counted and is closed automatically when the last reference is discarded. The e4Graph package strongly encourages a programming style that uses stack allocated instances and so-called dot-based method invocation. Programming with pointers to instances allocated on the heap is possible but cumbersome and, unless care is taken, may lead to reference counting errors and memory leaks.
The e4_Storage class provides assignment and comparison operators, as shown in the following code snippet:
If auto-commit is turned on, any changes are committed to the storage at the time it is closed. Auto-commit is turned on by default. Changes can also be committed at any time under the control of the user program. A storage is considered dirty if any marker, node or vertex in it has been modified and the change has not yet been committed. In the following example, the storage is automatically closed and committed when the instance s goes out of scope:e4_Storage s("mystorage", E4_METAKIT); ... if (s.IsValid()) { printf("The storage \"%s\" is valid\n", s.GetName()); } ... e4_Storage another = s; ... if (s == another) { printf("Yes, they are one and the same!\n"); }
The global variable invalidStorage refers to a constant instance of e4_Storage that is guaranteed to be invalid. You can assign this instance to a local e4_Storage variable to discard the reference to another storage it contains, as shown in the following example:{ e4_Storage s("mystorage", E4_METAKIT); ... }
The assignment to s causes the number of references to the storage named mystorage to drop to zero, and it is automatically closed and committed if needed. Remember to assign invalidStorage to instances of e4_Storage embedded within heap allocated structures before these structures are freed, to ensure that the reference count of any storages referenced by the embedded instances is correct. When a storage is closed, any e4_Marker, e4_Node and e4_Vertex instances held by the user program that refer to elements within that storage also become invalid.e4_Storage s("mystorage", E4_METAKIT); ... s = invalidStorage; if (s.IsValid()) { printf("Something fishy here!\n"); }
Each storage can contain any number of markers. The e4_Storage class provides operations to count the markers in a storage, to retrieve a named marker, and to retrieve the storage name and driver selector.
Deletion A storage may contain cyclical graph structures. The deletion mechanism attempts to delete all storage as it becomes unreachable. However, sometimes determining whether a node is really unreachable is very costly. In these situations, the deletion mechanism defers deletion till later and marks the node as a potential leaked unreachable node.
The deletion mechanism guarantees to delete all nodes that are not members of a cycle. If a node is a member of a cycle and its first parent is reachable from outside the cycle, that node is reachable, and will not be marked as potentially leaked. If the first parent is not itself reachable, the node is marked as potentially unreachable and leaked. Also, if the first parent is a member of a cycle, the node is marked as potentially unreachable and leaked.
e4Graph provides a way for a program using the library to detect when a storage potentially contains leaked unreachable nodes, and a garbage collection mechanism to collect any nodes that are really unreachable.
Whenever an application makes significant changes to a storage, such as adding or deleting a node, e4Graph fires an event that can be intercepted by a callback function registered by the application. For example, when a node is deleted, e4Graph fires a node deletion event which can be intercepted by a callback registered with that storage by the application. The callback receives the node that is about to be deleted as an argument; it can do any cleanups required by the application, such as removing the node from data structures private to the application.
Events are fired when the application explicitly requests the changes through the appropriate operation on a storage, node or vertex, or when the application implicitly causes the change, such as when a node is removed because a marker was removed and the node becomes unreachable.
The following events can be intercepted by an application using e4Graph,
by registering callbacks for each specific event:
Event Name | When Fired: | Callback Function Type: |
Marker Addition | After a new marker is added to a storage. | typedef void (*e4_MarkerAddCallbackFunction)(void *clientData, e4_Marker m) |
Marker Deletion | Right before a marker is removed from the storage. | typedef void (*e4_MarkerDelCallbackFunction)(void *clientData, e4_Marker m) |
Node Addition | After a new node is added to a storage. | typedef void (*e4_NodeAddCallbackFunction)(void *clientData, e4_Node n) |
Node Deletion | Right before a node is removed from the storage. The callback may be deferred until a garbage collection is initiated by the program using the library. | typedef void (*e4_NodeDelCallbackFunction)(void *clientData, e4_Node n) |
Vertex Addition | After a new vertex is added to a storage. | typedef void (*e4_VertexAddCallbackFunction)(void *clientData, e4_Vertex v) |
Vertex Deletion | Right before a vertex is removed from the storage. The callback may be deferred until a garbage collection is initiated by the program using the library. | typedef void (*e4_VertexDelCallbackFunction)(void *clientData, e4_Vertex v) |
Vertex Modification | Right after a vertex value is modified. | typedef void (*e4_VertexModCallbackFunction)(void *clientData, e4_Vertex v) |
The application can register, through interfaces described below, any number of callback functions for each event for a given storage. At callback registration time the application supplies the address of the function to call as well as as an arbitrary client data argument accessed through a void * pointer. The client data is passed as the first argument to the callback function when the event is fired, and the e4Graph storage element (marker, node or vertex, respectively) on which the event occurs is passed as the second argument. Your application can also register the same callback function several times, with different client data pointers; in that case, the callback function will be invoked several times for each event, each time with the appropriate client data and the e4Graph storage element on which the event occurs. When several callback functions are registered for an event, the order in which they are called is undetermined; therefore applications should not rely on the order in which callback functions are invoked for a specific event. Similarly, when an event applies to several entities (e.g. a deletion event for several vertices), the order in which callback functions are called is undetermined.
A single deletion, e.g. a vertex deletion, may cause implicit deletion of a large number of other entities because they become unreachable. When the deletion event is fired for such a cascaded deletion operation, all deletion callbacks are invoked before any change is made to the storage. This allows the deletion callbacks to operate in a predictable state. Deletion callbacks always occur in a type-ordered manner: first the deletion callback functions for all vertices to be deleted are called, then the ones for all markers, and finally the deletion callback functions for all nodes to be removed are invoked.
When a storage is emptied out with the MakeEmpty operation, a deletion event is fired for all removed entities in the order described above. As above, the deletion event is fired before any change is made to the storage, to allow the deletion callback functions to operate in a predictable environment. When a storage is deleted with the Delete method but not previously emptied, no deletion events fire.
Callback functions should be careful to avoid actions that may cause infinite loops. For example, a vertex modification callback function should not modify the value of the same or another vertex, otherwise an infinite chain of callback events is created. Similarly, deletion callback functions should not attempt to prevent the deletion by attaching the to-be-removed entity to another entity. Doing this may result in memory corruption or incorrect storage structure.
A deletion callback may not occur immediately when a node or vertex become unreachable. This is happens when a deletion defers further checking on a node or vertex when doing the check at this time would be too expensive. The deletion callback is not invoked at that time because the library has not yet discovered that the node or vertex is really unreachable. The deletion callback will happen for those nodes and vertices that are really unreachable when a garbage collection is initiated by the program using the library.
To cancel a specific callback function for an event, your application can use the appropriate interface described below, supplying the same arguments as used when the callback function was registered. After the callback function is unregistered, that callback function will no longer be called with that client data when the event is fired; other callback functions registered for that event continue to be called when the event is fired. All registered callback functions are automatically removed when the storage on which they are registered is closed.
Methods and Constructors of e4_Storage
The following methods are defined for the e4_Storage class:
e4_Storage() | Default constructor. Returns a storage that is not connected to a persistent representation and is invalid. |
e4_Storage(const e4_Storage &ref) | Constructs a storage by copying the state of ref. The new storage and ref refer to the same underlying persistent representation. |
e4_Storage(const char *name, const char * storageKind) | Constructor. Returns a storage with the given name, using the storage driver identified by the storageKind argument. |
~e4_Storage() | Destructor. The underlying representation is reference counted and closed automatically when the last reference to it is discarded. If auto-commit is turned on, then changes to the storage are committed when the last reference is discarded. |
bool operator==(const e4_Storage &comp) const | Returns true if comp refers to the same storage instance as this or if both are invalid, false otherwise. |
bool operator!=(const e4_Storage &comp) const | Returns true if comp does not refer to the same storage instance as this, false if they are the same or if both are invalid. |
e4_Storage & operator=(const e4_Storage &ref) | Copies the state of ref to this e4_Storage instance and returns this. |
void AutoCommit(bool on) const | Turns auto-commit on or off. When on is true, the e4_Tree package automatically commits changes to the storage when it is closed. |
bool AutoCommit() const | Returns true when auto-commit is true, false otherwise. |
bool Commit() const | Commits any changes to the storage at this time. Returns true if the commit succeeded, false otherwise. |
bool Delete() | Deletes the underlying storage. No events are fired because of the deletion of storage elements. If the operation succeeds, this returns true. |
bool CopyTo(e4_Graph otherStorage, bool forceCommit) const | Copies the e4Graph contents of this storage to otherStorage.
The previous contents of otherStorage is deleted, and no events
are fired because of the deletion. If forceCommit is true, then
otherStorage
is committed after the copy is done.
After this operation, the e4Graph contents of this storage and otherStorage are identical. Changes made to one storage after the copy are not reflected in the other storage. Callbacks registered for otherStorage stay in effect and may be called when events fire after the copy if changes are made to otherStorage. |
bool IsDirty() const | Returns true when the storage has been modified and not yet committed. |
void MarkDirty() const | Marks the storage as dirty, i.e. it has been modified and not yet committed. |
int MarkerCount() const | Returns how many markers are represented within this storage. |
bool GetMarker(const char *name, e4_Marker &t) const | If the operation succeeds, an e4_Marker instance is returned in t and true is returned. Otherwise, t is not modified and false is returned. If the named marker does not yet exist within this storage, it is created at this time. |
bool MarkerExists(const char *name) const | Returns true if a marker with the given name exists in this storage. The marker is not created. |
bool GetMarkerdNode(const char *name, e4_Node &n) const | Retrieves the node marked by the marker whose name is given, creating the node and the marker if needed. |
bool GetMarkerFromID(e4_MarkerUiqueID id, e4_Marker &m) const | Given a valid unique ID obtained from a marker using GetUniqueID, retrieves the corresponding marker. |
bool GetNodeFromID(e4_NodeUniqueID id, e4_Node &n) const | Given a valid unique ID obtained from a node using GetUniqueID, retrieves the corresponding node. |
bool GetVertexFromID(e4_VertexUniqueID id, e4_Vertex &v) const | Given a valid unique ID obtained from a vertex using GetUniqueID, retrieves the corresponding vertex. |
bool IsValid() const | Returns true if the storage is valid, false otherwise. A storage is valid if it designates an open persistent storage. |
bool IsDirty() const | Returns true if the storage contains modifications to trees, nodes or fields that have not yet been committed to persistent storage. |
const char *GetName() const | Returns the name of the storage. Returns NULL if the storage is invalid. Note that the memory occupied by the returned string is owned by e4Graph and may be reused by the next e4Graph method invocation. |
const char *GetDriver() const | Returns the StorageKind used to open this storage. Returns NULL if the storage is invalid. Note that the memory occupied by the returned string is owned by e4Graph and may be reused by the next e4Graph method invocation. |
bool IsEmpty() const | Returns true if the storage is empty, that is, it contains no markers and other elements. Otherwise it returns false. |
bool MakeEmpty() const | Deletes any markers and elements reachable from those markers, from this storage. If the operation succeeds, or the storage is already empty, returns true. Upon failure this operation returns false. |
bool GetStatistic(e4_Space sp, e4_SpaceStat st, int &v) const | Retrieves statistics about the use of various allocation spaces within a storage. If the operation succeeds, returns true and v contains the statistic measure selected by sp and st. |
bool DeclareMarkerAddCallback(e4_MarkerAddCallbackFunction fn, void *clientData) | Registers the supplied function fn to be called with the supplied clientData when a marker addition event is fired by e4Graph. Returns true if the registration succeeds. |
bool DeleteMarkerAddCallback(e4_MarkerAddCallbackFunction fn, void *clientData) | Deletes the registration of a previously registered function fn that was being called with the supplied clientData when a marker addition event is fired by e4Graph. Returns true if the fn and clientData were previously registered for this event and the registration is removed successfully. |
bool DeclareMarkerDelCallback(e4_MarkerDelCallbackFunction fn, void *clientData) | Registers the supplied function fn to be called with the given clientData when a marker deletion event is fired by e4Graph. Returns true if the registration succeeds. |
bool DeleteMarkerDelCallback(e4_MarkerDelCallbackFunction fn, void *clientData) | Deletes the registration of a previously registered function fn that was being called with the supplied clientData when a marker deletion event is fired by e4Graph. Returns true if the fn and clientData were previously registered for this event and the registration is removed successfully. |
bool DeclareNodeAddCallback(e4_NodeAddCallbackFunction fn, void *clientData) | Registers the supplied function fn to be called with the given clientData when a node addition event is fired by e4Graph. Returns true if the registration succeeds. |
bool DeleteNodeAddCallback(e4_NodeAddCallbackFunction fn, void *clientData) | Deletes the registration of a previously registered function fn that was being called with the supplied clientData when a node addition event is fired by e4Graph. Returns true if the fn and clientData were previously registered for this event and the registration is removed successfully. |
bool DeclareNodeDelCallback(e4_NodeDelCallbackFunction fn, void *clientData) | Registers the supplied function fn to be called with the given clientData when a node deletion event is fired by e4Graph. Returns true if the registration succeeds. |
bool DeleteNodeDelCallback(e4_NodeDelCallbackFunction fn, void *clientData) | Deletes the registration of a previously registered function fn that was being called with the supplied clientData when a node deletion event is fired by e4Graph. Returns true if the fn and clientData were previously registered for this event and the registration is removed successfully. |
bool DeclareVertexAddCallback(e4_VertexAddCallbackFunction fn, void *clientData) | Registers the supplied function fn to be called with the given clientData when a vertex addition event is fired by e4Graph. Returns true if the registration succeeds. |
bool DeleteVertexAddCallback(e4_VertexAddCallbackFunction fn, void *clientData) | Deletes the registration of a previously registered function fn that was being called with the supplied clientData when a vertex addition event is fired by e4Graph. Returns true if the fn and clientData were previously registered for this event and the registration is removed successfully. |
bool DeclareVertexDelCallback(e4_VertexDelCallbackFunction fn, void *clientData) | Registers the supplied function fn to be called with the given clientData when a vertex deletion event is fired by e4Graph. Returns true if the registration succeeds. |
bool DeleteVertexDelCallback(e4_VertexDelCallbackFunction fn, void *clientData) | Deletes the registration of a previously registered function fn that was being called with the supplied clientData when a vertex deletion event is fired by e4Graph. Returns true if the fn and clientData were previously registered for this event and the registration is removed successfully. |
e4_RefKind Kind() const | Returns E4_RKSTORAGE, the e4_RefKind identifier for the e4_Storage type. |