C++ Interface Release Notes

Chapter 1

New Features

ObjectStore is an object-oriented database management system suited for rapid application development and deployment in multitiered environments. It combines the data query and management capabilities of a traditional database with the flexibility and power of C++ and Java interfaces on all platforms. ObjectStore for Windows also provides support for the ActiveX interface.

This chapter describes

For detailed information about other changes to ObjectStore Release 6.0, see Chapter 2, Changed Features and Chapter 3, Changes to the API. For information about migrating an existin ObjectStore application or database to Release 6.0, see Chapter 4, Migrating to Release 6.0.

ObjectStore Sessions Facility

Release 6.0 introduces the ObjectStore sessions facility. This facility allows an ObjectStore client to run concurrent threads in separate, independent transactions. If you use the sessions facility for a multithreaded application:

ObjectStore's support for sessions means that different threads can use different styles of transaction management. For example, one thread in an application server can service read-only requests with a database opened for MVCC, while another thread services update requests with the same database opened for update.

ObjectStore fully supports sessions in ObjectStore/Single applications in order to provide a mechanism to build sessions-based application servers that are fully contained within a single executable or shared library.

Note
If your application does not require you to use sessions, you do not need to know anything about the sessions facility.

For detailed information about the sessions facility, see ObjectStore C++ Sessions Facility.

Clusters

Previous to Release 6.0, an ObjectStore database was organized into segments. A segment was the basic logical and physical unit exposed to the user. Users organized or clustered data into segments.

In Release 6.0, a database is still composed of segments, but rather than functioning as the basic unit of allocation, the segment is just a group of one or more clusters. The cluster is now the basic physical unit of allocation in a database. You cannot set a comment or access controls on a cluster.

Taking advantage of clusters with this release

Use clusters to keep data together by allocating it in the same cluster. Use segments when you want that data to share similar behaviors in regards to fetching, locking, and so on.

If you previously used the class os_object_cluster to perform clustering, you must remove this class from your application; it is no longer supported. Instead, you can use either os_cluster or os_segment; see os_cluster and os_segment. The os_segment class is also described in the ObjectStore C++ API Reference.

Clusters and Allocation Size

There are two types of clusters: normal and huge. These correspond to the way ObjectStore allocates storage, in units of 64K. A normal allocation (less than 64K) is assigned to a normal cluster, which can contain any number of normal allocations up to a maximum size of 2G. For huge allocations (greater than 64K), ObjectStore creates a huge cluster containing that one allocation and no more.

When allocating an array, ObjectStore determines whether to use a normal or allocate a huge cluster according to the total size of the array, not the size of the individual object.

Cluster API

The following classes have been added to the API in support of clusters:

In addition, the following classes have been changed to support clusters:

Soft Pointers

In previous releases, ObjectStore applications could use either native C++ pointers for referencing other objects or one of the os_Reference family of references. Native pointers provided high performance in structure traversal, while os_Reference references were larger and slower, but allowed address space to be conserved by not reserving memory for segments until actually needed. The choice had to be made when designing the application and could not easily be changed later, after the database was created.

Release 6.0 introduces the soft pointer to ObjectStore. The soft pointer provides the same address space conservation as os_Reference references while reducing their size to that of a native pointer. Soft pointers also provide fast dereferencing and allow user applications to choose whether to use native pointer and soft pointer format when operating against a particular database.

Soft Pointer Template Classes

The soft pointer template classes are os_soft_pointer32 and os_soft_pointer64. These are 32 and 64 bits in size, respectively. Their APIs are modeled on the os_Reference API. For convenience, ObjectStore defines the C++ macro os_soft_pointer to be os_soft_pointer32 on 32-bit platforms and os_soft_pointer64 on 64-bit platforms. Instances of these soft pointer classes are stored in the database in the same way as native C++ pointers of the same size.

Resolved and Unresolved Soft Pointers

When a soft pointer is in memory, it is either resolved or unresolved. When resolved, it contains a C++ pointer to the target, allowing subsequent calls to the soft pointer method resolve() to operate very quickly. When unresolved, the soft pointer contains a pointer to a location within a reserved range of memory, allowing it to be quickly identified as unresolved.

Hard and Soft Pointers

Because native C++ pointers - referred to as hard pointers - and soft pointers have exactly the same database representation, an application can choose at run time whether the in-memory representation will be hard or soft. The application indicates its choice of pointer representation through its program schema. When generating an application schema or DLL schema, if os_soft_pointer32, os_soft_pointer64, or os_soft_pointer is used in a persistent class, that pointer will be soft. If a C++ native pointer is used, the pointer will be hard.

Because the choice of pointer hardness is made at the data-member level, the use of soft pointers is only meaningful as the type of a data member in a persistent class. An application cannot directly allocate persistent soft pointer instances and cannot use them as the base type of a class in a persistent schema.

The hardness of a pointer in the program schema used by an application that creates a database does not constrain the choice of hardness for other applications that later access that database. Each application that accesses the database can choose the hardness of that pointer at run time. Multiple processes can concurrently access a database, each selecting its preferred pointer hardness without regard to the hardness specified by the other processes.

Restriction

All component schemas used by the application must agree on the hardness of a particular pointer. In this beta release, the choice of hardness for a pointer is determined by the first component schema loaded that includes the class containing the pointer. No check is currently made that all component schemas are in agreement. In a future beta release, ObjectStore will check whether the component schemas are in agreement and will choose the hard pointer representation if any component schema identifies a pointer as hard.

Soft Pointer API

The os_soft_pointer template classes provides the following methods:

Constructors
Construct a soft pointer initialized to a null pointer.

os_soft_pointer(); 
Construct a soft pointer initialized with the specified hard or soft pointer value.

os_soft_pointer(T* p); 
os_soft_pointer(const os_soft_pointer&  r); 
Assignment operators
Assign a value to the soft pointer.

operator =(T* p); 
operator =(const os_soft_pointer<T>&  r); 
Resolution methods
Resolve the soft pointer to a C++ hard pointer value. The resolved value is cached if possible.

operator T*() const; 
T* resolve() const; 
T* operator->() const; 
Comparison operators
Perform relational operations on soft pointers.
os_boolean operator !() const; 
os_boolean operator ==(void const*) const; 
os_boolean operator ==(os_soft_pointer32_base const&) const; 
os_boolean operator !=(void const* other) const; 
os_boolean operator !=(os_soft_pointer32_base const& other) const; 
os_boolean operator <(void const*) const; 
os_boolean operator <(os_soft_pointer32_base const&) const; 
os_boolean operator >(void const*) const; 
os_boolean operator >(os_soft_pointer32_base const&) const; 
os_boolean operator <=(void const* other) const; 
os_boolean operator <=(os_soft_pointer32_base const& other) const; 
os_boolean operator >=(void const* other) const; 
os_boolean operator >=(os_soft_pointer32_base const& other) const; 

Note
os_soft_pointer32_base is the base class of all 32-bit soft pointer classes, allowing soft pointer types with differing instantiation parameters to be compared without requiring a resolve operation.

OS_SOFT_POINTER32_NOCLASS Macro

Because the soft pointer template classes define an operator->() method, the template type parameter T must normally be a class, struct, or union type. If you want to use a pointer or primitive type as the template parameter, your source code must include a call to the OS_SOFT_POINTER32_NOCLASS macro, specifying the type as an argument, prior to any use of the soft pointer. The following example shows how to use the macro to replace a C++ int* pointer with a soft pointer:

#include <ostore/ostore.hh>; 
OS_SOFT_POINTER32_NOCLASS(int) 
struct int_pointer { 
      os_soft_pointer<int> pint; 
}; 
The ObjectStore include files provide OS_SOFT_POINTER32_NOCLASS macro calls for void and char types, so user applications need not call the macro.

Export IDs

Release 6.0 introduces Export IDs. Export IDs are unique identifiers for each object in a segment that make databases more efficient to manage. They allow segment-level data reorganizations that do not affect pointers to the data from other segments. To use this capability you must specify a segment reference policy for the segment when it is created and objects which are to be referenced from outside the segment must be explicitly exported.

Export IDs can also be used to implement addressing schemes with referential integrity protection. The os_Reference_protected<> classes use Export IDs in this manner.

Use the following APIs for manipulating Export IDs directly:

For detailed information about the Export ID API, see ObjectStore C++ API Reference. For information about segment reference policy and protected references, see Advanced C++ API User Guide.

Generalized Allocators

ObjectStore's new allocator framework extends the allocator abstraction that was recently introduced to the C++ language; see Stroustrup's The C++ Programming Language, 3rd edition, section 19.4 ("Allocators"). Generalized allocators provide logical storage and allow decisions on clustering to be made at runtime under administrative control instead of application development time.

Applications that take advantage of generalized allocators do not need to be aware of the details of ObjectStore's physical storage model.

Performance Improvements

The follow sections describe improvements to the performance of Release 6.0.

Concurrent Allocation

Previous to Release 6.0, only one client at a time could create new persistent objects in a segment because allocation used and modified persistent metadata that was global to the segment. If another client tried to create a persistent object in the same segment, it would get a lock conflict, forcing it to wait until the first transaction ended.

In Release 6.0, concurrent clients can create new persistent objects concurrently in the same segment, even in the same cluster within a segment. Their allocations are automatically steered to distinct pages. Allocation now requires only write-locks on the page containing the new object; it no longer uses any global persistent metadata, even when the cluster's size is being increased. Transactions operating on other pages in the same cluster now face no lock conflicts with transactions creating new persistent objects.

In Release 6.0, ObjectStore's strategy is to avoid locking anything other than the pages containing the persistent objects being used, Wherever possible, there will be a minimum of concurrency bottlenecks other than those implied by the actions taken by the user program.

Relocation Optimization

The following discussion of the improved relocation optimization for Release 6.0 assumes that you are familiar with how ObjectStore performed relocation optimization in previous releases. The focus of this discussion is more on the technology that makes for better performance rather than how to use relocation optimization.

Previous to Release 6.0, the ObjectStore client would attempt to skip pointer swizzling when possible in order to improve the performance of page faulting. (Pointer swizzling: translating pointers from their external values to their internal values, or vice-versa.) The mechanism - referred to as relocation optimization - consists of two separate parts:

Inbound relocation optimization
With inbound relocation optimization, the first time any page in a segment was used in a transaction, the client would attempt to align the pseudoaddresses representing the external values of pointers with virtual addresses in the persistent storage region (PSR) so that pointer swizzling would not be necessary. The client would only attempt to align the pseudoaddresses if no other translation of the page were necessary (such as byte-swapping and virtual function table pointer setup), since such translations could require almost the full complexity of pointer swizzling.

Outbound relocation optimization
Outbound relocation optimization could occur only if

For outbound relocation optimization, the client avoided pointer swizzling back to external values when a page was committed, by growing the segment's persistent relocation map (PRM) to cover all possible pseudoaddress translations - in effect, the PRM became the union of its previous state with the state of the PSR at commit time.

Relocation optimization
With the introduction of sessions in Release 6.0 and the replacement of per-segment PRMs by per-page PRMs, the relocation optimization mechanism has completely changed.

Sessions
The introduction of sessions has had a significant impact on relocation optimization. ObjectStore's VMMA architecture requires that each session have its own unique PSR, distinct from the PSRs for other sessions in the same process. Because there can be many PSRs in a process, each with a disjoint range of virtual addresses, the likelihood that the external values of pointers could be aligned with the virtual addresses in a PSR is significantly decreased - in effect, only one session per process could possibly benefit from such an alignment for any specific segment.

The mechanism just described relies on being able to perform segment-wide computation just once per transaction, when the first page is used. The benefits occur during the rest of the transaction, when other pages in the segment are used. Because each page has its own independent PRM, no such batched computation is possible.

Pointer swizzling
The new relocation optimization mechanism concentrates on skipping pointer relocation between transactions for pages held in the client's cache across transactions. So, pointer translation is always performed on a page

However, most of the time spent in these operations is related to network and disk I/O and not to the CPU activity of pointer translation.

Performance benefit
The real performance benefit occurs for pages held in the cache. Once a page gets inbound relocation, it is held in the client cache in that state, even across multiple transactions. If the address mappings needed for the page - between database, segment, cluster, and offset on the one hand and virtual addresses in the PSR on the other - can be kept from one transaction to the next (or across calls to any API that releases address space), the page will not have to be relocated when used again.

Recycling address mappings
If the PSR ever becomes completely occupied, the new relocation scheme can selectively recycle address mappings. If a page requires an address mapping that has been recycled, this requirement is detected the next time the page is used, and the page is relocated again. Furthermore, detecting whether or not a page requires relocation is a constant-time operation within the new relocation scheme. It does not require scanning the page's PRM. Also, instead of requiring immediate assignment of all address mappings for a segment, the new relocation scheme accomplishes the optimization while keeping the benefits of deferred assignment.

Reduced relocation cost
In addition to the change when relocation optimization occurs, Release 6.0 of ObjectStore has been optimized to reduce the cost of doing relocation.

Nested Transactions

There is no longer a client-side limit on the size of a nested transaction. In previous releases, modifying a page within a nested transaction where the page was also modified in an outer transaction caused a snapshot to be made. This snapshot was wired into the client cache, and if an excessive number of such pages were modified, the cache would fill up completely, and the client would raise a cache-full exception.

In Release 6.0, snapshot pages are evictable from the cache. This change means that there is no longer a client-side limit on the size of nested transactions. There is still a limit, but it is the same as for nonnested transactions with respect to modified pages: the size of the transaction log.



[previous] [next]

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

Updated: 03/11/99 12:16:49