DECLARE_EXCEPTION(name);name is the name of a user-defined TIX exception you want to declare. It must be defined in the same application, using the DEFINE_EXCEPTION() macro. A user-defined TIX exception is a variable of the class objectstore_exception and is part of the TIX exception-handling facility.
The DECLARE_EXCEPTION() macro makes a TIX variable available to files other than the one in which it is defined. For example, by specifying the DECLARE_EXCEPTION() macro in a header file, you make the declared variable accessible to any file that includes the header file.
DECLARE_EXCEPTION(bad_char_input)
DEFINE_EXCEPTION(name, "message", pointer-to-parent);name is the identifier for the exception you want to create.
message is the error message to display when the exception is signaled. As shown in the syntax statement, this argument must be enclosed in quotation marks.
pointer-to-parent is the address of a parent exception, which thus becomes the new exception's parent. For information about parent exceptions, see Parent Exceptions. Supply 0 for this argument if you do not want your exception to have a parent.
Note
The DEFINE_EXCEPTION() macro must end in a semicolon (;). Example
The following program shows how to use the DEFINE_EXCEPTION() macro. The program defines three exceptions, err_too_few_args, err_too_many_args, and err_bad_arg. These are used to perform error-checking on command-line arguments. The first one, err_too_few_args, is handled by a TIX exception handler; the other two are not handled. All three exceptions are signaled by calls to the method signal(); see objectstore_exception::signal().
// def_exc.cc: Illustrates how to use the DEFINE_EXCEPTION
// macro to define your own TIX exceptions. This program defines
// TIX exceptions to handle command-line argument errors. The
// program signals err_too_few_args if there are no arguments
// present, err_too_many_args if there are more than one,
// and err_bad_arg if the word "bad" is used as an argument.
// Only err_too_few_args is handled.
#include <ostore/ostore.hh>
#include <string.h>
#include <fstream.h>
DEFINE_EXCEPTION(err_too_few_args, "Too few arguments", 0);
DEFINE_EXCEPTION(err_too_many_args, "Too many arguments",
0);
DEFINE_EXCEPTION(err_bad_arg, "Illegal argument: ", 0);
void validate_args(int argc, char **argv);
main(int argc, char **argv)
{
OS_ESTABLISH_FAULT_HANDLER {
objectstore::initialize();
TIX_HANDLE (err_too_few_args) {
validate_args(argc, argv);
} TIX_EXCEPTION {
tix_exception *exception = tix_handler::get_exception();
if (exception == &err_too_few_args)
cout << "Missing command-line arguments.\n";
else
cout << "Unknown exception occurred.\n";
} TIX_END_HANDLE
} OS_END_FAULT_HANDLER
}
void validate_args(int argc, char **argv)
{
if (argc == 1) // no arguments
// No message is specified because the default message
// specified in the DEFINE_EXCEPTION macro is sufficient.
err_too_few_args.signal("");
else if (argc > 2) // more than one argument
// No message is specified, so only the default message
// specified with the DEFINE_EXCEPTION macro will
// be displayed.
err_too_many_args.signal("");
else if (argc == 2 && !strcmp(argv[1], "bad"))
// This call to signal includes a message,
// which will therefore be displayed along with the
// default message specified with the DEFINE_EXCEPTION
// macro.
err_bad_arg.signal(argv[1]);
}
Following is the output from a sample run:
$def_excMissing command-line arguments.$def_exc arg$def_exc arg argToo many arguments(err_too_many_args)$def_exc badIllegal argument:bad (err_bad_arg)
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.
Syntax
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)
There must be no spaces anywhere in the argument lists to OS_BEGIN_TXN and OS_BEGIN_TXN_NAMED. Also, the enclosing braces are not required, but some source code editors complain if you do not use them.
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 nonzero value, the transaction aborted; that is, any changes to persistent state within the transaction were undone. The identity of the exception gives the reason for the abort.
In the event of an abort that causes the transaction to abort, you can examine expression only if one of the following is true:
txn-type is one of the following enumerators:
txn-name is the name you want to give to the transaction. See os_transaction::get_name().
Nesting
Transactions can be nested. For example, you can nest an update transaction inside a read-only transaction if you want to write temporarily to persistent memory, as in the following:
OS_BEGIN_TXN(txn1, 0, os_transaction::read_only) {
OS_BEGIN_TXN(txn2, 0, os_transaction::update) {
// process database
os_transaction::abort(); // Roll back the transaction
} OS_END_TXN(txn2)
} OS_END_TXN(txn1)
The program creates a database (stanza.db) and uses a lexical transaction to write an array of strings to the database. After the lexical transaction commits, the program starts a dynamic transaction and reads the strings from the database, displaying them on standard output.
// txn_example.cc: illustrates lexical and dynamic transactions
// The program writes an array of strings to a database in a
// lexical transaction (using the macros), and reads the array
// in a dynamic transaction (using the os_transaction methods).
#include <ostore/ostore.hh>
#include <string.h>
#include <fstream.h>
#define SIZE 5
main( )
{
os_database* db;
os_database_root* root;
os_transaction* txn;
char *verse[] = {
"Matter, as wise logicians say,",
" Cannot without a form subsist;",
"And form, say I as well as they,",
" Must fail if matter brings no grist.",
""
};
OS_ESTABLISH_FAULT_HANDLER {
objectstore::initialize();
// create the database "stanza.db"; if it already exists,
// overwrite it
db = os_database::create("stanza.db", 0644, 1);
// start a lexical transaction in update mode
OS_BEGIN_TXN(t1, 0, os_transaction::update) {
// allocate persistent storage for an array of pointers to
// chars
char **s = (char**)new(db,
os_typespec::get_pointer(), SIZE) void**[SIZE];
// create a root ...
root = db->create_root("root");
// ... and associate it with the first element of the array,
// making it the entry point
root->set_value(s, os_typespec::get_pointer());
for (int i = 0; i < SIZE; i++) {
int len = strlen(verse[i])+1;
// allocate persistent storage for the string, clustering
// it with the previously allocated array
s[i] = new(os_cluster::with(s),
os_typespec::get_char(), len) char[len];
// copy the string in verse[i] to the allocated storage
strcpy(s[i], verse[i]);
}
} OS_END_TXN(t1)
db->close(); // close database
db->open(0); // re-open database for read-only
// start a dynamic transaction in read-only mode
txn = os_transaction::begin(os_transaction::read_only);
root = db->find_root("root"); // find the database root
// get the entry-point (the first element of an array of
// pointers to chars) associated with the root
char** s =
(char**)(root->get_value(os_typespec::get_pointer()));
// print the strings
for (; **s; s++)
cout << *s << endl;
txn->commit(); // commit transaction
db->close(); // close database
// clean up
delete db;
delete root;
delete txn;
} OS_END_FAULT_HANDLER
return 0;
}
Following is the output from a sample run:
$txn_exampleMatter, as wise logicians say,Cannot without a form subsist;And form, say I as well as they,Must fail if matter brings no grist.
OS_BEGIN_TXN_NAMED()
Like the OS_BEGIN_TXN() macro, this macro begins a lexical transaction and establishes a new scope. Unlike the other macro, this one allows you to specify a transaction name. For more information
See OS_BEGIN_TXN() for a full description of the transaction macros.
OS_END_FAULT_HANDLER
Used with the OS_ESTABLISH_FAULT_HANDLER macro to delimit a fault-handler block. For more information
See OS_ESTABLISH_FAULT_HANDLER for information on the fault-handler macros.
OS_END_TXN()
Marks the end of a lexical transaction established by the OS_BEGIN_TXN() or OS_BEGIN_TXN_NAMED() macro. For more information
See OS_BEGIN_TXN() for a full description of the lexical transaction macros.
OS_ESTABLISH_FAULT_HANDLER
The OS_ESTABLISH_FAULT_HANDLER and OS_END_FAULT_HANDLER macros are used to handle page faults. ObjectStore uses page faulting to detect references to persistent memory. All applications performing ObjectStore operations must use these macros to establish a page-fault handler at the top of every stack in the program. Essentially, this requirement means that you must enclose the code in the top-level function (main() or WinMain()) within these macros. If the program uses multiple threads, the first function of each new thread that uses ObjectStore must also include these macros. Syntax
int main (int argc, char** argv)
{
OS_ESTABLISH_FAULT_HANDLER {
// your code
} OS_END_FAULT_HANDLER
return value;
}
The enclosing braces are not required but some source code editors complain if you do not use them.
OS_MARK_SCHEMA_TYPE()
This macro is used in schema source files to include a class in an application's schema. Syntax
OS_MARK_SCHEMA_TYPE(class)class is the class to be included in the application's schema. Typedef names are not allowed. To include a template class that has more than one argument, use the OS_MARK_SCHEMA_TYPESPEC() macro.
Calls to the macro should appear outside any function at global or file scope level.
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.
However, if you specify the -make_reachable_source_classes_persistent option to the ossg schema generator, you need not mark every class that might be read from a database. This option causes every class that is defined in the schema source file and reachable from a persistently marked class to be persistently allocatable and accessible. The -make_reachable_source_classes_persistent option is useful to ensure that items that could be overlooked, for example, subtypes, are marked. However, it can also make classes persistent that do not need to be so for compilation to succeed.
OS_MARK_SCHEMA_TYPESPEC((type-name<param-list>))type-name is the name of a class template, and param-list is a comma-separated list of parameters.
You can use this macro to parameterize types with multiple parameters. Note that you must enclose type-name and param-list within a set of parentheses. If the template has one or no parameters, you can use the OS_MARK_SCHEMA_TYPE() macro.
Calls to the macro should appear outside any function at global or file scope level.
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 also must mark every class that appears in a library interface query string or index path in the application.
However, if you specify the -make_reachable_source_classes_persistent option to the ossg schema generator, you need not mark every class that might be read from a database. This option causes every class that is defined in the schema source file and reachable from a persistently marked class to be persistently allocatable and accessible. The -make_reachable_source_classes_persistent option is useful to ensure that items that could be overlooked, for example, subtypes, are marked. However, it can also make classes persistent that need be for compilation to succeed.
OS_REFERENCE_NOCLASS(type)If you use a reference type whose referent type is not a class, you must call this macro, passing the referent type. Calling this macro provides a definition for the template instantiation. For example, the following defines the class os_Reference<float>:
OS_REFERENCE_NOCLASS(float);Implicit instantiation of the template defines operator ->(), which is invalid for nonclass parameters. Calling the macro defines an instantiation that does not provide operator ->().
For references whose referent type is not a class, you resolve the pointer by calling resolve() or by relying on the conversion operator.
OS_REFERENCE_PROTECTED_NOCLASS()
OS_REFERENCE_PROTECTED_NOCLASS(type)If you use a protected reference type whose referent type is not a class, you must call this macro, passing the referent type. Calling this macro provides a definition for the template instantiation. For example, the following defines the class os_Reference_protected<float>:
OS_REFERENCE_PROTECTED_NOCLASS(float);Implicit instantiation of the template defines operator ->(), which is invalid for nonclass parameters. Calling the macro defines an instantiation that does not provide operator ->().
For references whose referent type is not a class, you resolve the pointer by calling resolve() or by relying on the conversion operator.
OS_REPORT_DLL_LOAD_AND_UNLOAD()
This macro is used in schema source files when generating component schemas. It enables or disables automatic reporting of DLL loading and unloading. Syntax
OS_REPORT_DLL_LOAD_AND_UNLOAD(boolean)When boolean is true, automatic reporting of DLL loading and unloading is enabled. This is accomplished by having ossg generate code that calls os_DLL_schema_info::DLL_loaded() and os_DLL_schema_info::DLL_unloaded() from the DLL's initialization and termination functions. By default, automatic reporting is enabled.
If 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.
OS_SCHEMA_DLL_ID(string)This macro can be used multiple times, for example, to specify different platform-specific DLL identifiers. 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(name)This macro generates the 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.
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.
#define os_soft_pointer os_soft_pointer64 #define os_soft_pointer os_soft_pointer32
OS_SOFT_POINTER32_NOCLASS()
If you use a 32-bit soft pointer type (see os_soft_pointer32<T>) whose referent type is not a class, you must call this macro, passing the referent type.
OS_SOFT_POINTER32_NOCLASS(type)type is the referent type. This provides a definition for the template instantiation. For example, the following defines the class os_soft_ptr32<float>:
OS_SOFT_POINTER32_NOCLASS(float);Implicit instantiation of the template defines operator ->(), which is invalid for nonclass parameters. Calling the macro defines an instantiation that does not provide operator ->().
For soft pointers whose referent type is not a class, you resolve the pointer by calling resolve() or by relying on the conversion operator.
The ObjectStore API explicitly provides (using OS_SOFT_POINTER32_NOCLASS()) the following instantiations of os_soft_pointer32<T>:
OS_SOFT_POINTER64_NOCLASS(type)type is the referent type. This provides a definition for the template instantiation. For example, the following defines the class os_soft_ptr64<float>:
OS_SOFT_POINTER64_NOCLASS(float);Implicit instantiation of the template defines operator ->(), which is invalid for nonclass parameters. Calling the macro defines an instantiation that does not provide operator ->().
For soft pointers whose referent type is not a class, you resolve the pointer by calling resolve() or by relying on the conversion operator.
The ObjectStore API explicitly provides (using OS_SOFT_POINTER64_NOCLASS()) the following instantiations of os_soft_pointer64<T>:
TIX_EXCEPTION
This macro is used in a block of code delimited by the macros TIX_HANDLE and TIX_END_HANDLE to mark the beginning of the statement block to which control is transferred in the event of a specified exception. For more information
See TIX_HANDLE() for information about the TIX exception handler macros.
TIX_HANDLE()
This macro is used in conjunction with the macros TIX_EXCEPTION and TIX_END_HANDLE to specify a handler for an exception signaled by a given code block. Syntax
TIX_HANDLE(exception) {
exception-block
} TIX_EXCEPTION {
handle-exception-block
} TIX_END_HANDLE
exception-block and handle-exception-block can consist of any number of statements and are considered to be within their own block. The enclosing braces are not required but many source code editors can complain if you do not use them. exception can be one of the following:
If exception is signaled but there is no handle-exception-block, program control passes to the statement immediately following TIX_END_HANDLE. In this situation, you might want to handle the exception outside the TIX exception handler.
If exception is not signaled in exception-block, control flows from the end of exception-block to the statement immediately following TIX_END_HANDLE.
In place of the TIX_HANDLE() macro, you can substitute the TIX_HANDLE_IF() macro, which allows for conditional processing. See TIX_HANDLE_IF().
Nesting
These constructs can be nested, allowing handling of multiple exceptions. For example:
TIX_HANDLE(exception1) {
TIX_HANDLE(exception2) {
exception-block
} TIX_EXCEPTION {
handle-exception1-block
} TIX_END_HANDLE
} TIX_EXCEPTION {
handle-exception2-block
} TIX_END_HANDLE
Nested handlers are especially useful when the outer handler specifies a parent exception in exception1 and the inner handlers each specify a child of the parent in exception2. However, some care should be taken in constructing a nested handler to ensure that the parent is in the outer handler and the children are in the inner handlers. If they are reversed, the parent might never get control.
// tix_example.cpp: illustrates a very simple TIX exception handler.
// The program tries to open a database named on the command-line.
// If the open fails because the database doesn't exist
// (err_database_not_found), the exception handler creates a
// database of that name.
#include <ostore/ostore.hh>
#include <iostream.h>
main(int argc, char** argv)
{
OS_ESTABLISH_FAULT_HANDLER {
if (argc != 2) { // check for name of database
cout << "Usage: " << argv[0] << " <database>" << endl;
return 1;
}
objectstore::initialize();
os_database *db;
TIX_HANDLE(err_database_not_found) {
db = os_database::open(argv[1]); // try to open database
} TIX_EXCEPTION { // an exception was signaled
cout << "Can't open " << argv[1];
cout << ", will create it." << endl;
db = os_database::create(argv[1]);
} TIX_END_HANDLE
cout << "Opened " << db->get_pathname() << endl;
db->close(); // close database
} OS_END_FAULT_HANDLER
return 0;
}
Following is the output from running the program with different command-line arguments:
$tix_example # no command-line argumentsUsage: tix_example <database>$tix_example nonsense # one argument, but database doesn't existCan't open nonsense, will create it.Opened /h/handcuff/2/tmp/examples/nonsense$tix_example nonsense # argument to an existing databaseOpened /h/handcuff/2/tmp/examples/nonsense
TIX_HANDLE_IF()
The TIX_HANDLE_IF() macro is just like the TIX_HANDLE() macro except that it allows for conditional processing of the exception. Syntax
TIX_HANDLE_IF(flag, exception) {
exception-block
} TIX_EXCEPTION {
handle-exception-block
} TIX_END_HANDLE
The enclosing braces are not required but some source code editors complain if you do not use them.flag is a conditional expression, as used in an if statement. If it evaluates to true (nonzero), the handler is established around exception-block; otherwise, no handler is established.
exception identifies the exception, just as it does in the TIX_HANDLE macro.
Updated: 03/15/99 16:44:26