Object oriented data store integration environment for integration of object oriented databases and non-object oriented data facilities5542078Abstract A method and apparatus for accessing and effectively integrating non-object oriented data stores with object applications. An integrating environment is implemented wherein an application using a distributed object database and object database management system (ODBMS) is provided with an interface to external data stores in a manner so as to effect location transparency. The application, accessing data via the ODBMS, can manipulate data in foreign data stores which include external data that is mapped and converted into objects for use by object applications. A storage management application program interface ("SM API"), effects a functional interface for handling objects, referencing objects, implementing iteration and indexing of objects, and implementing object transaction and cache handling. The SM API is part of a modular architecture that includes an external storage manager which implements classes that provide the foundation for engaging external data stores, and which maps and converts external data into objects that can be manipulated by an application using the ODBMS. Claims What is claimed is: Description FIELD OF THE INVENTION
______________________________________
virtual void* allocateObj (long sz, OC.sub.-- Type* the Type,
OC.sub.-- Object* where, OC.sub.-- Clustering howNear);
______________________________________
Allocates and initializes a new object. Specify the object's size in bytes with sz and its OC.sub.-- Type with theType. Depending upon the OC.sub.-- StorageManager's implementation, allocateObj() may use the where and howNear arguments to set the clustering object and proximity, respectively. Clustering and the interpretation of clustering levels (OC.sub.-- defaultClustering, OC.sub.-- sameArea, and OC.sub.-- sameSegment) is OC.sub.-- StorageManager implementation-dependent, so allocateObj() may use the clustering arguments as it needs to, or not at all. This function raises exception OC.sub.-- SystemLimitation when an OC.sub.-- StorageManager resource is depleted. An example of such a resource is an in-memory reference or object space for a storage manager with a fixed-size cache. This function is called by OC.sub.-- Object::operator new(). virtual void deallocateObj(void* ent); Deallocates the memory that was used by *ent, which was an OC.sub.-- Object-based instance. This function is called by OC.sub.-- Object::operator delete(). Implementation of deallocateObj() should be complementary to the implementation of allocateObj(). For example, if allocateObj() allocates memory from a particular pool, deallocateObj() should return it to the same pool. Object status query virtual OC.sub.-- Boolean isObjModified(OC.sub.-- Object* obj); Returns OC.sub.-- true if*obj is marked modified;returns OC.sub.-- false otherwise. See the description of markObjModified() below. If the object's self ref is not recognized as valid, isObjModified() raises an OC.sub.-- NoSuchRef exception. This pure virtual function is called by OC.sub.-- Object::isModified(), and by OC.sub.-- Entity::isEntityModified() if the OC.sub.-- Entity is an OC.sub.-- Object. Object manipulation virtual void putObj(OC.sub.-- Object* obj); Puts the current, in-memory state of obj to the database. If the object's self ref is not recognized as valid, putObj() raises an OC.sub.-- NoSuchRef exception. If the object has been persistently deleted, putObj() raises an OC.sub.-- ObjectWasDeleted exception. If acquiring a lock on the referent causes the application's current transaction to wait for another transaction to commit, putObj() raises an OC.sub.-- WaitException exception. If acquiring a lock on the referent causes the transaction to be aborted, pujObj() raises an OC.sub.-- TransactionWas-Aborted exception. If putObj() is called outside any transaction, it raises an OC.sub.-- NoTransaction exception. Note that during the transaction in which they are made, all changes to the persistent state of an object with putObj() must be made visible only within the context of that transaction. If the transaction is successfully checkpointed or committed, you should then make the changes visible to subsequent transactions. If the transaction is aborted, you should discard all changes to the persistent states of objects made during the transaction. virtual void deleteObj(OC.sub.-- Object* obj); Deletes *obj from the database. If *obj's self reference value is not recognized as valid, deleteObj() raises an OC.sub.-- NoSuchRef exception. If acquiring a lock on the referent causes the application's current transaction to wait for another transaction to commit, deleteObj() raises an OC.sub.-- Wait-Exception exception. If acquiring a lock on the referent causes the transaction to be aborted, deleteObj() raises an OC.sub.-- TransactionWasAborted exception. This function is called by OC.sub.-- Object::deleteObject(). virtual void destroyObj(OC.sub.-- Object* obj); Prepares *obj for deallocation from memory. If aborted is set to OC.sub.-- true, destroy() has been called as a result of an exception handler abort. This method should not be called directly except from this class's destructor or from the destroy() function of derived classes. This function is called by OC.sub.-- Object::destroy(). virtual void markObjModified(OC.sub.-- Object* obj); Marks *obj as having been modified. This pure virtual function is called by OC.sub.-- Object::markModified(). See the Reference Manual, Volume 1: Class Library for suggestions on using the OC.sub.-- Object member functions markModified(), unmark-Modified(), and isModified() in an optional modification-flagging scheme. virtual void unmarkObjModified(OC.sub.-- Object* obj); Unsets the modified flag set on *obj by markObjModified(), described above. This function is called by OC.sub.-- Object::unmarkModified(). Helper functions These implemented object handling functions are available to be called by functions implemented by the storage management developer. Object activation
______________________________________
OC.sub.-- Object* defaultActiveObj (OC.sub.-- Object* obj,
OC.sub.-- Type* theType, unsigned long objSelfRef);
______________________________________
Performs the final processing required to activate *obj, which is a memory location for an object that is initialized but inactive. The argument theType must point to the OC.sub.-- Type for the object. The objSelfRef argument must be the self ref for the object to be activated. The processing performed by defaultActivateObj() includes the location and invocation of the activation constructor wrapper function, vtbl simulation for instances of OC.sub.-- Types that do not have an available vtbl, and initialization of storage manager and self ref values for *obj. This function is usually called toward the end of the OC.sub.-- StorageManager::getReferent() function Hash key retrieval virtual unsigned long getObjHashKey(OC.sub.-- Object* obj); Finds, calculates, or generates the hash key value for *obj. This value is used for hashing the object when it serves as a key to an aggregate, such as an unordered OC.sub.-- Dictionary, or as a member of an OC.sub.-- Set. This function is called by OC.sub.-- Object::getEntityHash-Key(). If you refine getObjHashKey(), you should adhere to the following basic guidelines: getObjHashKey() should always return the same value for a particular object; this requirement pertains to the lifetime of the object. For the best performance, you should minimize the probability that multiple objects have hash keys with the same values for their low-order bits. To that end, the hash values associated with n objects to be hashed by an OC.sub.-- Aggregate should yield an even distribution of results from the formula modulo 2 m where m is the smallest positive integer such that 2 m+3>n where n is the hash key value. Entity initialization
______________________________________
void initializeEntityPiece (OC.sub.-- Entity* ent,
unsigned long refVal);
______________________________________
Sets the ref val for *ent to the refVal argument, and sets *ent's storage manager to this one. You may wish to use this function in implementations of allocateObj() and getReferent. However, you may find initializeInstance() and defaultActivateObj() more useful, as they subsume the functionality of initializeEntityPiece().
______________________________________
void initializeInstance (unsigned long refValue,
char* startOfInstance, OC.sub.-- Type* entType);
______________________________________
Updates all self reference value and storage manager values for all inherited and embedded objects in an object upon its creation or activation. You may wish to use this function in implementations of OC.sub.-- StorageManager::allocateObj() and OC.sub.-- StorageManager::getReferent(). However, you may find defaultActivateObj() more useful, as it subsumes the functionality of initializeInstance(). OC.sub.-- Primitive memory allocation
______________________________________
virtual void* allocatePrim (long sz, OC.sub.-- Type* theType,
OC.sub.-- Object* where, OC.sub.-- Clustering howNear);
______________________________________
Returns a pointer to the memory it allocates for an OC.sub.-- Primitive object. The sz argument is the number of bytes to allocate, and theType is the type of the object. The where and howNear arguments specify the clustering object and proximity, respectively. This function is called by OC.sub.-- Primitive::operator new(). virtual void deallocatePrim(void* prim); Deallocates the memory pointed to by prim, which is an OC.sub.-- Primitive or portion of an OC.sub.-- Primitive object. This function is called by OC.sub.-- Primitive::operator delete(). If you refine deallocatePrim(), make sure that its implementation is compatible with that of allocatePrim(). IMPLEMENTING REFERENCE HANDLING Reference handling support Overview Reference handling is a one of the most important storage management feature areas. This chapter describes basic reference handling, in which the OC.sub.-- Reference and its referent belong to the same storage manager. Chapter 5, "Implementing inter-SM reference translation and export," addresses inter-storage manager reference handling, in which the referent's storage manager is different from the OC.sub.-- Reference's. An in-memory reference can refer either to an in-memory or a persistent object. A persistent reference can refer only to a persistent object. Reference values Reference values and self reference values Every instance of an OC.sub.-- Entity-derived class has a property that is referred to as its self-reference, or self ref. This property identifies the entity to itself, in its in-memory state, for the duration off a client cache. Every OC.sub.-- Reference instance has a similar property that is referred to as its reference value, or ref val. That property identifies the referent to the OC.sub.-- Reference for the duration of the client cache. Every OC.sub.-- StorageManager instance initializes and maintains a set of self reference values that represents all the entities managed by that storage manager. Every OC.sub.-- StorageManager instance also initializes and maintains a set of reference values that represents all the OC.sub.-- References that reference all the entities managed by the storage manager. Each OC.sub.-- StorageManager instance is responsible for the method of translating its reference values to pointers to their corresponding entities, and for maintaining this reference value-to-referent mapping for the duration of the client cache. Each storage manager is also responsible for mapping its reference values to the status of each object it manages. The status referred to encompasses the results of such OC.sub.-- StorageManager query functions as is Obj-Modified() and isReferentInDB(). The reference space Both the reference value and the self reference value properties are 32-bit(unsigned long) structures, of which eight bits are reserved for ONTOS DB use and 24 bits are available for use by the reference's storage manager. The storage manager's portion of the reference value or self reference value is called its reference space and can contain 2.sup.24 (about 16 million) different values to map to entities. FIG. 4-1 illustrates the reference value or self reference value structure.
______________________________________
8 bits; reserved
24-bit reference space; value set by storage
for ONTOS manager
DB
FIG. 4-1 32 bit reference value (in OC.sub.-- Reference) or
self reference value (in OC.sub.-- Entity)
______________________________________
For developer-derived OC.sub.-- StorageManager subclasses, this structure also applies to the persistent state of the object. In the future, OC.sub.-- StorageManager may represent persistent reference values in a different way. Control of reference values For intra-storage manager references, reference values for persistent OC.sub.-- References are controlled by the OC.sub.-- Reference's storage manager (which is also the referent's storage manager). However, reference values for in-memory OC.sub.-- References are always the same as the referent's self reference value. Control of reference values for inter-storage manager references differs somewhat from this scheme. Chapter 5, "Implementing inter-SM reference translation and export," compares intra-SM references with inter-storage manager references. Reference handling functions Class OC.sub.-- Reference has a number of functions that are implemented to call corresponding functions on the OC.sub.-- StorageManager subclass instance that manages the OC.sub.-- Reference. OC.sub.-- StorageManager's basic reference handling functions include functions to query the status of an OC.sub.-- Reference's referent and manipulation functions to change the status of an OC.sub.-- Reference or its referent. Unimplemented functions All-reference handling member functions are defined as pure virtual on OC.sub.-- StorageManager, so that the storage management developer must implement them for any subclass, according to their specifications. Referent status query virtual OC.sub.-- Boolean isReferentActive(OC.sub.-- Reference*ref); Returns OC.sub.-- true if *ref's referent is active; returns OC.sub.-- false otherwise. If the reference's value is not recognized as valid, isReferentActive() raises an OC.sub.-- NoSuchRef exception. This function is called by OC.sub.-- Reference::isActive() and OC.sub.-- Reference::getActiveReferent(). virtual OC.sub.-- Boolean isReferentDeleted(OC.sub.-- Reference* ref); Returns OC.sub.-- true if ref's referent has been persistently deleted; returns OC.sub.-- false otherwise. If the reference's value is not recognized as valid, isReferentDeleted() raises an OC.sub.-- NoSuchRef exception. This function is called by OC.sub.-- Reference::isReferentDeleted() and OC.sub.-- Object::isObjectDeleted(), and by OC.sub.-- Entity::isEntityDeleted() if the instance is an OC.sub.-- Object. virtual OC.sub.-- Boolean isReferentInDB(OC.sub.-- Reference* ref); Returns OC.sub.-- true if *ref's referent has ever been put to the database (and has not been persistently deleted). The function returns OC.sub.-- false otherwise. If the reference's value is not recognized as valid, isReferentInDB() raises an OC.sub.-- NoSuchRef exception. This function is called by OC.sub.-- Reference::isInDB() and OC.sub.-- Object::isObjectInDB(), and by OC.sub.-- Entity::isEntity-InDB() if the instance is an OC.sub.-- Object. virtual OC.sub.-- Boolean isReferentNew(OC.sub.-- Reference* ref); Returns OC.sub.-- true if *ref's referent was created in the current cache (and has not been persistently deleted). The function returns OC.sub.-- false otherwise. If the reference's value is not recognized as valid, isReferentNew() raises an OC.sub.-- NoSuchRef exception. This function is called by OC.sub.-- Reference::isNew() and OC.sub.-- Object::isObjectNew(), and by OC.sub.-- Entity::isEntityNew() if the instance is an OC.sub.-- Object. Referent retrieval functions virtual OC.sub.-- Entity* getReferent(OC.sub.-- Reference* ref, OC.sub.-- LockType lock); Returns a pointer to *ref's referent, whether or not the referent is currently active. If necessary, get-Referent() activates the referent, locking it with lock type lock. The following table shows the exceptions that may be raised by getReferent( ) and the conditions that cause them to be raised.
______________________________________
Exception raised
Condition
______________________________________
OC.sub.-- NoSuchRef
Reference value is not recognized as
valid.
OC.sub.-- ObjectWasDeleted
Referent has been persistently
deleted.
OC.sub.-- WaitException
Acquiring a lock on the referent
causes the application's current
transaction to wait for another
transaction to commit.
OC.sub.-- TransactionWasAborted
Acquiring a lock on the referent
causes the transaction to be aborted
______________________________________
This function is called by OC.sub.-- Reference::getReferent(). virtual OC.sub.-- Entity* getReferentIfActive(OC.sub.-- Reference* ref); Returns a pointer to *ref's referent if *ref has a referent that is active;returns 0 otherwise. If the reference's value is not recognized as valid, get-ReferentIfActive() raises an OC.sub.-- NoSuchRef exception. This function is called by the following OC.sub.-- Reference member functions:isReferentModified(), getReferent-IfActive(), and getActiveReferent(). Lock function
______________________________________
virtual OC.sub.-- LockType getReferentLockType (
OC.sub.-- Reference* ref);
______________________________________
Returns *ref's lock type. If the reference's value is not recognized as valid, getReferentLockType() raises an OC.sub.-- NoSuchRef exception. This pure virtual function is called by OC.sub.-- Reference::getReferentLockType() and OC.sub.-- Object::getLock-Type(), and by OC.sub.-- Entity::getEntityLockType() if the instance is an OC.sub.-- Object.
______________________________________
virtual void lockReferent (OC.sub.-- Reference* ref,
OC.sub.-- LockType lock);
______________________________________
Acquires or upgrades a lock of OC.sub.-- LockType lock on the referent of *ref. If the reference's value is not recognized as valid, lockReferent() raises an OC.sub.-- NoSuch-Ref exception. This function is called by OC.sub.-- Reference::lockReferent and OC.sub.-- Object::lockObject(), and by OC.sub.-- Entity::lock-Entity() if the instance is an OC.sub.-- Object. Reference manipulation function
______________________________________
virtual void discardReference (OC.sub.-- Reference* ref,
OC.sub.-- Boolean persistently);
______________________________________
Discards the reference value of *ref, setting it to 0. Passing a persistently argument of OC.sub.-- true causes discardReference() to free all resources associated with all persistent references to the referent. All resources associated with in-memory references to the referent are freed, regardless of the persistently argument. If the reference's value is not recognized as valid, discardReference() raises an OC.sub.-- NoSuchRef exception. The discardReference() function must be called only for reference values that are no longer used by any OC.sub.-- Reference. If the reference is outbound (that is, the referent's storage manager is different from the OC.sub.-- -Reference's), discardReference() discards the reference value used by the referent's storage manager before discarding that used by the reference's storage manager. If an application does not call this function after a referent is deallocated or persistently deleted, the storage manager continues to associate the reference value with the referent. This default behavior guards against dangling and ambiguous references by preventing reuse of a reference value for any other object. One disadvantage of this behavior is the overhead it requires to maintain support for reference values that are no longer in use. Another is the limit it imposes of 2.sup.24 (about 16 million) referents per cache duration per storage manager. By informing the storage manager that the current reference value is no longer in use, a call to discardReference() eliminates these drawbacks and enables reuse of the 24-bit reference space portion of the reference value. Caution: Be careful not to call discardReference() with a *ref argument that has the same value as another OC.sub.-- -Reference that might be used later by the application. Helper functions These implemented functions are available to be called by functions implemented by the storage management developer. self reference value retrieval static unsigned long getEntSelfRefValue(OC.sub.-- Entity* ent); Returns the self reference value of *ent. Since self reference values are useful as keys to data structures defined and maintained by storage managers, storage manager developers can use this function in OC.sub.-- Object- and OC.sub.-- Reference-related query and update functions. Referent retrieval
______________________________________
virtual OC.sub.-- Argument getReferentAsArgument (
OC.sub.-- Reference* ref);
______________________________________
Returns *ref's referent as an OC.sub.-- Argument. If the referent is stored as type char* or int, the returned OC.sub.-- Argument is initialized directly with that value. The purpose of this function is to convert reference values to OC.sub.-- Arguments without the overhead of using OC.sub.-- Primitive-derived classes. The following table shows the exceptions that may be raised by getReferentAsArgument() and the conditions that cause them to be raised.
______________________________________
Exception raised
Condition
______________________________________
OC.sub.-- NoSuchRef
Reference's value is not
recognized as valid.
OC.sub.-- ObjectWasDeleted
Referent has been persistently
deleted.
OC.sub.-- WaitException
Acquiring a lock on the referent
causes the application's current
transaction to wait for another
transaction to commit.
OC.sub.-- TransactionWasAborted
Acquiring a lock on the referent
causes the transaction to be
aborted.
______________________________________
IMPLEMENTING INTER-SM REFERENCE TRANSLATION AND EXPORT Inter-SM reference translation and export support Overview Every storage manager must be able to translate, into its own reference space, the persistent and non-persistent OC.sub.-- References to objects under the control of other storage managers. A storage manager must also handle export of OC.sub.-- References to its own objects and to objects under the control of other storage managers. The inter-storage manager reference translation and export functions, defined on OC.sub.-- StorageManager, enable objects controlled by different storage managers to reference each other. Without this reference translation and export interface, you would be able to use only one storage manager instance per physical database. REFERENCE VALUES FOR INTER-SM REFERENCES Chapter 4, "Implementing reference handling," describes the 32-bit reference value structure. This structure is also used for inter-storage manager reference values. However, the reference values for inter-storage manager references are always controlled by the OC.sub.-- Reference's storage manager, whether the reference is in-memory or persistent. Recall that for intra-storage manager references, reference values for persistent OC-References are also controlled by the OC.sub.-- Reference's storage manager (which is also the referent's storage manager), but reference values for in-memory OC.sub.-- References are always the same as the referent's self reference value. Resolution of inter-SM references Resolution of inter-storage manager references is based on a two-tiered architecture, which facilitates the resolution of references that have been previously translated by one or more other storage managers. With the two-tiered architecture, a storage manager given a reference also receives a record of the referent's original reference value and the identity of its storage manager, no matter how many intervening translations into other storage managers' reference spaces have occurred. Functions for inter-SM reference translation and export The OC.sub.-- StorageManager's inter-storage manager translation interface includes functions that translate OC.sub.-- References referring to objects handled by other storage manager instances and that export OC.sub.-- References to other storage manager instances. Unimplemented functions These inter-storage manager reference translation/export functions are pure virtual, so must be implemented by the storage management developer:
______________________________________
virtual unsigned long translateRefValue (
OC.sub.-- Entity* referent);
______________________________________
Returns an in-memory reference value for *referent, which belongs to a storage manager other than this one. After the call to translateRefValue(), this OC.sub.-- Storage-Manager recognizes the translateRefValue() return as an outbound reference, that is, as a reference to *referent as an OC.sub.-- Entity under the control of another storage manager. Note that the reference value should encode the storage manager originating the reference, as well as the self reference value of *referent. Consequently, the translateRefValue() implementation is independent of the storage managers in existence at a particular time. This function is called by OC.sub.-- Reference::reset(), OC.sub.-- -Reference::init(), and the OC.sub.-- Reference constructor, when the referent's storage manager is different from the OC.sub.-- Reference's.
______________________________________
virtual unsigned long translateRefValue (
unsigned long oldRefValue,
OC.sub.-- StorageManager* oldContext);
______________________________________
***Returns a reference value that is either an outbound reference, or a reference originating from this storage manager that was translated by another storage manager and then passed back to this storage manager. The oldRefValue argument is the reference value to translate. The oldContext argument points to the storage manager for oldRefValue (oldContext is never this). If oldRefValue is not recognized as valid in the context of oldContext, translateRefValue() raises an OC.sub.-- NoSuch-Ref exception. Note that the reference value returned must indicate the storage manager originating the reference, as well as oldRefValue. Consequently, the translateRefValue() implementation is independent of other storage managers' implementations that exist at a particular time. This function is called by OC.sub.-- Reference::reset(), OC.sub.-- -Reference::init(), and the OC.sub.-- Reference constructor, when *oldContext is different from the OC.sub.-- Reference's storage manager.
______________________________________
virtual OC.sub.-- Boolean compareReferences (OC.sub.-- Reference* r1,
oc.sub.-- Reference* r2);
______________________________________
Returns OC.sub.-- true if r1 and r2 have referents that are the same or equal; returns OC.sub.-- false otherwise. If either reference's value is invalid, compareReferences() raises an OC.sub.-- NoSuchRef exception. This function is called by OC.sub.-- Reference::compare(). Helper functions These implemented inter-storage manager reference translation/export functions perform complex processing that is common to most OC.sub.-- StorageManager-based classes. They are available for use in implementing the functions described above.
______________________________________
virtual OC.sub.-- Boolean simplifyRefValue (
unsigned long& simpleRefValue,
OC.sub.-- StorageManager*& simpleSM);
______________________________________
Translates a reference value into the form associated with the storage manager that originated it. The reference is now managed by this storage manager but may have previously been managed by another storage manager. Pass the reference value as the simpleRefValue argue-ment, and pass a pointer to this storage manager (assigned to this) as simpleSM. The function returns OC.sub.13 true if the reference value originated with another storage manager. In that case, it returns a pointer to the originating storage manager in simpleSM, and the simplified reference value in simpleRefValue (which may coincidentally be the same value that was passed in). Note: The following three functions are not yet available for use. Their descriptions are included here for completeness.
______________________________________
virtual void makePersistentReference (
unsigned long refValue, OC.sub.-- StorageManager* referencer,
OC.sub.-- PersistentReference& toBeSet);
______________________________________
This function is not available with ONTOS DB Release 3.1. It is specified to translate the in-memory reference value refValue into a persistent reference toBeSet, with storage manager *referencer.
______________________________________
virtual OC.sub.-- Boolean replacePersistentReference (
const OC.sub.-- PersistentReference& oldValue,
const OC.sub.-- PersistentReference& newValue,
OC.sub.-- StorageManager* owner);
______________________________________
This function is not available with ONTOS DB Release 3.1. It is specified to return. OC.sub.-- true if replacePersistentReference() has unconditionally replaced oldValue with newValue. The owner argument points to the storage manager for both oldValue and newValue.
______________________________________
virtual unsigned long resolvePersistentReference (
const OC.sub.-- PersistentReference& toBeResolved,
OC.sub.-- StorageManager* referencer);
______________________________________
This function is not available with ONTOS DB Release 3.1. It is specified to return the reference value of an in-memory reference, managed by storage manager *referencer, for the same referent as the persistent reference toBeResolved. IMPLEMENTING ITERATION AND INDEXING Iteration and indexing support Overview Every OC.sub.-- StorageManager subclass provides support for processing objects as instances of OC.sub.-- Types with extensions and as instances of OC.sub.-- Types with indexed properties. For more information about extensions and indexed properties, see the Developer's Guide and the entries for the OC.sub.-- Property and OC.sub.-- Type classes in the Reference Manual, Volume 1:Class Library. The storage management developer can implement OC.sub.-- -StorageManager functions to achieve greater efficiency in iteration and indexing than is offered by the OC.sub.-- -StandardSM and OC.sub.-- Group classes. This section describes two supporting features, subextensions and subindexes, and how to use them. The section also discusses providing storage management support for operations involving common and specialized subextensions and indexes. Completeness and uniqueness Completeness of iteration over extensions and indexes Objects with storage managers that are not in the currently open logical database do not participate in iterations over their extensions and indexes. Therefore, in order to extend any processing to all instances of a type, you must store all those instances, as well as all their storage managers, in a single logical data-base. Qualified global uniqueness for indexed properties Because objects with storage managers not in the currently open logical database do not participate in iteration over their indexes, uniqueness of values for indexed properties is guaranteed only for objects belonging to storage managers that are in the currently open logical database. This consequence is called qualified global uniqueness. When an area containing a storage manager to the current database, there is a possibility that one or more objects in the added area have values that duplicate those of objects already in the database. This dupli-cation violates the uniqueness constraint for those properties defined as unique. Because the duplication does not arise often, ONTOS DB takes an optimistic approach and leaves detection and correction of the condition to the application. If such duplications could be detrimental to an application, the application should include code to detect and correct the problem wherever it might occur. The following example is suggested as a basis for such code:
______________________________________
void checkIndexesOnType (OC.sub.-- Type* theType)
OC.sub.-- Object* suspectInstance;
OC.sub.-- Iterator* theIter = theType.fwdarw.getIterator
(OC.sub.-- read-Lock);
while (suspectInstance = (OC.sub.-- Object*)theIter.fwdarw.yield-
EntityValue ( ) )
{
OC.sub.-- StorageManager::checkAllIndexes (suspectInstance);
}
}
______________________________________
The subextension feature Common and specialized subextensions ONTOS DB transparently partitions every extension into subextensions, each comprising objects belonging to a single storage manager. The subextension feature enables storage management developers to implement specialized subextension treatments for particular storage managers. Many storage managers are well served by the default, common subextension implementation provided by ONTOS DB. However, for a particular custom storage manager, a specialized subextension might give more accurate results and better performance. Note: An instance can be a member of only one subexten-sion (common or specialized) on its direct type, if the direct type has an extension. The instance can also be a member of only one subextension on each of its direct type's supertypes that have extensions. When to use a specialized subextension A custom iterator can be advantageous for a storage manager that accesses many objects as a single opera-tion. Consider, for example, a storage manager that supports specialized functions that identify a large number of objects, likely to be requested within a short period of time, and access them all at once. Iteration of that storage manager's subextension would be faster than the default iteration, which uses references to individual objects in order to access them one at a time. Implementing specialized subextensions To implement a specialized subextension, you must derive an iterator class from class OC.sub.-- Iterator. Implement your class's member functions to most effectively iterate over the objects belonging to the storage manager. Also, implement the getIterator() functions (three signatures) for your storage manager class, so each returns a pointer to an instance of the specialized iterator class. The result of the implementation is that when an application uses the iterator returned by OC.sub.-- Type::get-Iterator() to iterate over the type's extension, ONTOS DB calls getIterator() on the storage manager for each subextension. ONTOS DB uses the returned iterator to yield the objects belonging to that storage manager. Temporary subextension for new objects ONTOS DB also defines a special, temporary subextension, in which it automatically includes all newly created, unsaved objects, regardless of the storage managers they belong. An iteration over an extension includes iteration over the temporary subextension. Because the temporary subextension includes all new objects, you should implement all specialized sub-extensions to exclude new objects. The subindex feature Description Property indexes are divided into subindexes, each managed by a different storage manager instance. Since different storage managers and their objects can be stored in different database areas, subindexing supports restriction of access through iteration, to those objects that are stored in areas in the current logical database. The subindex feature enables storage management devel-opers to implement specialized subindex treatments for particular storage managers. Many storage managers are well served by the default, common subindex implemen-tation provided by ONTOS DB. However, for a particular custom storage manager, a specialized subindex might give more accurate results and better performance. Note: An instance of an OC.sub.-- Type should be a member of only one subindex (common or specialized) per index for each of the type's indexed properties. Implementing specialized subindexes To implement a specialized subindex, you must derive an iterator class from class OC.sub.-- Iterator. Implement your class's member functions to most effectively iterate over the objects belonging to the storage manager for the subindex. Also, implement the getIterator() functions (three signatures) for your storage manager class, so each returns a pointer to an instance of the specialized iterator class. The result of the implementation is that when an application uses the iterator returned by OC.sub.-- Type::get-Iterator() to iterate over the type's subindex, ONTOS DB calls getIterator() on the storage manager for each subindex. ONTOS DB uses the returned iterator to yield the objects belonging to that storage manager. Operations with Common Subextensions and Common Subindexes Storage managers that do not provide specialized subextensions for all subextensions or all subindexes must provide support for several operations that deal, respectively, with common subextensions or common subindexes. OC.sub.-- StorageManager defines helper functions, described in the following subsection, for these operations. A storage manager is responsible for adding an instance, as required, to the common subextensions and common subindexes when the instance is created, and for updating the instance's indexes when it is put to the database. The storage manager is also responsible for removing the instance from extensions and indexes when the instance is deleted. To support these operations, OC.sub.-- StorageManager has the helper functions described under "Common subextension membership" on page 6-8 and "Common subindex membership" on page 6-9. There are pairs of complementary helper functions for adding instances to, and removing them from, common subextensions and common indexes. For extensions, one function in the pair applies only to extensions on the given type, and the other applies to the direct type of the given object and to the type's supertypes. Unless the storage manager is using specialized subextensions on one or more types in the object's type hierarchy, you should use the second variant in each of these pairs of functions. An example of a pair of complementary extension-related helper functions is addToCommonExtension() and addToAllCommonExtensions(). The addToCommonExtension() function adds the instance only to the extension on the given type. The addToAllCommonExtensions() function adds the instance to its direct type's common subextension and to the common subextensions for all the type's super-types. For indexes, one variation on the add or remove function affects only the given indexed property (for example, addToCommonIndex()) and the other affects all indexed properties (for example, addToAllCommonIndexes()). Iteration over Subextensions and Subindexes OC.sub.-- StorageManager supports operations that deal with participation in iteration of subextensions and subindexes, through a number of helper functions described in the subsection. For efficiency, OC.sub.-- IndexIterator functions call the OC.sub.-- StorageManager::getIterator() function on only those storage managers that are enabled as participants in the iteration of the subextension or subindex. Most storage managers are enabled as participants in a specialized iteration, as required, when they are created or activated; they should also be disabled as participants when they are deleted. The unimplemented functions described under "Sub-extension iteration participation" on page 6-9 and "Subindex iteration participation" on page 6-9 must be implemented to enable and disable participation in iteration of subextensions and subindexes, respectively. Those subsections also describe query functions for ONTOS DB code to determine whether the storage manager is a participant in the iteration. Functions for Iteration and Indexing Unimplemented Functions The iteration and indexing functions are pure virtual, so must be implemented by the storage management developer. Iterator retrieval virtual OC.sub.-- Iterator* getIterator(OC.sub.-- Type* theType, OC.sub.-- LockType lock); Returns a pointer to an OC.sub.-- Iterator for this storage manager's subextension of *theType's extension. Use the lock argument to specify the lock type for instances that are activated by iteration. virtual OC.sub.-- Iterator* getIterator(OC.sub.-- Type* theType, OC.sub.-- -Property* prop* OC.sub.-- Argument value, OC.sub.-- LockType lock); virtual OC.sub.-- Iterator* getIterator(OC.sub.-- Type* theType, OC.sub.-- -Property* theProp, OC.sub.-- Argument start, OC.sub.-- Argument end, OC.sub.-- -Boolean yieldInOrder, OC.sub.-- LockType lock); Returns a pointer to an OC.sub.-- Iterator for this storage manager's subindex of property *theProp on *theType. For the first overload, the returned iterator yields instances with property values that are equal to the value of value. For the second overload, the iterator yields instances with property values in the range specified by start and end. For the last of the three getIterator() overloads, a yieldInOrder argument of OC.sub.-- true specifies that the returned iterator yield instances in ascending values for *prop;setting yieldInOrder to OC.sub.-- false means that the yield order is undetermined. The lock argument specifies the lock type for instances activated by iteration. The three getIterator() functions are called by the OC.sub.-- InstanceIterator member functions. They are called only on storage managers that have been enabled as iteration or index participants for the specified OC.sub.-- Type or OC.sub.-- Property, respectively. This scheme is based on the assumption that a storage manager that is not enabled as a participant either has no instances of the specified OC.sub.-- Type or has added all the instances to the common subextension and indexes for the OC.sub.-- Type. Instance count query virtual unsigned long getInstanceCount(OC.sub.-- Type* theType); Returns an approximate number of instances of *theType that belong to this storage manager, if it uses a specialized subextension. If neither *theType nor any of its supertypes has an extension, or if this storage manager uses the common subextension, getInstanceCount() returns 0. This function is called by OC.sub.-- Type::numInstances(), only on storage managers enabled as iteration participants for *theType. Helper functions These implemented functions for iteration and indexing perform complex procesing that is common to most OC.sub.-- StorageManagerbased classes. They are available for use in implementing object operations. Common subextension membership These functions add objects to and remove them from the common subextension for a type. static void addToCommonExtension(OC.sub.-- Type, theType, OC.sub.-- -Object* theObj); Adds *theObj to the common subextension for *theType. static void addToAllCommonExtensions(OC.sub.-- Object, theObj); Adds *theObj to its direct type's common subextension and to the common subextensions for all the OC.sub.-- Type's supertypes.
______________________________________
static void removeFromCommonExtension (OC.sub.-- Type* theType,
OC.sub.-- Object* theObj);
______________________________________
Removes *theObj from the common subextension for *theType.
______________________________________
static void removeFromAllCommonExtensions (OC.sub.-- Object*
theObj);
______________________________________
Removes *theObj from its OC.sub.-- Type's common subextension and from the common subextensions for all the OC.sub.-- Type's supertypes. Common subindex membership
______________________________________
static void addToCommonIndex (OC.sub.-- Type* theType,
OC.sub.-- Property* theProp, OC.sub.-- Object* theObj);
______________________________________
Adds *theObj to the common subindex for the indexed property *theProp. The *theType argument is ignored. static void addToAllCommonIndexes(OC.sub.-- Object, theObj); Adds *theObj to all common subindexes for all the indexed properties for *theObj.
______________________________________
static void removeFromCommonIndex (OC.sub.-- Type* theType,
OC.sub.-- Property* theProp, OC.sub.-- Object* theObj);
______________________________________
Removes *theObj from the common subindex for the indexed property *theProp. The *theType argument is ignored. static void removeFromAllCommonIndexes(OC.sub.-- Object, theObj); Removes *theObj from all common subindexes for all the indexed properties for *theObj.
______________________________________
static void updateCommonIndex (OC.sub.-- Type* theType,
OC.sub.-- Property* theProp, OC.sub.-- Object* theObj);
______________________________________
Updates *theObj in the common subindex for the indexed property *theProp. Updating involves adding current index entries and removing entries that are no longer used. The *theType argument is ignored. static void updateAllCommonIndexes(OC.sub.-- Object* theObj); Updates *theObj in all common subindexes for all the indexed properties for *theObj. Updating involves adding current index entries and removing entries that are no longer used. static void checkAllIndexes(OC.sub.-- Object* theObj); Checks for uniqueness the indexes for all unique properties on *theObj. If checkAllIndexes() finds a non-unique value, it raises an OC.sub.-- NotUnique exception. Subextension iteration participation OC.sub.-- Boolean isIterationParticipant(OC.sub.-- Type* theType); Returns OC.sub.-- true if this storage manager is a participant in iteration over a specialized subextension for *the-Type; returns OC.sub.-- false otherwise. OC.sub.-- InstanceIterator functions call the OC.sub.-- Storage-Manager::getIterator() functions on only those storage managers that are enabled as participants in the iteration. void enableIterationParticipation(OC.sub.-- Type* theType); Enables this storage manager as a participant in iteration for *theType. For efficiency, OC.sub.-- Instance-Iterator functions call the OC.sub.-- StorageManager::get-Iterator() function on only those storage managers that are enabled as participants in the iteration. void disableIterationParticipation(OC.sub.-- Type* theType); Disables this storage manager as a participant in specialized subextension iteration for *theType. OC.sub.-- InstanceIterator functions call the OC.sub.-- Storage-Manager::getIterator() function on only those storage managers that are enabled as participants in the iteration. Subindex iteration participation
______________________________________
OC.sub.-- Boolean isIndexParticipant (OC.sub.-- Type* theType,
OC.sub.-- Property* theProp);
______________________________________
Returns OC.sub.-- true if this storage manager is a participant in iteration over a specialized subindex for property *theProp on type *theType. It returns OC.sub.-- false otherwise. OC.sub.-- IndexIterator functions call the OC.sub.-- Storage-Manager::getIterator() function on only those storage managers that are enabled as participants in iteration over a specialized subindex for the property.
______________________________________
void enableIndexParticipation (OC.sub.-- Type* theType,
OC.sub.-- Property* theProp, OC.sub.-- Boolean ordered,
OC.sub.-- Boolean isUnique);
______________________________________
Enables this storage manager as a participant in iteration over a specialized subindex for property *theProp on type *theType. If *theProp does not have an index, enableIndexParticipation() creates one, making it ordered if ordered is OC.sub.-- true and unique if isUnique is OC.sub.-- true. Call enableIndexParticipation() for each property for which this storage manager implements a specialized subindex.
______________________________________
void disableParticipation (OC.sub.-- Type* theType,
OC.sub.-- Property* theProp);
______________________________________
Disables this storage manager as a participant in iteration over the specialized subindex for property *theProp on type *theType. IMPLEMENTING TRANSACTION AND CACHE HANDLING Transaction and cache handling support Overview Every OC.sub.-- StorageManager subclass must provide the processing that needs to take place before and after transaction and cache handling operations occur. The storage manager developer is responsible for identifying the tasks, if any, that the storage manager's trans-action and cache handling functions need to perform. Concurrent object ID allocation At a site that needs to support simultaneous object creation by concurrent applications, the applications must create and use an OC.sub.-- OIDSpace object to manage the allocation of object IDs(OIDs). The OC.sub.-- OIDSpace class enables concurrent allocation of OIDs without risk of duplication. Class OC.sub.-- OIDSpace is described in the Reference Manual, Volume 1: Class Library. As that manual states, the application must activate the OC.sub.-- OIDSpace object with an OC.sub.-- LockType of OC.sub.-- instantUpdateLock. The application must also call putObject() on the OC.sub.-- OIDSpace immedi-ately after its use. Storage manager deallocation An OC.sub.-- StorageManager instance should never be deallo-cated from memory while any of the objects it manages are in memory. The "Storage management" chapter of the Developer's Guide informs application developers about this restriction. Functions for transaction and cache handling The transaction and cache handling functions are all called by related Client Library free functions, which have names similar to the OC.sub.-- StorageManager functions. An example is the function OC.sub.-- StorageManager::start-Transaction(). At the end of its processing, OC.sub.-- -transactionStart() calls startTransaction() on each active instance of an OC.sub.-- StorageManager class. Application code may also call these functions where required. Unimplemented functions These functions are all pure virtual, so must be implemented by the storage management developer. Transaction handling virtual void startTransaction(); This function is called on each active storage manager at the end of OC.sub.-- transactionStart(). Usually, after a new transaction is started, the application must construct the storage managers needed to manage its objects. However, one or more storage managers may already exist when the transaction starts. A storage manager can exist because the preceding transaction was ended with an OC.sub.-- keepCache setting, or because the storage manager was created outside the scope of any transaction. OC.sub.-- StorageManager::startTransaction() processing must be performed for each storage manager, whether or not the storage manager exists at the start of the transaction. Also, the startTransaction() processing should be performed only once per transaction for each object. You can satisfy these requirements by using the following approach: 1. Define a function on each storage manager class to perform the processing that startTransaction() must perform. The function might be called startXAProcessing(), for example. (Alternatively, you could give each class a different function with the same purpose.) 2. For each class, implement the startXAProcessing() function described in Step 1. 3. Implement startTransaction() as a pass-through function, whose only action is to call the startXAProcessing() function. 4. Code the storage manager class's constructor to include a call to startXAProcessing(). Following these steps results in identical processing for each storage manager, whether it exists at the transaction's start or is created during the transaction. virtual void abortTransaction(); This function is called on each active storage manager at the beginning of OC.sub.-- transactionAbort(). virtual void checkpointTransaction(); This function is called on each active storage manager at the beginning of OC.sub.-- transactionCheckpoint(). virtual void commitTransaction(); This function is called on each active storage manager at the beginning of OC.sub.-- transactionCommit(). Cache handling virtual void cleanCache(); If the cache disposition is set to OC.sub.-- cleanCache, cleanCache() is called on each active storage manager during execution of OC.sub.-- transactionCommit() or OC.sub.-- trans-actionAbort(), as part of the cache cleaning operation. Database close virtual void closeDatabase(); This function is called on each active storage manager at the beginning of OC.sub.-- close(). ADMINISTERING STORAGE MANAGEMENT FACILITIES Task overview The role of storage management administrator encompasses management of the tasks of creating, configuring, using, and deleting storage managers. (Bear in mind that the term "storage manager" refers to an instance of an OC.sub.-- -StorageManager-based class.) For some storage management facilities, these tasks also pertain to instances of related, component classes. Management of the configuration and use of storage managers is specific to the particular OC.sub.-- StorageManager class and the storage management facility in which it serves. Therefore, this guide does not address issues of storage manager configuration and use. There are, however, some points that you should consider in the creation and deletion of all storage managers; these are addressed in the following two sections. When to create a storage manager Determining storage manager scope and number The decision on when to create a new storage manager is strongly influenced by two factors:the scope of the prospective storage manager (the number of objects that can belong to it) and the number of storage managers that can exist concurrently. These two factors are interdependent:the greater a storage manager's scope, the fewer of them are needed, and vice versa. Each OC.sub.-- StorageManager-based class has to make its own trade-offs regarding scope and number. Following are some considerations to take into account when determining the scope and number of storage managers. Reference space One limitation affecting both the scope and the number is the storage manager's reference spaces, as defined by their OC.sub.-- Reference reference value structures. If you plan to use multiple storage managers, scope is affected by the amount of interstorage manager referencing that will be required. A small data set, for which the number of objects is expected to be much smaller than the number of usable references in a storage manager's reference space, is a strong candidate for association with a single storage manager. Note that the usable reference space of a particular storage manager may be limited to significantly less than the theoretical maximum imposed by the OC.sub.-- Reference structure. This limitation may be introduced whenever a storage manager class imposes partitionings, structures, or orders on its reference spaces. The primary motivation in limiting the number of storage managers is usually the amount of processing required to handle inter-storage manager references. If a potentially large data set can easily be separated into two or more parts such that references from one part to another are rarely used, there is a strong case for creating the objects in each part with a different storage manager instance. Resource limitations Occasionally, the number of storage managers is limited by a particular storage manager's consumption of a great deal of memory or disk resources. Performance of persistent, inter-SM references An additional factor limiting the number of storage manager instances is ONTOSDB's current storage manager identification algorithm for support of persistent, inter-storage manager references. This algorithm stores a reference to each storage manager instance in an OC.sub.-- List in the database's kernel area. The time and memory overhead involved in accessing an element in a large OC.sub.-- List is roughly proportional to the position of the element in the OC.sub.-- List. Therefore, it is possible to have some reduction in the efficiency of storage managers created after the creation of a great many others. For most applications, the impact of this overhead is negligible. Only in an application that creates hundreds of storage managers would the effect be noticeable. Even in such an application, the impact is likely to be minimal, unless the application frequently accesses objects containing persistent, inter-storage manager references. Caveats on deletion of storage managers Do not deallocate from memory any OC.sub.-- StorageManager-based class instance if there is the possibility that any objects belonging to it are still active. Do not delete from the database any OC.sub.-- StorageManager-based class instance if there is the possibility that any objects belonging to it still exist or are still referenced by other objects (active or inactive) belonging to other storage managers. Results of attempts to violate either of these con-straints are undefined. OC-StorageManager function The following are OC.sub.-- StorageManager implemented functions that support the tasks of the storage management administrator. Constructors and destructor OC.sub.-- StorageManager(char* name=(char*) OC.sub.-- null); OC.sub.-- StorageManager constructor, called from subclass constructors only. You may optionally specify a name for the storage manager with the argument name. OC.sub.-- StorageManager(OC.sub.-- APL* theAPL); OC.sub.-- StorageManager activation constructor. .about.OC.sub.-- StorageManager(); Administrative member functions void destroy(OC.sub.-- Boolean aborted); Prepares this storage manager for deallocation. If aborted is set to OC.sub.-- true, destroy() has been called as a result of an exception handler abort. This method should not be called directly except from this class's destructor or from the destroy() function of derived classes. unsigned short getAreaNumber(); Returns the ID number of the kernel area for the open logical database. virtual OC.sub.-- Type* getDirectType(); Returns a pointer to this storage manager's OC.sub.-- Type. unsigned short getID(); Returns the unique ID for this OC.sub.-- StorageManager instance. Objects in the ODBMS 20 of the illustrative embodiment are units of data representing the objects (people, places, concepts, and other things) found in the application 10 domain. Objects have a type (what they are, such as a "baseball player"), which can be determined at run-time and usually have some type-appropriate data (metrics, colors, labels, descriptions, etc. like "name", "batting record", "height", "rookie year") , and some type-appropriate behavior (what they can do, what can be done with/to them "play ball", "strike out", "practice", "get traded"), associated therewith. Object handling tasks, including reading and activating objects, and writing and putting objects to the data store, are implemented with object handling member functions. In the illustrative ONTOS DB, every object, upon instantiation, is assigned to a storage manager instance of the SM API based class. The associated storage manager instance is initially responsible for locating a suitable memory location for newly instantiated objects. The status of an object can be queried using functions in the object handling interface. An object's storage manager also includes functions for manipulating objects in memory or in the ODBMS. An object's storage manager effects the implementation of such object operations as activation, deactivation, deletion from the database, and deallocation. As indicated hereinbefore, each object handled by the ODBMS in the illustrative embodiment is assigned to and managed by a storage manager instance of SM API 24. The storage manager must have a mechanism or reference by which it can refer to either an in-memory or persistent object. Thus, every object has a property or reference that refers to it. References are connections by which one object can be related to another. For example, an object representing a "baseball player" may have references that connect it with other objects such as those representing a "baseball team", "practice schedule", and/or "baseball uniform". Iteration and indexing operations relate to the use of indices and extensions that facilitate fast access to objects based on their type and/or data. ODBM's typically include a mechanism to permit applications to iterate over objects in the database for processing. In ONTOS DB, as described in the referenced materials, indices and extensions are used to iterate over objects that are represented as instances of types in the database schema. A type is a kind of object that defines the state, behavior and applicability of other entities, called its instances. Types specify an instance's (other object's) state in terms of its properties; dynamic behaviors in terms of its procedures; and means of constructing new instances. Types in ONTOS DB in the illustrative embodiment also provide information used in bringing instances of the Type into memory from disk and an optional iterator for accessing all the instances of the Type. Similarly, indices, supported in typical ODBM's known in the art including ONTOS DB of the illustrative embodiment, allow fast access to objects when some of their data is known but their identities are not. For example, a structure listing each "ball player" in order by batting average, would allow fast access to the best and worst hitters in the league (the top and bottom of the listing). Extensions allow fast access to all objects of a known type regardless of their data. For example, a list of all "pitchers" would allow faster access to all of the pitchers than a list of all "ball players" or, worse yet, a huge list of all baseball-related objects, including "ball players", "teams", "team managers", "stadiums", etc Transactions are operations in the context of the object oriented database, effected by the ODBMS, in which individual modifications of the database are aggregated into a single large modification that either occurs in its entirety (is "committed"), or does not occur at all (is "aborted"). All client application database operations occur in transactions which are effected by the ODBMS, or ONTOS DB in the case of the illustrative embodiment. In a typical ODBMS, transactions are referred to as an atomic set of operations on one or more objects. "Atomic" meaning that the operations within the transaction are treated as if they all happened or none of them happened. Continuing the "baseball player" example, each "ball game" may be associated with a transaction since either the game is held and all of the statistics for the teams and players in the game are updated accordingly, or the game is called off due to rain and the team and player records are ALL left unchanged. The object handling, reference handling, indices and extensions, and transactions are typical ODBMS constructs that are accommodated by the SM API 24 in the modular, illustrative implementation described herein. It should be appreciated that the SM API 24 is not an absolute requirement, but is an aspect of ONTOS DB included in this illustrative embodiment. To practice the invention it is only necessary that the constructs and functions for manipulating the constructs of the typical ODBMS discussed hereinbefore be supported at the "front end" API of an external storage manager mechanism 26 according to the invention, discussed hereinafter. In this illustrative embodiment ONTOS DB provides such support in the form and functions of the SM API 24. These constructs and the operations defined for manipulating these constructs provide the API or "front end" to the external storage manager mechanism 26. As this "front end" API is indistinguishable from the API to an object-oriented database programming system, the external storage manager mechanism 26 allows an application 10 to be developed in the normal object-oriented paradigm, as if all data were being transparently accessed from a true object-oriented database. In particular, the application developer need not be concerned with the interface requirements for each of the data storage facilities being accessed. The functions comprising the SM API 24 in the illustrative embodiment invoke specialized external storage manager(s) 28, as discussed hereinafter, to meet particular requirements of external data stores 22 of a particular installation. Essentially, the external storage manager mechanism 26 provides a flexible, extensible adapter between the generic functionality of the SM API 24 or other ODBMS API and the particular requirements of external data stores 22 or foreign databases and files with various schemas and formats. The external storage manager mechanism 26 described here focuses on the objects' type and data, their references to other objects, the transactions in which the objects participate, and the use of indices and extensions to quickly access the objects. Each of these "front-end" constructs is mapped by the external storage manager 26 mechanism into one or more "back-end" constructs supported directly by the available external data store(s) 22 or data storage subsystem(s). Applications written using the generic front-end constructs apply various operations to the constructs. These operations are implemented uniformly by the external storage manager 26 mechanism by either dispatching to operations specific to the external data store(s) 22 or data storage facility being supported, or by internal operations of the external storage manager mechanism 26 using data cached, as known in the art, from previous accesses to the data storage facility. The "back end" of the external storage manager(s) 28 which communicates directly with the external data store(s) 22, consists of an API with its own set of constructs, i.e. back end constructs. Unlike the "front end", which is designed to be identical to the ODBMS API, the "back end" API is unique and not intended to be identical to any particular paradigm or standard. Instead, "back end" constructs are implemented and intended to generally correspond to the common kinds of constructs used in a wide range of data storage facilities and their APIs. Each of the back end constructs is represented in the back-end API as a "generic" or "abstract" construct which has very specific requirements but still allows a wide range of variation in-the implementation of these requirements in the context of a data storage facility. These common back end or external data storage facility API constructs and their requirements are defined as follows: Storage manager--a dedicated object that represents a particular data storage facility. Each such data storage facility is expected to support implementations of most or all of the other common data storage facility constructs described hereinafter. Each implementation of these constructs is usually valid only within the context of a specific data storage facility. Examples of data storage facilities are disk files and specific relational databases. Record--one or more pieces of related data that make up an entry in the data storage facility. Allowable variations on "record" include "physical records", "network or hierarchy of physical records", "collection of physical record", or "persistent object". Records provide the basis for object data and object type information presented to the application. Key--an object containing one or more data items that can be used to identify a particular record regardless of how (other) data associated with that record may be updated. Allowable variations on "key" include "disk address", "logical record ID", "primary key (simple or composite)", "hierarchial path", "network path", or "persistent object id". Keys provide the basis for object identity and the ability to reference objects being manipulated. Keys are created "on the fly", as objects are created, to correspond to the actual location of data associated with the object. Typemap--an object defining the transformation between records and objects. Typemaps provide the basis for representing record-based stored data as object-based application data and for transforming the object-based data updated or generated in the application (back) into record-based data for storage. There typically exists one Typemap per data storage facility and per type of object whose data is stored via that facility regardless of the number of format(s) or record type(s) in which the data is stored. Different pieces of implementation technology may be shared by Typemaps that access similar data storage facilities or similar types of object data. Each Typemap object includes key layout information and object layout information, used in constructing keys and objects as described with respect to the examples hereinafter. Distributed Transaction--a protocol allowing any data storage facilities that support transaction processing to be notified when the application has determined that a set of changes constitutes a complete transaction. Distributed Index Iterator and Common Index--a protocol allowing any data storage facilities that support index structures to use these index structures to implement fast access to records when some of their data is known but their keys are not. Data storage facilities that do not support index structures are allowed to use key-based "common" index structures stored by the external storage manager mechanism on their behalf, or to provide alternative (slow) forms of access, for the sake of completeness. Distributed Extension Iterator and Common Extension--a protocol allowing any data storage facilities that support iteration over all records corresponding to an object type to use this capability to produce appropriate objects when the application attempts to process all of the objects of a given type. Data storage facilities that do not support this capability are allowed to use key-based "common" extension structures stored by the external storage manager mechanism on their behalf. The operation of the external storage manager mechanism 26, which maps the front end constructs of a typical ODBMS to the set of back end constructs manipulated by respective external storage manager(s) 28 and supported by the external data store(s) 22, is effected by abstract classes of functions. Such operation serves as the basis for storage management for applications that store ODBMS data in external data stores or store external data in the ODBMS for use by an object application. The abstract classes of functions are set forth in the following text taken from the ONTOS DB 3.0 Reference Manual Volume I Class Library. OC.sub.-- CleanupObj--OC.sub.-- Entity--OC.sub.-- Object--OC.sub.-- ExternalKey OC.sub.-- ExternalFreeFormKey Class OC.sub.-- ExternalFreeFormKey is available as part of the optional External Storage Management product, which can be used to develop external storage management for ONTOS DB 3.0 client applications. The storage manager developer is responsible for implementing many of the functions for OC.sub.-- External-FreeFormKey and classes derived from it. OC.sub.-- ExternalFreeFormKey implements some of the functions defined on its base class, OC.sub.-- ExternalKey, in an architecture that allows a wide range of options for classes derived from OC.sub.-- ExternalFreeFormKey.
______________________________________
To use
#include "External.h"
Synopsis
class OC.sub.-- ExternalFreeFormKey : public OC.sub.-- ExternalKey {
protected:
OC.sub.-- ExternalFreeFormKey (
OC.sub.-- Entity* referent = (OC.sub.-- Entity*) 0);
OC.sub.-- ExternalFreeFormKey (OC.sub.-- APL* theAPL);
.about.OC.sub.-- ExternalFreeFormKey ( );
virtual OC.sub.-- Object* getReferent (OC.sub.-- ExternalSM*&,
OC.sub.-- Type*&, OC.sub.-- LockType);
virtual OC.sub.-- ExternalSM* getExternalSM ( ) = 0;
virtual void* getReferenceText (OC.sub.-- ExternalSM*,
OC.sub.-- LockType) = 0;
virtual OC.sub.-- Type* getTypeOfObj (void*) = 0;
virtual OC.sub.-- Object* getProtoObj (void*, OC.sub.-- Type*) =
0;
};
______________________________________
Constructors and destructors
______________________________________
OC.sub.-- ExternalFreeFormKey (
OC.sub.-- Entity* referent = (OC.sub.-- Entity*) 0);
______________________________________
Constructor for OC.sub.-- ExternalFreeFormKey; optional argument referent points to the entity that this key represents. OC.sub.-- ExternalFreeFormKey(OC.sub.-- APL* theAPL); Activation constructor. .about.OC.sub.-- ExternalFreeFormKey(); Destructor for OC.sub.-- ExternalFreeFormKey. Class Library reference Member functions virtual OC.sub.-- ExternalSM* getExternalSM(); Returns the OC.sub.-- ExternalSM associated with this OC.sub.-- External FreeFormKey.
______________________________________
virtual OC.sub.-- Object* getProtoObj (void* dataStruct,
OC.sub.-- Type* objType);
______________________________________
Returns an initialized but inactive OC.sub.-- Object. The argument dataStruct is a free-form data structure representing the object; its value can be obtained through a call to OC.sub.-- ExternalFreeFormKey::getReferent-Text(). The argument objType also represents the object; its value can be obtained through a call to OC.sub.-- External-FreeFormKey::getTypeOfObj().
______________________________________
virtual OC.sub.-- Object* getReferent (OC.sub.-- ExternalSM*& extSM,
OC.sub.-- Type*& type, OC.sub.-- LockType lock);
______________________________________
Returns a pointer to the referent of this OC.sub.-- External-TypeMappedKey. See the entry on OC.sub.-- ExternalKey::get-Referent(), starting on page.backslash.2-159, for a detailed description.
______________________________________
virtual void* getReferentText (
OC.sub.-- ExternalSM* extSM, OC.sub.-- LockType lock);
______________________________________
Returns a pointer to a free-form data structure that represents, in a format specific to an OC.sub.-- External-FreeFormKey class implementation, the state of an object to be activated. The extSM argument is the object's storage manager, and lock argument is the type of lock for the object. virtual OC.sub.-- Type* getTypeOfObj(void* dataStruct); Returns the OC.sub.-- Type of the object described by dataStruct, a free-form data structure whose value can be obtained through a call to OC.sub.-- ExternalFreeForm-Key::getReferentText(). See also Related classes OC.sub.-- ExternalSM, OC.sub.-- ExternalTypeMap, and OC.sub.-- ExternalKey Related documentation See in the discussion about external keys in the ONTOSDB External Storage Management Guide. OC.sub.-- CleanupObj--OC.sub.-- Iterator--OC.sub.-- ExternalInstIterator--OC.sub.-- ExternalIndexIterator Class OC.sub.-- ExternalIndexIterator is available as part of the optional External Storage Management product, which can be used to develop external storage management for ONTOS DB 3.0 client applications. Class OC.sub.-- ExternalIndexIterator, derived from OC.sub.-- -ExternalInstIterator, provides iteration over indexed properties on objects mapped by the iterator's associated OC.sub.-- ExternalTypeMap instance.
______________________________________
To use
#include "External.h"
Synopsis
class OC.sub.-- ExternalIndexIterator : public
OC.sub.-- External-InstIterator{
public:
OC.sub.-- ExternalIndexIterator (OC.sub.-- ExternalTypeMap*
source,
OC.sub.-- Type* type, OC.sub.-- Property* prop,
OC.sub.-- -Argument value,
OC.sub.-- LockType lock, void* cursorData = 0);
OC.sub.-- ExternalIndexIterator (OC.sub.-- ExternalTypeMap*
source,
OC.sub.-- Type* type, OC.sub.-- Property* prop,
OC.sub.-- Argument start,
OC.sub.-- Argument end, OC.sub.-- Boolean yieldInOrder,
OC.sub.-- LockType lock, void* cursorData = 0);
virtual OC.sub.-- Boolean moreData ( );
OC.sub.-- Property* getProperty ( );
OC.sub.-- Argument getStart ( );
OC.sub.-- Argument getEnd ( );
OC.sub.-- Boolean get YieldsInOrder ( );
OC.sub.-- Boolean getYieldsRange ( );
};
______________________________________
Constructors
______________________________________
OC.sub.-- ExternalIndexIterator (OC.sub.-- ExternalTypeMap* source,
OC.sub.-- Type* type, OC.sub.-- Property* prop, OC.sub.-- Argument
value,
OC.sub.-- LockType lock = OC.sub.-- defaultLock,
void* cursorData = 0);
OC.sub.-- ExternalIndexIterator (OC.sub.-- ExternalTypeMap* source,
OC.sub.-- Type* type, OC.sub.-- Property* prop, OC.sub.-- Argument
start,
OC.sub.-- Argument end, OC.sub.-- Boolean yieldInOrder,
OC.sub.-- LockType lock = OC.sub.-- defaultLock,
void* cursorData = 0);
______________________________________
OC.sub.-- ExternalIndexIterator constructors. The first overload initializes the instance's data members to the same state achieved by reset(). The constructors' arguments are the following:
______________________________________
source Pointer to the OC.sub.-- ExternalTypeMap that
generated this instance.
type Pointer to the type of objects the iterator
returns.
prop Pointer to the OC.sub.-- Property over which to iterate.
value Value required for prop for the iterator to return
the object.
lock Type of lock for objects in the iteration.
cursorData
Optional pointer to an implementation-specific
object, which contains data for tracking the state
of the iteration.
yieldInOrder
Value OC.sub.-- true yields an index in ascending
order of the property's value.
start First value in a range of indexes.
end Last value in a range of indexes.
______________________________________
Member functions OC.sub.-- Argument getEnd(); Returns the end index of the range for iteration. If the iteration is for all objects with the identical single value for a property, getEnd() returns the single value. OC.sub.-- Property* getProperty(); Returns a pointer to the property for the iteration. OC.sub.-- Argument getStart(); Returns the starting index of the range for iteration. If the iteration is for all objects with the identical single value for a property, getStart() returns the single value. OC.sub.-- Boolean getYieldsInOrder(); Returns OC.sub.-- true if the iterator yields in index order; returns OC.sub.-- false otherwise. OC.sub.-- Boolean getYieldsRange(); Returns OC.sub.-- true if the iterator yields a range of indices; returns OC.sub.-- false otherwise. OC.sub.-- Boolean moreData(); Not implemented for this class. See also Related classes OC.sub.-- ExternalSM, OC.sub.-- ExternalTypeMap, OC.sub.-- ExternalKey, OC.sub.-- Iterator, and OC.sub.-- ExternalInstIterator Related documentation See the discussion about implementing iteration of type-mapped objects in the ONTOS DB External Storage Management Guide. OC.sub.-- CleanupObj--OC.sub.-- Iterator--OC.sub.-- ExternalInstIterator Class OC.sub.-- ExternalInstIterator is available as part of the optional External Storage Management product, which can be used to develop external storage management for ONTOS DB 3.0 client applications. Class OC.sub.-- ExternalInstIterator, derived from OC.sub.-- Iterator, provides iteration over objects that are mapped by the iterator's associated OC.sub.-- ExternalTypeMap instance.
______________________________________
To use
#include "External.h"
Synopsis
class OC.sub.-- ExternalInstIterator : public OC.sub.-- Iterator {
public:
OC.sub.-- ExternalInstIterator (OC.sub.-- ExternalTypeMap*
source,
OC.sub.-- Type* type, OC.sub.-- LockType lock =
OC.sub.-- defaultLock,
void* cursorData = 0);
virtual OC.sub.-- Boolean moreData ( );
virtual OC.sub.-- Argument operator ( ) ( );
virtual OC.sub.-- Entity* yieldEntityValue ( );
virtual long yieldIntegerValue ( );
virtual char* yieldStringValue ( );
virtual double yieldRealValue ( );
virtual void* yieldPointerValue ( );
virtual OC.sub.-- Boolean yieldLogicalValue ( );
virtual char yieldCharacterValue ( );
virtual void reset (OC.sub.-- LockType lock =
OC.sub.-- -defaultLock);
virtual void reset (OC.sub.-- Entity* ent,
OC.sub.-- LockType lock = OC.sub.-- defaultLock);
virtual OC.sub.-- Boolean seek (long offset,
OC.sub.-- SeekType sType);
protected:
OC.sub.-- ExternalTypeMap* getSource ( );
void* getCursorData ( );
OC.sub.-- Type* getType ( );
};
______________________________________
Constructors
______________________________________
OC.sub.-- ExternalInstIterator (OC.sub.-- ExternalTypeMap* source,
OC.sub.-- Type* type, OC.sub.-- LockType lock =
OC.sub.-- defaultLock,
void* cursorData = 0);
______________________________________
OC.sub.-- ExternalInstIterator constructor. The constructor's arguments are the following:
______________________________________
source Pointer to the OC.sub.-- ExternalTypeMap that
generated this instance.
type Pointer to the type of objects that the iterator
returns.
lock Type of lock for objects in the iteration.
cursorData Optional pointer to an implementation-specific
object, which contains data for tracking the
state of the iteration.
______________________________________
Member functions void* getCursorData(); Returns a pointer passed as the cursorData argument to the OC.sub.-- ExternalInstIterator constructor. If the constructor was called with cursorData equal to 0, this function returns 0. virtual OC.sub.-- ExternalTypeMap* getSource(); Returns a pointer to the type map that generated this OC.sub.-- ExternalInstIterator. virtual OC.sub.-- Type* getType(); Returns a pointer to the OC.sub.-- Type over which this OC.sub.-- ExternalInstIterator iterates. virtual OC.sub.-- Boolean moreData(); Returns OC.sub.-- true if there is more data over which to iterate; returns OC.sub.-- false otherwise. virtual OC.sub.-- Argument operator()(); Returns the next instance, if any. virtual void reset(OC.sub.-- LockType lock=OC.sub.-- defaultLock);
______________________________________
virtual void reset (OC.sub.-- Entity* ent,
OC.sub.-- LockType lock = OC.sub.-- defaultLock);
______________________________________
Not needed for this class. Calling either raises an OC.sub.-- NotImplemented exception. virtual OC.sub.-- Boolean seek(long offset, OC.sub.-- SeekType sType); Not needed by OC.sub.-- ExternalInstIterator; its default implementation raises an OC.sub.-- NotImplemented exception. virtual char yieldCharacterValue(); Not needed by OC.sub.-- ExternalInstIterator; its default implementation raises an OC.sub.-- NotImplemented exception. virtual OC.sub.-- Entity* yieldEntityValue(); Returns the next instance, if any. virtual long yieldIntegerValue(); virtual char* yieldStringValue(); virtual double yieldRealValue(); virtual void* yieldPointerValue(); virtual OC.sub.-- Boolean yieldLogicalValue(); These functions are not needed by OC.sub.-- ExternalInst-Iterator; their default implementations raise an OC.sub.-- NotImplemented exception. See also Related classes OC.sub.-- ExternalSM, OC.sub.-- ExternalTypeMap, OC.sub.-- ExternalKey, OC.sub.-- Iterator, and OC.sub.-- ExternalIndexIterator Related documentation See the discussion about implementing iteration of type-mapped objects in the ONTOS DB External Storage Management Guide. OC.sub.-- CleanupObj--OC.sub.-- Entity--OC.sub.-- Object--OC.sub.-- ExternalKey Class OC.sub.-- ExternalKey is available as part of the optional External Storage Management product, which can be used to develop external storage management for ONTOS DB 3.0 client applications. OC.sub.-- ExternalKey is an abstract class that must be subclassed by the storage management developer. OC.sub.-- ExternalKey subclasses encapsulate the persistent identity of objects stored in an external data store. It is possible for the storage manager developer to subclass OC.sub.-- ExternalKey itself. However, subclassing one of OC.sub.-- ExternalKey's ONTOS-provided subclasses , OC.sub.-- External-TypeMappedKey and OC.sub.-- ExternalFreeFormKey, is usually more beneficial.
______________________________________
To use
#include "External.h"
Synopsis
class OC.sub.-- ExternalKey : public OC.sub.-- Object {
protected:
OC.sub.-- ExternalKey (OC.sub.-- Entity* referent =
(OC.sub.-- -Entity*) 0);
OC.sub.-- ExternalKey (OC.sub.-- APL* theAPL);
.about.OC.sub.-- ExternalKey ( );
void destroy (OC.sub.-- Boolean aborted);
virtual OC.sub.-- Type* getDirectType ( );
virtual unsigned long getReferentHashKey ( ) const;
virtual unsigned long getEntityHashKey ( ) const;
virtual OC.sub.-- Boolean operator==(const
OC.sub.-- Entity& ent)
const;
virtual OC.sub.-- Object* getReferent
(OC.sub.-- ExternalSM*& sm,
OC.sub.-- Type*& type, OC.sub.-- LockType lock);
virtual void lockReferent (OC.sub.-- LockType lock);
virtual void putReferent ( );
virtual void deleteReferent ( );
OC.sub.-- Object* getReferentIfActive ( );
OC.sub.-- LockType getReferentLockType ( );
OC.sub.-- Boolean getReferentIsNew ( );
OC.sub.-- Boolean getReferentIsInDB ( );
void setReferentLockType (OC.sub.-- LockType
theLock);
};
OC.sub.-- ExternalKey (OC.sub.-- Entity* referent =
(OC.sub.-- Entity*) 0);
______________________________________
Constructor for OC.sub.-- ExternalKey; optional argument referent points to the entity that this key represents. OC.sub.-- ExternalKey(OC.sub.-- APL* theAPL); Activation constructor. .about.OC.sub.-- ExternalKey(); Destructor for OC.sub.-- ExternalKey. Member functions virtual void deleteReferent(); Removes from the database the referent of this OC.sub.-- ExternalKey. The storage manager developer must implement this function. virtual unsigned long getEntityHashKey(); Returns the hash key value for the referent of this OC.sub.-- ExternalKey. The storage manager developer must implement this function.
______________________________________
virtual OC.sub.-- Object* getReferent (OC.sub.-- ExternalSM*& extSM,
OC.sub.-- Type*& type, OC.sub.-- LockType lock);
______________________________________
Returns a pointer to the referent of this OC.sub.-- ExternalKey. The referent returned is initialized but inactive; that is, its data members have been initialized from a persistent representation of the object, but its activation constructor has not yet executed. The function also returns, through the extSM argument, a pointer to the referent's storage manager. It also returns, through the type argument, a pointer to the OC.sub.-- Type of the referent. The lock argument is the type of lock for the referent. The storage manager developer must implement this function. virtual unsigned long getReferentHashKey(); Returns the hash key value for the referent of this OC.sub.-- ExternalKey. The default implementation returns the same value as OC.sub.-- ExternalKey::getEntityHashKey(). virtual void lockReferent(OC.sub.-- LockType lock); Acquires or upgrades a lock, of the specified OC.sub.-- -LockType, on the referent of this OC.sub.-- ExternalKey. Attempts to downgrade a lock or to reacquire an existing lock have no effect. The storage manager developer must implement this function. Note that setting lock-buffering options with OC.sub.-- -setLockBuffering() or similar functions has no effect on objects with external storage managers. virtual OC.sub.-- Boolean operator==(OC.sub.-- Entity& key); Returns OC.sub.-- true if this OC.sub.-- ExternalKey and the OC.sub.-- -ExternalKey referenced by key are duplicate instances. The function returns OC.sub.-- false otherwise. The key argument must be associated with the same OC.sub.-- ExternalSM instance as this OC.sub.-- ExternalKey; however, the two keys may have been created by different OC.sub.-- ExternalTypeMaps. (The type of parameter key is OC.sub.-- Entity only for the purpose of internal optimization; the key argument must be of type OC.sub.-- ExternalKey.) The storage manager developer must implement this function. virtual void putReferent(); Stores in the database the current state of the referent of this OC.sub.-- ExternalKey. If the referent already exists in the database, putReferent() replaces it with the current state of the object. The storage manager developer must implement this function. See also Related classes OC.sub.-- ExternalSM and OC.sub.-- ExternalTypeMap Related documentation See the discussion about implementing external keys in the ONTOS External Storage Management Guide. OC.sub.-- CleanupObj--OC.sub.-- Entity--OC.sub.-- Object--OC.sub.-- StorageManager--OC.sub.-- ExternalSM Class OC.sub.-- ExternalSM is available as part of the optional External Storage Management product, which can be used to develop external storage management for ONTOS DB 3.0 client applications. OC.sub.-- ExternalSM is an abstract class that must be subclassed by the storage management developer. OC.sub.-- ExternalSM subclasses serve as the basis for storage management for applications that store ONTOS DB data in external data stores and/or store external data in ONTOS DB. External data stores include non-ONTOS DB databases with various paradigms and schemas, as well as files of various formats. OC.sub.-- ExternalSM is the recommended starting point for defining external storage manager classes. OC.sub.-- ExternalSM has the same interface (member functions ) as its base class, OC.sub.-- StorageManager. For development of external storage managers, OC.sub.-- ExternalSM offers two advantages over its base class: OC.sub.-- ExternalSM implements many of the OC.sub.-- StorageManager-defined virtual functions, with functionality to serve a wide range of OC.sub.-- ExternalSM-based classes. For most external storage managers, most of these ONTOS-provided implementations provide the needed functionality. Many OC.sub.-- ExternalSM functions translate an invocation of an OC.sub.-- ExternalSM function into an invocation of a function on an OC.sub.-- ExternalKey- or OC.sub.-- ExternalTypeMap-derived class. This delegation of functions to component classes supports code reuse, as a single OC.sub.-- ExternalSM subclass may use several instances of a single component class or instances of different component classes.
______________________________________
To use
#include "External.h"
Synopsis
class OC.sub.-- ExternalSM : public OC.sub.-- StorageManager {
public:
virtual OC.sub.-- Type* getDirectType ( );
virtual void putObject (OC.sub.-- Boolean deallocate =
OC.sub.-- false);
virtaul void deleteObject (
OC.sub.-- Boolean deallocate = OC.sub.-- false);
OC.sub.-- Iterator* getTypeMapIterator (
OC.sub.-- LockType lock = OC.sub.-- defaultLock);
virtual OC.sub.-- ExternalTypeMap* getTypeMap
(OC.sub.-- Type* theType);
protected:
OC.sub.-- ExternalSM (char* name = (char*) OC.sub.-- null);
OC.sub.-- ExternalSM (OC.sub.-- APL* theAPL);
.about.OC.sub.-- ExternalSM ( );
void destroy (OC.sub.-- Boolean aborted);
virtual OC.sub.-- Boolean isReferentActive
(OC.sub.-- -Reference* ref);
virtual OC.sub.-- Boolean isReferentModified
(OC.sub.-- -Reference* ref);
virtual OC.sub.-- Boolean isReferentNew
(OC.sub.-- Reference* ref);
virtual OC.sub.-- Boolean isReferentInDB
(OC.sub.-- -Reference* ref);
virtual OC.sub.-- Boolean isReferentDeleted
(OC.sub.-- -Reference* ref);
virtual OC.sub.-- Entity* getReferent (OC.sub.-- Reference* ref,
OC.sub.-- LockType lock);
virtual OC.sub.-- LockType getReferentLockType (
OC.sub.-- Reference* ref);
virtual void lockReferent (OC.sub.-- Reference* ref,
OC.sub.-- LockType lock);
virtual void discardReference (OC.sub.-- Reference* ref,
OC.sub.-- Boolean persistently);
virtual void* allocateObj (long sz, OC.sub.-- Type* theType,
OC.sub.-- Object* obj, OC.sub.-- Clustering clustering);
OC.sub.-- Object* activate (OC.sub.-- Object* obj,
OC.sub.-- Type* the Type,
OC.sub.-- ExternalKey* key);
virtual OC.sub.-- Boolean isObjNew (OC.sub.-- Object* obj);
virtual OC.sub.-- Boolean isObjInDB (OC.sub.-- Object* obj);
virtual OC.sub.-- Boolean isObjDeleted (OC.sub.-- Object* obj);
virtual OC.sub.-- Boolean isObjModified (OC.sub.-- Object* obj);
virtual void markObjModified (OC.sub.-- Object* obj);
virtual void unmarkObjModified (OC.sub.-- Object* obj);
virtual void putObj (OC.sub.-- Object* obj);
virtual void lockObj (OC.sub.-- Object* obj,
OC.sub.-- Lock-Type lock);
virtual OC.sub.-- LockType getObjLockType
(OC.sub.-- Object* obj);
virtual void deleteObj (OC.sub.-- Object* obj);
virtual void destroyObj (OC.sub.-- Object* obj);
virtual void deallocateObj (void* Obj);
virtual unsigned long getObjHashKey (OC.sub.-- Object* obj);
virtual unsigned long translateRefValue (
OC.sub.-- Entity* referent);
virtual unsigned long translateRefValue (
unsigned long oldRefValue,
OC.sub.-- StorageManager* oldContext);
virtual OC.sub.-- Boolean compareReferences (
OC.sub.-- Reference* r1, OC.sub.-- Reference* r2);
virtual void makePersistentReference (
unsigned long refValue,
OC.sub.-- Storage-Manager* forWhom,
OC.sub.-- PersistentReference& toBeSet);
virtual unsigned long resolvePersistent-Reference (
const OC.sub.-- PersistentReference& toBe-Resolved,
OC.sub.-- StorageManager* forWhom);
virtual void replacePersistentReference (
const OC.sub.-- PersistentReference& toBe-Replaced,
const OC.sub.-- PersistentReference& replacement,
OC.sub.-- StorageManager* forWhom);
virtual unsigned long
getInstanceCount-(OC.sub.-- Type* theType);
virtual OC.sub.-- Iterator* getIterator (OC.sub.-- Type* theType,
OC.sub.-- LockType lock);
virtual OC.sub.-- Iterator* getIterator (OC.sub.-- Type* theType,
OC.sub.-- Property*, OC.sub.-- Argument value,
OC.sub.-- LockType lock);
virtual OC.sub.-- Iterator* getIterator (OC.sub.-- Type* theType,
OC.sub.-- Property* prop, OC.sub.-- Argument start,
OC.sub.-- Argument end,
OC.sub.-- Boolean yieldInOrder, OC.sub.-- LockType lock);
virtual void startTransaction ( );
virtual void abortTransaction ( );
virtual void checkpointTransaction ( );
virtual void commitTransaction ( );
virtual void cleanCache ( );
virtual void beforeKeepCache ( );
virtual void afterKeepCache ( );
virtual void closeDatabase (OC.sub.-- Boolean cleanall);
OC.sub.-- Dictionary* getMaps ( );
void addTypeMap (OC.sub.-- Type* theType,
OC.sub.-- ExternalTypeMap* theMap);
void removeTypeMap (OC.sub.-- Type* theType,
OC.sub.-- ExternalTyepMap* theMap);
virtual OC.sub.-- ExternalKey* validateKey
(OC.sub.-- -ExternalKey* key);
};
______________________________________
Constructors and destructors OC.sub.-- ExternalSM(char* name=(char*) OC.sub.-- null); Constructor for OC.sub.-- ExternalSM; name is the optional object name. OC.sub.-- ExternalSM(OC.sub.-- APL* theAPL); Activation constructor. .about.OC.sub.-- ExternalSM(); Destructor for OC.sub.-- ExternalSM. Member functions void abortTransaction(); The storage manager developer implements this function, which is called at the beginning of OC.sub.-- transaction-Abort().
______________________________________
void activate (OC.sub.-- Object* obj, OC.sub.-- Type* theType,
OC.sub.-- ExternalKey* key;
______________________________________
Performs the final processing required to activate obj, which is a memory location for an object that is initialized but inactive. The argument theType must point to the OC.sub.-- Type for the object. The key argument must point to the OC.sub.-- ExternalKey for the object to be activated. The processing performed by activate() includes the location and invocation of the activation constructor wrapper function, vtbl simulation for instances of OC.sub.-- Types that do not have an available vtbl, and initialization of storage manager and self ref values for obj.
______________________________________
void addTypeMap (OC.sub.-- Type* theType,
OC.sub.-- ExternalTypeMap* theMap);
______________________________________
Adds an external type map, theMap, to the OC.sub.-- Dictionary of maps for the storage manager for the OC.sub.-- Type specified by theType. virtual void afterKeepCache(); Empty implementation, since it is not needed by OC.sub.-- ExternalSM.
______________________________________
virtual void* allocateObj (long sz, OC.sub.-- Type* type,
OC.sub.-- Object* obj, OC.sub.-- Clustering clustering);
______________________________________
In addition to performing other processing, allocate-Obj() uses the global function ::operator new to allocate space. Note: If you reimplement allocateObj(), be sure also to reimplement deallocateObj() with a complementary algorithm. virtual void beforeKeepCache(); Empty implementation, since it is not needed by OC.sub.-- -ExternalSM. virtual void checkpointTransaction(); The storage manager developer implements this function, which is called at the beginning of OC.sub.-- transaction-Checkpoint(). virtual void cleanCache(); Deletes from memory this storage manager instance and all its associated OC.sub.-- ExternalKey and OC.sub.-- ExternalTypeMap instances. Before deleting the OC.sub.-- ExternalSM, clean-Cache() iterates over the active OC.sub.-- ExternalKey and OC.sub.-- ExternalTypeMap instances and deletes them from memory. virtual void closeDatabase(OC.sub.-- Boolean cleanAll); The storage manager developer implements this function, which is called at the beginning of OC.sub.-- close(). virtual void commitTransaction(); The storage manager developer implements this function, which is called at the beginning of OC.sub.-- transaction-Commit().
______________________________________
virtual OC.sub.-- Boolean compareReferences (OC.sub.-- Reference* r1,
OC.sub.-- Reference* r2);
______________________________________
Returns OC.sub.-- true if r1 and r2 refer to the same referent. virtual void deallocateObj(void* inst); In addition to performing other processing, deallocateObj() uses the global function ::operator delete to deallocate space. Note: If you reimplement deallocateObj(), be sure also to reimplement allocateObj() with a complementary algorithm. virtual void deleteObj(OC.sub.-- Object* obj); Deletes from the database the OC.sub.-- Object pointed to by obj. If obj has no associated OC.sub.-- ExternalKey, deleteObj() determines that it is a new object that has never been put to the database and, therefore, simply marks it as deleted. If obj has an associated OC.sub.-- ExternalKey, deleteObj() calls the refinement of deleteReferent() on the object's OC.sub.-- ExternalKey. virtual void destroyObj(OC.sub.-- Object* obj); Prepares the OC.sub.-- Object pointed to by obj for deallocation from memory.
________ | ||||||
