ObjectStore C++ API Reference

Chapter 1

Introduction

This document describes the application programming interface to the functionality provided by the ObjectStore object-oriented database management system. ObjectStore seamlessly integrates the C and C++ programming language with the database services required by complex, data-intensive applications. These services include support for the following:

Persistence
Provision of a central repository for information that persists beyond the lifetime of the process that recorded it

Query processing
Support for associative data retrieval, such as lookup by name or ID number

Integrity control
Services that maintain data consistency based on specified database constraints

Access control
Services that protect data against unauthorized access

Concurrency control
Services that allow shared, concurrent data access

Fault tolerance
Services that protect data consistency and prevent data corruption even in the face of system crashes or network failures

Dynamic schema access
Services that allow the programmatic manipulation of database schema information

Schema evolution
Services that support schema change and automatic modification of database objects to conform to new schemas

Data compaction
Services that support data reorganization to eliminate fragmentation

ObjectStore Database Services

This section summarizes the functionality of each ObjectStore database service.

Persistence
ObjectStore provides direct, transparent access to persistent data from within C++ programs. No explicit database reads or writes are required, and persistence is entirely orthogonal to type. This means that the same type can have both persistent and nonpersistent instances, and the same function can take both persistent and nonpersistent arguments. Moreover, the instances of any built-in C++ type can be designated as persistent.

Persistent allocation is performed with an overloading of the C++ new operator. This variant of new allows for the specification of clustering information, so that objects that should exhibit locality of reference can be clustered into the same database segment or object cluster. Segments are variable-size portions of database storage that can be used as the unit of transfer to and from the database. Object clusters are fixed-size portions of database storage that live within segments.

ObjectStore supplies a class that provides the ability to name an object to serve as a database entry point. This class also provides a function allowing the entry point object to be looked up by its name, so that it can serve as a starting point for navigational or query access. Navigational access is performed by following pointers contained in data structure fields, just as would be done in a regular, nondatabase C or C++ program. Pointer dereferencing causes transparent database retrievals when needed. Query access is described below.

A single ObjectStore application can open several databases at a time. In addition, several applications can access the same database concurrently, as described in the section on Transactions and Concurrency Control, below.

Query processing
Many application types require two forms of data access: navigational access and associative access. Navigation accesses data by following pointers contained in data structure fields. In C++, the data member access syntax supports navigational data access. Associative access, on the other hand, is the lookup of those data structures whose field values satisfy a certain condition (for example, lookup of an object by name or ID number). ObjectStore supports associative access, or query, through member functions in the ObjectStore Class Library.

Queries involve collections, which are objects such as sets, bags, or lists, that serve to group together other objects. ObjectStore provides a library of collection classes. These classes provide the data structures for representing such collections, encapsulated by member functions that support various forms of collection manipulation, such as element insertion and removal. Retrieval of a given collection's elements for examination or processing one at a time is supported through the use of a cursor class.

Queries return a collection containing those elements of a given collection that satisfy a specified condition. They can be executed with an optimized search strategy, formulated by the ObjectStore query optimizer. The query optimizer maintains indexes into collections based on user-specified keys, that is, data members, or data members of data members, and so on. By using these indexes, implemented as B-trees or hash tables, the number of objects examined in response to a query can be minimized. Formulation of optimization strategies is performed automatically by the system. Index maintenance can also be automatic - the programmer need only specify the desired index keys.

See ObjectStore Collections C++ API Reference for more information on collections, queries, and indexes.

Integrity control
Many design applications create and manipulate large amounts of complex persistent data. Frequently, this data is jointly accessed by a set of cooperative applications, each of which carries the data through some well-defined transformation. Because the data is shared, and because it is more permanent and more valuable than any particular run of an application, maintaining the data's integrity becomes a major concern and requires special database support.

In addition to the integrity control provided by compile-time type checking, ObjectStore provides facilities to help deal with some of the most common integrity maintenance problems.

One integrity control problem concerns pairs of data members that are used to model binary relationships. A binary relationship, such as the part/subpart relationship, for example, can be modeled by a pair of data members, parent_part and child_part. Modeling the relationships with both these data members has the advantage of allowing navigation both up and down the parts hierarchy. However, the data members must be kept in a consistent state with respect to one another: one object is the parent of another if and only if the other is a child of the first. This integrity constraint can be enforced by declaring the two data members as inverses of one another. ObjectStore automatically implements the constraint as an update dependency.

Another integrity control problem concerns illegal pointers. ObjectStore can dynamically detect pointers from persistent to transient memory, as well as cross-database pointers from segments specified by the user to disallow such pointers. ObjectStore's schema evolution facility can also detect pointers to deleted objects and incorrectly typed pointers.

Access control
ObjectStore provides two general approaches to database access control. With one approach, you can set read and write permissions for various categories of users, at various granularities. With the other approach, you can require that applications supply a key in order to access a particular database. ObjectStore also supports Server authentication services.

Concurrency control
The concurrency control scheme employed by ObjectStore is based on transactions with two-phase locking. Locking is automatic and completely transparent to the user. The act of reading (or writing) an object causes a read (write) lock to be acquired for the object, so there is no need to insert any special locking commands into the application code. Locking information is cached on both client and Server, to minimize the need for network communication when the same process performs consecutive transactions on the same data.

ObjectStore also supports multiversion concurrency control, which allows nonblocking database reads. This form of concurrency control is implemented using a technique of delaying propagation of data from the Server log.

Fault tolerance
ObjectStore's fault tolerance is based on transactions and logging. Fault tolerance endows transactions with a number of important properties. Either all of a transaction's changes to persistent memory are made successfully, or none are made at all. If a failure occurs in the middle of a transaction, none of its database updates is made. In addition, a transaction is not considered to have completed successfully until all its changes are recorded safely on stable storage. Once a transaction commits, failures such as server crashes or network failures cannot erase the transaction's changes.

Dynamic schema access
ObjectStore's metaobject protocol supports access to ObjectStore schema information, stored in the form of objects that represent C++ types. These objects are actually instances of ObjectStore metatypes, so called because they are types whose instances represent types. Schema information is also represented with the help of various auxiliary classes that are not in the metatype hierarchy, such as ones whose instances represent data members and member functions. The metaobject protocol supports run-time read access to ObjectStore schemas, as well as dynamic type creation and schema modification.

Schema evolution
The term schema evolution refers to the changes undergone by a database's schema during the course of the database's existence. It refers especially to schema changes that potentially require changing the representation of objects already stored in the database.

Without the schema evolution facility, a database schema can be changed only by adding new classes to it. Redefinition of a class already contained in the schema, except in ways that do not affect the layout the class defines for its instances, is not allowed. (Adding a nonstatic data member, for example, changes instance layout, but adding a nonvirtual member function does not.)

The schema evolution facility, however, allows arbitrary redefinition of the classes in a database's schema - even if instances of the redefined classes already exist. Invoking schema evolution directs ObjectStore to modify a database's schema, and change the representation of any existing instances in the database to conform to the new class definitions. If desired, these representation changes can be directed by user-supplied routines.

Data compaction
ObjectStore databases consist of segments containing persistent data. As persistent objects are allocated and deallocated in a segment, internal fragmentation in the segment can increase because of the presence of holes produced by deallocation. Of course, the ObjectStore allocation algorithms recycle deleted storage when objects are allocated, but there might nevertheless be a need to compact persistent data by squeezing out the deleted space. Such compaction frees persistent storage space so that it can be used by other segments.



[previous] [next]

Copyright © 1997 Object Design, Inc. All rights reserved.

Updated: 03/31/98 17:25:04