Programmer's Guide to the Oracle Call Interface
Release 8.0

A54656_01

Library

Product

Contents

Index

Prev Next

11
Object Cache and Object Navigation

This chapter introduces the OCI's facility for working with objects in an Oracle8 Server. It also discusses the OCI's object navigational function calls.

This chapter includes the following sections:

Chapter Overview

This chapter is broken down into several main sections that cover the basic concepts involved in writing OCI applications to manipulate Oracle8 objects. The chapter also covers the OCI navigational function calls.

The following specific sections are included:

Complete descriptions of the OCI navigational functions can be found in Chapter 14, "OCI Navigational Functions".

The Object Cache and Memory Management

The object cache is a client-side memory buffer that provides lookup and memory management support for objects. It stores and tracks object instances that have been fetched by an OCI application.

When objects are fetched by the application through a SQL SELECT, or through an OCI pin operation, a copy of the object is stored in the object cache. Objects that are fetched directly through a SELECT statement are fetched by value, and they are non-referenceable objects which cannot be pinned. Only referenceable objects may be pinned.

If an object is being pinned, and an appropriate version already exists in the cache, it does not need to be fetched from the server.

Every client program that uses the Oracle8 OCI to dereference REFs to retrieve objects utilizes the object cache. A client-side object cache is allocated for every OCI environment handle initialized in object mode. Multiple threads of a process can share the same client-side cache by sharing the same OCI environment handle.

Exactly one copy of each referenceable object exists in the cache per connection. Dereferencing a REF many times or dereferencing several equivalent REFs returns the same copy of the object.

If you modify a copy of an object in the cache, you must flush the changes to the server before they are visible to other processes. Objects that are no longer needed can be unpinned or freed; they can then be swapped out of the cache, freeing the memory space they occupied.

The object cache maintains the association between all object copies in the cache and their corresponding objects in the database.

The cache does not manage the contents of object copies; it does not automatically refresh object copies. The application must ensure the correctness and consistency of the contents of object copies. For example, if the application marks an object copy for insert, update, or delete, then aborts the transaction, the cache simply unmarks the object copy but does not purge or invalidate the copy. The application must pin "recent" or "latest", or refresh the object copy in the next transaction. If it pins "any", it may get the same object copy with its uncommitted changes from the previous aborted transaction.

See Also: For more information about pin options, see "Pinning an Object Copy" on page 11-7.

The object cache is created when the OCI environment is initialized in object mode, using OCIInitialize(). Each application processes running against the same server has its own object cache, as shown in Figure 11-1.

Figure 11-1 The Object Cache

The object cache tracks the objects that are currently in memory, maintains references to the objects, manages automatic object swapping, and tracks object meta-attributes.

Cache Consistency and Coherency

The object cache does not automatically maintain value coherency or consistency between object copies and their corresponding objects in the database. In other words, if an application makes changes to an object copy, the changes are not automatically applied to the corresponding object in the database, and vice versa. The cache provides operations such as flushing a modified object copy to the database and refreshing a stale object copy with the latest value from the database to enable the program to maintain some coherency.

Note: Oracle8 does not support any automatic cache coherency with the server's buffer cache or database. Automatic cache coherency refers to the mechanism by which the object cache refreshes local object copies when their corresponding objects have been modified in the server's buffer cache, and the object cache flushes the changes made to local object copies to the buffer cache before any direct access of the corresponding objects in the server. Direct access includes using SQL, triggers, or stored procedures to read or modify the objects in the server.

Object Cache Parameters

The object cache has two important parameters associated with it, which are attributes of the environment handle:

These parameters refer to levels of cache memory usage, and they help to determine when the cache automatically ages out eligible objects to free up memory.

If the memory occupied by the objects currently in the cache reaches or exceeds the high watermark, the cache automatically begins to free unmarked objects which have a pin count of zero. The cache continues freeing such objects until memory usage in the cache reaches the optimal size, or until it runs out of objects eligible for freeing.

OCI_ATTR_CACHE_MAX_SIZE is specified as a percentage of OCI_ATTR_CACHE_OPT_SIZE. The maximum object cache size (in bytes) is computed by incrementing OCI_ATTR_CACHE_OPT_SIZE by OCI_ATTR_CACHE_MAX_SIZE percentage:

maximum_cache_size = optimal_size + optimal_size * max_size_percentage / 100

or

maximum_cache_size = OCI_ATTR_CACHE_OPT_SIZE + OCI_ATTR_CACHE_OPT_SIZE * 
OCI_ATTR_CACHE_MAX_SIZE / 100

The default value for OCI_ATTR_CACHE_MAX_SIZE is 10%.

The default value for OCI_ATTR_CACHE_OPT_SIZE is 200k bytes.

See the section "Environment Handle Attributes" on page B-13 for more information.

Object Cache Operations

This section describes the most important functions the object cache provides to operate on object copies. All of the OCI's navigational and cache/object management functions are listed in the section "OCI Navigational Functions" on page 11-19.

Pinning and unpinning

Pinning an object copy allows the application to access it in the cache by dereferencing the REF to it.

Unpinning an object indicates to the cache that the object currently is not being used. Objects should be unpinned when they are no longer needed to make them eligible for implicit freeing by the cache, thus freeing up memory.

Freeing

Freeing an object copy removes it from the cache and frees its memory.

Marking and unmarking

Marking an object notifies the cache that an object copy has been updated in the cache and the corresponding object must be updated in the server when the object copy is flushed.

Unmarking an object removes the indication that the object has been updated.

Flushing

Flushing an object writes local changes made to marked object copies in the cache to the corresponding objects in the server. When this happens, the copies in the object cache are unmarked.

Refreshing

Refreshing an object copy in the cache replaces it with the latest value of the corresponding object in the server.

Note: Pointers to top-level object memory are valid after a refresh. Pointers to secondary-level memory (e.g., string text pointers, collections, etc.) may become invalid after a refresh.

Operations for Loading and Removing Object Copies

Pin, unpin, and free functions are discussed in this section.

Pinning an Object Copy

When an application needs to dereference a REF in the object cache, it calls OCIObjectPin(). This call dereferences the REF and pins the object copy in the cache. As long as the object copy is pinned, it is guaranteed to be accessible by the application. Another variation of OCIObjectPin() is OCIObjectPinArray() which takes an array of REFs, dereferences the REFs, and pins the object copies. Both OCIObjectPin() and OCIObjectPinArray() take a pin option, "any", "recent", or "latest".

When the program pins an object, the program also specifies one of two possible values for the pin duration: "session" or "transaction".

When loading an object copy into the cache from the database, the cache effectively executes

SELECT VALUE(t) FROM t WHERE REF(t) = :r

where t is the object table storing the object, and r is the REF, and the fetched value becomes the value of the object copy in the cache.

Since the object cache effectively executes a separate SELECT statement to load each object copy into the cache, in a read-committed transaction, object copies are not guaranteed to be read-consistent with each other.

In a serializable transaction, object copies (pinned "recent" or "latest") are read-consistent with each other because the SELECT statements to load these object copies are executed based on the same database snapshot.

The object cache model is orthogonal to or independent of the Oracle transaction model. The behavior of the object cache does not change based on the transaction model, even though the objects that are retrieved from the server through the object cache can be different when running the same program under different transaction models (e.g., read committed versus serializable).

Unpinning an Object Copy

An object copy can be unpinned when it is no longer used by the program. It then becomes available to be freed. An object copy must be both completely unpinned and unmarked in order to become eligible to be implicitly freed by the cache when the cache begins to run out of memory. To be completely unpinned, an object copy that has been pinned N times must be unpinned N times.

An unpinned but marked object copy is not eligible for implicit freeing until the object copy is flushed or explicitly unmarked by the user. However, the object cache implicitly frees object copies only when it begins to run out of memory, so an unpinned object copy need not necessarily be freed. If it has not been implicitly freed and is pinned again (with the any or recent options), the program gets the same object copy.

An application calls OCIObjectUnpin() or OCIObjectPinCountReset() to unpin an object copy. In addition, a program can call OCICacheUnpin() to completely unpin all object copies in the cache for a specific connection.

Freeing an Object Copy

Freeing an object copy removes it from the object cache and frees up its memory. The cache supports two methods for freeing up memory:

  1. Explicit freeing - A program explicitly frees or removes an object copy from the cache by calling OCIObjectFree() which takes an option to (forcefully) free either a marked or pinned object copy. The program can also call OCICacheFree() to free all object copies in the cache.
  2. Implicit freeing - Should the cache begin to run out of memory, it implicitly frees object copies that are both unpinned and unmarked. Unpinned objects that are marked are eligible for implicitly freeing only when the object copy is flushed or unmarked. For more information, see the section "Object Cache Parameters" on page 11-5.

For memory management reasons, it is important that applications unpin objects when they are no longer needed. This makes these objects available for aging out of the cache, and makes it easier for the cache to free memory when necessary.

The OCI does not provide a function to free unreferenced objects in the client-side cache.

Operations for Making Changes to Object Copies

Functions for marking and unmarking object copies are discussed in this section.

Marking an Object Copy

An object copy can be created, updated, and deleted locally in the cache. If the object copy is created in the cache (by calling OCIObjectNew()), the object copy is marked for insert by the object cache, so that the object will be inserted in the server when the object copy is flushed.

If the object copy is updated in the cache, the user has to notify the object cache by marking the object copy for update (by calling OCIObjectMarkUpdate()). When the object copy is flushed, the corresponding object in the server is updated with the value in the object copy.

If the object copy is deleted, the object copy is marked for delete in the object cache (by calling OCIObjectMarkDelete()). When the object copy is flushed, the corresponding object in the server is deleted. The memory of the marked object copy is not freed until it is flushed and unpinned. When pinning an object marked for delete, the program receives an error, as if the program is dereferencing a dangling reference.

When a user makes multiple changes to an object copy, it is the final results of these changes which are applied to the object in the server when the copy is flushed. For example, if the user updates and deletes an object copy, the object in the server is simply deleted when the object copy is flushed. Similarly, if an attribute of an object copy is updated multiple times, it is the final value of this attribute which is updated in the server when the object copy is flushed.

The program can mark an object copy as updated or deleted only if the object copy has been loaded into the object cache.

Unmarking an Object Copy

A marked object copy can be unmarked in the object cache. By unmarking a marked object copy, the changes that are made to the object copy are not flushed to the server. The object cache does not undo the local changes that are already made to the object copy.

A program calls OCIObjectUnmark() to unmark an object. In addition, a program can call OCICacheUnmark() to unmark all object copies in the cache for a specific connection.

Operations for Synchronizing Object Copies with Server

Cache/server synchronization operations (flushing, refreshing) are discussed in this section.

Flushing Changes to Server

The local changes made to a marked object copy in the cache are written to the server when the object copy is flushed. The program can call OCIObjectFlush() to flush a single object copy or OCICacheFlush() to flush all marked object copies in the cache or a list of selected marked object copies. OCICacheFlush() flushes objects associated with a specific service context.

After flushing an object copy, the object copy is unmarked. (Note that the object is locked in the server after it is flushed; the object copy is therefore marked as locked in the cache.)

Note: The OCICacheFlush() operation incurs only a single server roundtrip even if multiple objects are being flushed.

If an application wishes to flush only dirty objects of a certain type, this functionality is available through the callback function which is an optional argument to the OCICacheFlush() call. The application can define a callback which returns only the desired objects. In this case the operation still incurs only a single server roundtrip for the flush.

Refreshing an Object Copy

When refreshed, an object copy is reloaded with the latest value of the corresponding object in the server. The latest value may contain changes made by other committed transactions and changes made directly (not through the object cache) in the server by the transaction. The program can change objects directly in the server using SQL DML, triggers, or stored procedures.

To refresh a marked object copy, the program must first unmark the object copy. An unpinned object copy is simply freed when it is refreshed (i.e., when the whole cache is refreshed).

The program can call OCIObjectRefresh() to refresh a single object copy or OCICacheRefresh() to refresh all object copies in the cache, all object copies that are loaded in a transaction (i.e., object copies that are pinned recent or pinned latest), or a list of selected object copies.

When an object is flushed to the server, triggers can be fired to modify more objects in the server. The same objects (modified by the triggers) in the object cache become out-of-date, and must be refreshed before they can be locked or flushed.

The various meta-attribute flags and durations of an object are modified as described in Table 11-1 after being refreshed:

Table 11-1 Object Attributes After Refresh
Object Attribute   Status After Refresh  

existent  

set to appropriate value  

pinned  

unchanged  

flushed  

reset  

allocation duration  

unchanged  

pin duration  

unchanged  

During refresh, the object cache loads the new data into the top-level memory of an object copy, thus reusing the top level memory. The top-level memory of an object copy contains the in-line attributes of the object. On the other hand, the memory for the out-of-line attributes of an object copy may be freed and relocated, since the out-of-line attributes can vary in size.

See Also: See the section "Memory Layout of an Instance" on page 11-16 for more information about object memory.

Other Operations

Other pertinent OCI functions are discussed in this section.

Locking Objects For Update

The program can optionally call OCIObjectLock() to lock an object for update. This call instructs the object cache to get a row lock on the object in the database. This is similar to executing

SELECT NULL FROM t WHERE REF(t) = :r FOR UPDATE

where t is the object table storing the object to be locked and r is the REF identifying the object. The object copy is marked locked in the object cache after OCIObjectLock() is called.

To lock a graph or set of objects, several OCIObjectLock() calls are required, one per object, or the array pin OCIObjectArrayPin() call can be used for better performance.

By locking an object, the application is guaranteed that the object in the cache is up-to-date. No other transaction can modify the object while the application has it locked.

At the end of a transaction, all locks are released automatically by the server. The locked indicator in the object copy is reset.

Implementing Optimistic Locking

It is possible to implement optimistic locking in an OCI application if you run your transactions at the serializable level.

The Oracle8 OCI supports calls that allow you to dereference and pin objects in the object cache without locking them, modify them in the cache (again without locking them), and then flush them (the dirtied objects) to the database.

During the flush, if a dirty object has been modified by another committed transaction since the beginning of your transaction, a non-serializable transaction error is returned. If none of the dirty objects has been modified by any other any other transaction since the beginning of your transaction, then the changes are written to the database successfully.

Note: OCITransCommit() first flushes dirty objects into the database before committing a transaction.

The above mechanism effectively implements an optimistic locking model.

Commit and Rollback in Object Applications

When a transaction is committed (OCITransCommit()), all marked objects are flushed to the server. If an object copy is pinned with a transaction duration, the object copy is unpinned.

When a transaction is rolled back, all marked objects are unmarked. If an object copy is pinned with a transaction duration, the object copy is unpinned.

Object Duration

In order to maintain free space in memory, the object cache attempts to reuse objects' memory whenever possible. The object cache reuses an object's memory when the object's lifetime (allocation duration) expires or when the object's pin duration expires. The allocation duration is set when an object is created with OCIObjectNew(), and the pin duration is set when an object is pinned with OCIObjectPin().

Note: The pin duration for an object cannot be longer than the object's allocation duration.

When an object reaches the end of its allocation duration, it is automatically deleted and its memory can be reused. The pin duration indicates when an object's memory can be reused, and memory is reused when the cache is full.

The OCI supports two predefined durations: transaction (OCI_DURATION_TRANS) and session (OCI_DURATION_SESSION). The transaction duration expires when the containing transaction ends (commits or aborts). The session duration expires when the containing session/connection ends.

The application can explicitly unpin an object using OCIObjectUnpin. To minimize explicit unpinning of individual objects, the application can unpin all objects currently pinned in the object cache using the function OCICacheUnpin. By default, all objects are unpinned at the end of the pin duration.

Durations Example

Table 11-2 illustrates the use of the different durations in an application. Four objects are created or pinned in this application over the course of one connection and three transactions. The first column indicates the action performed by the database, and the second column indicates the function which performs the action. The remaining columns indicate the states of the various objects at each point in the application.

Table 11-2 Example of Allocation and Pin Durations
Time   Application Action   Function   Object 1   Object 2   Object 3   Object 4  

T1  

Establish connection  

 

 

 

 

 

T2  

Create object 1 - allocation duration = connection  

OCIObjectNew()  

exists  

T5  

Start Transaction1  

OCITransStart()  

exists  

T6  

SQL - fetch REF to object 2  

 

exists  

T7  

Pin object 2 - pin duration = transaction  

OCIObjectPin()  

exists  

pinned  

T8  

Process application data  

 

exists  

pinned  

T9  

Commit Transaction1  

OCITransCommit()  

exists  

unpinned  

T10  

Start Transaction2  

OCITransStart()  

exists  

 

T11  

Create object 3 - allocation duration = transaction  

OCIObjectNew()  

exists  

exists  

T12  

SQL - fetch REF to object 4  

 

exists  

exists  

T13  

Pin object 4 -
pin duration = connection  

OCIObjectPin()  

exists  

exists  

pinned  

T14  

Commit Transaction2  

OCITransCommit()  

exists  

deleted  

pinned  

T15  

Terminate session1  

OCIDurationEnd()  

exists  

 

pinned  

T16  

Start Transaction3  

OCITransStart()  

exists  

pinned  

T17  

Process application data  

 

exists  

pinned  

T18  

Commit Transaction3  

OCITransCommit()  

exists  

pinned  

T19  

Terminate connection  

 

deleted  

unpinned  

See Also: See the descriptions of OCIObjectNew() and OCIObjectPin() in Chapter 14 for specific information about parameter values which can be passed to these functions.
See the section "Creating, Freeing, and Copying Objects" on page 8-29 for information about freeing up an object's memory before its allocation duration has expired.

Memory Layout of an Instance

An instance in memory is composed of a top-level memory chunk of the instance, a top-level memory of the null indicator structure and optionally, a number of secondary memory chunks. Consider a DEPARTMENT row type,

CREATE TYPE department AS OBJECT
( dep_name      varchar2(20),
    budget        number,
   manager       person,            /* person is an object type */
    employees     person_array );   /* varray of person objects */

and its C representation

struct department
{
OCIString * dep_name;
OCINumber budget;
struct person manager;
OCIArray * employees;
);
typedef struct department department;

Each instance of DEPARTMENT has a top-level memory chunk which contains the top-level attributes such as dep_name, budget, manager and employees. The attributes dep_name and employees are themselves actually pointers to the additional memory (the secondary memory chunks). The secondary memory is used to contain the actual data for the embedded instances (e.g. employees varray and dep_name string).

The top-level memory of the null indicator structure contains the null statuses of the attributes in the top level memory chunk of the instance. From the above example, the top level memory of the null structure contains the null statuses of the attributes dep_name, budget, manager and the atomic nullness of employees.

Object Navigation

This section discusses how OCI applications can navigate through graphs of objects in the object cache.

Simple Object Navigation

In the example in the previous sections, the object retrieved by the application was a simple object, whose attributes were all scalar values. If an application retrieves an object with an attribute which is a REF to another object, the application can use OCI calls to traverse the object graph and access the referenced instance.

As an example, consider the following declaration for a new type in the database:

CREATE TYPE person_t AS OBJECT
(  name          VARCHAR2(30),
  mother          REF person_t,
  father          REF person_t);

An object table of person_t objects is created with the following statement:

CREATE TABLE person_table OF person_t;

Instances of the person_t type can now be stored in the typed table. Each instance of person_t includes references to two other objects, which would also be stored in the table. A NULL reference could represent a parent about whom information is not available.

An object graph is a graphical representation of the REF links between object instances. For example, Figure 11-2 on the following page depicts an object graph of person_t instances, showing the links from one object to another. The circles represent objects, and the arrows represent references to other objects.

Figure 11-2 Object Graph of person_t Instances

In this case, each object has links to two other instances of the same object. This need not always be the case. Objects may have links to other object types. Other types of graphs are also possible. For example, if a set of objects is implemented as a linked list, the object graph could be viewed as a simple chain, where each object references the previous and/or next objects in the linked list.

You can use the methods described earlier in this chapter to retrieve a reference to a person_t instance and then pin that instance. The OCI provides functionality which allows you to traverse the object graph by following a reference from one object to another.

As an example, assume that an application fetches the person1 instance in the above graph and pins it as pers_1. Once that has been done, the application can access the mother instance of person1 and pin it into pers_2 through a second pin operation:

OCIObjectPin(env, err, pers_1->mother, OCI_PIN_ANY, OCI_DURATION_TRANS, 
OCI_LOCK_X, (OCIComplexObject *) 0, &pers_2);

In this case, an OCI fetch operation is not required to retrieve the second instance.

The application could then pin the father instance of person1, or it could operate on the reference links of person2.

Note: Attempting to pin a NULL or dangling REF results in an error on the OCIObjectPin() call.

OCI Navigational Functions

This section provides a brief summary of the available OCI navigational functions. The functions are grouped according to their general functionality. More detailed descriptions of each of these functions can be found in Chapter 14, "OCI Navigational Functions".

The use of these functions is described in the earlier sections of this chapter.

The navigational functions follow a naming scheme which uses different prefixes for different types of functionality:

OCICache*() - these functions are Cache operations
OCIObject*() - these functions are individual Object operations

Pin/Unpin/Free Functions

The following functions are available to pin, unpin, or free objects:

Table 11-3 OCI Object Pin/Unpin/Free Functions
Function   Purpose  

OCIObjectPin()  

Pin an object  

OCIObjectUnpin()  

Unpin an object  

OCIObjectPinCountReset()  

Unpin an object to zero pin count  

OCICacheUnpin()  

Unpin persistent objects in cache or connection  

OCIObjectArrayPin()  

Pin an array of references  

OCIObjectPinTable()  

Pin a table object with a given duration  

OCICacheFree()  

Free all instances in the cache  

OCIObjectFree()  

Free and unpin a standalone instance  

Flush and Refresh Functions

The following functions are available to flush modified objects to the server:

Table 11-4 OCI Object Flush Functions
Function   Purpose  

OCICacheFlush()  

Flush modified persistent objects in cache to server  

OCIObjectFlush()  

Flush a modified persistent object to the server  

OCICacheRefresh()  

Refresh pinned persistent objects in the cache  

OCIObjectRefresh()  

Refresh a single persistent object  

Mark and Unmark Functions

The following functions allow an application to mark or unmark an object by modifying one of its meta-attributes:

Table 11-5 OCI Object Marking Functions
Function   Purpose  

OCIObjectMarkDelByRef()  

Mark an object deleted given a REF  

OCIObjectMarkUpd()  

Mark an object as updated/dirty  

OCIObjectMarkDel()  

Mark an object deleted / delete a value instance  

OCICacheUnmark()  

Unmarks all objects in the cache  

OCIObjectUnmark()  

Marks a given object as updated  

OCIObjectUnmarkByRef()  

Marks an object as updated, given a REF  

Object Meta-Attribute Accessor Functions

The following functions allow an application to access the meta-attributes of an object:

Table 11-6 OCI Object Status Checking Functions
Function   Purpose  

OCIObjectExists()  

Get existence status of an instance  

OCIObjectFlushStatus()  

Get the flush status of an instance  

OCIObjectGetInd()  

Get null structure of an instance  

OCIObjectIsDirtied()  

Has an object been marked as updated?  

OCIObjectIsLocked()  

Is an object locked?  

Other Functions

The following functions provide additional object functionality for OCI applications:

Table 11-7 Other OCI Navigational Functions
Function   Purpose  

OCIObjectCopy()  

Copy one instance to another  

OCIObjectGetObjectRef()  

Return reference to a given object  

OCIObjectGetTypeRef()  

Get a reference to a TDO of an instance  

OCIObjectLock()  

Lock a persistent object  

OCIObjectNew()  

Create a new instance  




Prev

Next
Oracle
Copyright © 1997 Oracle Corporation.

All Rights Reserved.

Library

Product

Contents

Index