ObjectStore C++ API Reference

Chapter 4

System-Supplied Macros

This chapter describes the ObjectStore macros related to transactions and schema. See the ObjectStore Collections C++ API Reference for information on macros related to index maintenance.

Macros

OS_BEGIN_TXN(),
OS_BEGIN_TXN_NAMED(), and
OS_END_TXN()

For applications using only the ObjectStore C++ library interface, transaction macros are supplied. OS_BEGIN_TXN() begins a transaction and establishes a new scope; OS_END_TXN() ends and commits the transaction started by the previous matching OS_BEGIN_TXN() call. OS_END_TXN() also marks the end of the scope established by OS_BEGIN_TXN().

OS_BEGIN_TXN_NAMED() is identical in behavior to OS_BEGIN_TXN() except that it allows you to specify a transaction name. The name must be unique among transactions in the same function. It is used in constructing statement labels.

Synopsis of Transaction Macros

Form of the call
OS_BEGIN_TXN ( txn-tag, expression, txn-type)
...
OS_END_TXN ( txn-tag)
or

OS_BEGIN_TXN_NAMED ( txn-tag, expression, txn-type, txn-name)
...
OS_END_TXN ( txn-tag)
txn-tag is an identifier, a tag for the transaction that is not used for any other transaction in the same function. (The tags are used to construct statement labels, and so have the same scope as labels in C++.) The tag specified in a transaction's BEGIN and END must be the same.

expression is of type tix_exception**, and specifies a location in which ObjectStore stores the transaction's completion status. If the tix_exception** points to 0 when the transaction completes, the transaction committed (that is, its changes were made permanent and visible). If the tix_exception** points to a tix_exception*, the transaction was aborted (that is, its changes to persistent state were undone), and the identity of the exception indicates the nature of the abort.

txn-type is one of

      os_transaction::abort_only 
      os_transaction::read_only 
      os_transaction::update 
os_transaction::abort_only indicates a transaction that can write to persistent data, but cannot be committed. See os_transaction::abort_only in ObjectStore C++ API Reference for further information.

os_transaction::read_only indicates that the transaction performs no updates to persistent storage. If write access to persistent data is attempted, a run-time error is signaled.

os_transaction::update indicates that the transaction performs updates to persistent storage.

txn-name is the name you want to give to the transaction. See os_transaction::get_name().

Caution: The macro arguments are used (among other things) to concatenate unique names. The details of macro preprocessing differ from compiler to compiler, and in some cases it is necessary to enter these macro arguments without white space to ensure that the argument concatenation will work correctly.

Transactions can be nested, but a nested transaction must be of the same type (os_transaction::update or os_transaction::read_only) as its parent, otherwise err_trans_wrong_type is signaled.

Locking

Locking in ObjectStore works as follows. When a persistent data item is read, the page on which it resides is read-locked by ObjectStore. When a data item is written, the page on which it resides is write-locked by the system. When another process attempts write access to an item on a read-locked page, the access is delayed until the outermost transaction (within which the access occurs) completes and the page is unlocked. Read access to a read-locked page is not delayed. When another process attempts read or write access to an item on a write-locked page, the access is delayed until the outermost transaction (in which the access occurs) completes and the page is unlocked.

Note that for purposes of locking, the boundaries of a nested transaction are insignificant. Locks acquired during a nested transaction are not released until the nonnested transaction within which the lock is nested terminates. However, when a nested transaction aborts, its changes to the database are effectively erased, and the state of the database prior to the initiation of the nested transaction is restored.

Transaction Aborts

When a transaction aborts, its changes to the database are undone, and the database is effectively restored to its state as of the moment the transaction began. In addition, if it is not nested, the transaction releases all its locks.

There are two kinds of aborts: user aborts and system aborts.

User aborts
The user can specify that an abort occur at a certain point in the flow of control by invoking the member function os_transaction::abort() or os_transaction::abort_top_level().

System aborts
On rare occasions, the system aborts a transaction either because of a network failure or because it has determined that the transaction is involved in a deadlock. A simple deadlock occurs when one transaction holds a lock on a page that another transaction is waiting to access, while at the same time this other transaction holds a lock on a page that the first transaction is waiting to access. Each process cannot proceed until the other does, with the result that neither process can proceed. Other forms of deadlock are analogous.

When a system abort occurs as a result of a deadlock, the transaction is automatically retried (after undo handling) until it completes successfully or until the maximum number of retries has occurred. This maximum for any transaction in a given process is determined by the value of the private static data member os_transaction::max_retries. Its default value is 10. You can change or retrieve the value of os_transaction::max_retries with os_transaction::set_max_retries() and os_transaction::get_max_retries(). Changing max_retries remains in effect only for the duration of the process, and is invisible to other processes. (Note that this does not apply to dynamic transactions, which are not automatically retried.)

Two-Phase Commit

Two-phase commit is the process by which transactions that use multiple Servers commit in a consistent manner. The majority of transactions, which do not use multiple Servers, are unaffected by two-phase commit.

Transactions that write-access data on multiple Servers commit in two phases: a voting phase and a decision phase. First, all the Servers vote on a transaction, indicating whether they are able to commit it or not. Servers always vote yes unless they have crashed fatally, such as by running out of disk space. If all the votes are yes, the decision is made to commit, and all the Servers are told to commit. (Note that, during normal processing, the Client process is the coordinator of the transaction.)

Problems can still occur at this point, before the transaction completes: a Server might crash in the middle of the commit process - after it has voted, but before it receives a decision. Another possibility is that a Server could crash or be restarted between the vote and decision phases. In both these cases, the Server must communicate with another Server to determine the outcome of the transaction, and the coordination control is passed to one of the Servers.

When a Server is restarted (perhaps after a power failure) after a multi-Server transaction was in the middle of committing when the crash occurred, it prints a message such as the following into the log file, or on standard output:

recovaux.C:1123(-2): This server is a participant in a multi server 
transaction
recovaux.C:1127(-2): (id: 8 global id: 67372226,649525822,20971521)
recovaux.C:1138(-2): The coordinator of the transaction is:
recovaux.C:1143(-2): peachbottom 
recovaux.C:1147(-2): There are 2 blocks involved in the transaction on 
this server.
Server started
This indicates that during the restart process, the Server noticed that a multi-Server transaction was in the process of committing when the host system crashed. The information about transaction IDs can be used to match up outstanding transactions with other Servers that might also be recovering. The message about the coordinator indicates that it will receive the decision from that host (in this case, peachbottom) when that Server recovers.

During peachbottom's restart process, it too notices that a multi-Server transaction was in the commit process when the host crashed, and prints a similar message:

recovaux.C:1120(-2): This server is coordinator for a multi server 
transaction
recovaux.C:1127(-2): (id: 6 global id: 67372226,649525822,20971521)
recovaux.C:1130(-2): The transaction committed.
recovaux.C:1135(-2): The 2 participant servers in the transaction are:
recovaux.C:1143(-2): peachbottom 
recovaux.C:1143(-2): seabrook
recovaux.C:1147(-2): There are 0 blocks involved in the transaction on 
this server.
Server started
(Note that it identifies the participant Servers, including itself.)

peachbottom then proceeds to notify seabrook of the decision for the transaction (committed), at which time seabrook prints the message

recovaux.C:1234(-2): Transaction committed
recovaux.C:1252(-2): (id=8 global id: 67372226,649525822,20971521)
The recovery is now complete for this transaction.

The pages that are involved in this transaction are in limbo during the commit phases as well as during the restart processing. However, during two-phase commit restart processing, it is possible for other requests to the Servers to be processed once they are started up. If one of those requests is for one of the pages that is being recovered as part of a multi-Server transaction that was committing, the client program receives an error indicating that the block is not recovered. This error is defined as

      DEFINE_EXCEPTION(err_svr_blknotrecovered,
            "The block is blocked by an incomplete two phase commit",
            &err_svr);
Once the recovery processing is done for the corresponding two-phase commit, the block becomes free to use again.

OS_ESTABLISH_FAULT_HANDLER and
OS_END_FAULT_HANDLER

ObjectStore must handle all memory access violations, because some are actually references to persistent memory in an ObjectStore database. On UNIX systems, ObjectStore can register a signal handler for such access violations. On Windows NT, there is no function for registering such a handler that will also work when you are debugging an ObjectStore application; the SetUnhandledExceptionFilter function does not work when you are using the Visual C++ debugger.



Therefore, every Windows NT ObjectStore application must put a handler for access violation at the top of every stack in the program. This normally means putting a handler in a program's main or WinMain function and, if the program uses multiple threads, putting a handler in the first function of new threads.

Use ObjectStore Macros to Set Up the Exception Handler

ObjectStore provides two macros to use in establishing a fault handler:

Using these macros, a typical main function in an ObjectStore application would look like

int main (int argc, char** argv) {
OS_ESTABLISH_FAULT_HANDLER
... your code...
OS_END_FAULT_HANDLER
return value;
}
Braces and semicolons are not necessary, as they are part of the macros.



You must use these macros for ObjectStore applications on Windows NT, HP-UX, and Digital UNIX platforms. The reasons vary depending on platform. For example, on Windows NT, every stack in an ObjectStore program must be wrapped with the macros OS_ESTABLISH_FAULT_HANDLER and OS_END_FAULT_HANDLER. This is because Windows NT offers no support for establishing a persistent memory fault handler in any other manner that would also work when you are debugging the application.





On the HP-UX and Digital UNIX platforms, use the OS_ESTABLISH_FAULT_HANDLER and OS_END_FAULT_HANDLER macros at the beginning and end of any thread that performs ObjectStore operations. This is needed because HP-UX and Digital UNIX signal handlers are installed strictly on a per-thread basis and are not inherited across pthread_create calls. See Establishing Fault Handlers in POSIX Thread Environments of ObjectStore Building C++ Interface Applications for additional information.

Note that these macros are only required for threads that use ObjectStore.

OS_MARK_QUERY_FUNCTION()

Applications that use a member function in a query or path string must call this macro.

Form of the call
      OS_MARK_QUERY_FUNCTION( class, func)
class is the name of the class that defines the member function.

func is the name of the member function itself.

The OS_MARK_QUERY_FUNCTION() macro should be invoked along with the OS_MARK_SCHEMA_TYPE() macros for an application's schema, that is, in the schema source file, inside the dummy function containing the calls to OS_MARK_SCHEMA_TYPE(). No white space should appear in the argument list of OS_MARK_QUERY_FUNCTION().

OS_MARK_SCHEMA_TYPE()
OS_MARK_SCHEMA_TYPESPEC()

These macros are used to include a class in an application's schema.

Form of the calls
      OS_MARK_SCHEMA_TYPE( class)
class is the class to be included in the application's schema. Typedef names are not allowed.

      OS_MARK_SCHEMA_TYPESPEC(( type-name< x,y>))
You can use this macro to parameterize types with multiple arguments. Note that you must place the type name and its arguments within a set of parentheses.

Calls to the macro should appear outside any function at global or file scope level.

Required include files
Schema source files must include the file <ostore/manschem.hh> after including <ostore/ostore.hh>, and should contain all the include lines from the application's source necessary to compile.

You must mark every class on which the application might perform persistent new, as well as every class whose instances can be used by the application as database entry points. You must also mark every class that appears in a library interface query string or index path in the application.

If you supply the -make_reachable_source_classes_persistent flag to the schema generator (see ObjectStore Management), you do not actually need to mark every class that might be read from a database. This flag causes every class that is both defined in the schema source file and reachable from a persistently marked class to be persistently allocatable and accessible. It is useful in ensuring that items that could be overlooked, such as subtypes, are marked; however, it can also make classes persistent that do not need to be in order for compilation to succeed.

Component Schema Macros

OS_REPORT_DLL_LOAD_AND_UNLOAD

Default: true
OS_REPORT_DLL_LOAD_AND_UNLOAD( os_boolean)
Reports that a DLL has been loaded or unloaded.

Component Schema source file macro
When os_boolean is true, automatic reporting of DLL loading and unloading is enabled. This is accomplished by ossg generating code that calls os_DLL_schema_info::DLL_loaded() and os_DLL_schema_info::DLL_unloaded() from the DLL's initialization and termination functions.

If os_boolean is false, automatic reporting is not enabled and you must write your own code to call os_DLL_schema_info::DLL_loaded() and os_DLL_schema_info::DLL_unloaded() from the DLL's initialization and termination functions. The default is true.

OS_SCHEMA_DLL_ID

OS_SCHEMA_DLL_ID( string)
Component Schema source file macro
For use in generating component schema, specifies the DLL identifier of the DLL. This macro can be used multiple times, for example, to specify different platform-specific DLL identifiers for different platforms. Do not conditionalize these calls on the platform- you want all the DLL identifiers to be recorded in any database that depends on this DLL.

You must call OS_SCHEMA_DLL_ID at least once in a DLL schema source file to distinguish it from an application schema.

OS_SCHEMA_INFO_NAME

OS_SCHEMA_INFO_NAME( name)
Use with component schema source file
For use with component schema, generates a variable extern os_DLL_schema_info name; that is the os_DLL_schema_info of this DLL. The default is to generate the schema information with a static name. Call this if you are going to call os_DLL_schema_info::DLL_loaded() yourself, so you can get access to the os_DLL_schema_info.

Use with application schema source file
This macro also works in an application schema, in which case the type of the variable is os_application_schema_info instead of os_DLL_schema_info.



[previous] [next]

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

Updated: 03/31/98 17:30:18