You are on page 1of 540

VVEERRSSAAN

NTT DDaattaabbaassee FFuunnddaam
meennttaallss M
Maannuuaall

June 2003

VVEERRSSAAN
NTT DDaattaabbaassee FFuunnddaam
meennttaallss M
Maannuuaall

June 2003

VERSANT Database Fundamentals Manual

This page is intentionally blank.

2

VERSANT Database Fundamentals Manual

Table of Contents
Chapter 1: System Description ..............................................................................................................8

Versant Developer Suite 6.0: An Overview..........................................................................................9
VERSANT Features ........................................................................................................................12
Storage Architecture ......................................................................................................................22
Software Structure .........................................................................................................................24
Language Interfaces .......................................................................................................................25
System Usage Notes.......................................................................................................................28

Chapter 2: Objects.............................................................................................................................34

Object Types.................................................................................................................................35
Object Elements ............................................................................................................................37
Object Characteristics.....................................................................................................................38
Object Status.................................................................................................................................42
Object Relationships.......................................................................................................................44

Chapter 3: Sessions ...........................................................................................................................46

Session Boundaries ........................................................................................................................47
Session Memory Areas ...................................................................................................................48
Session Elements ...........................................................................................................................49
Session Types................................................................................................................................51
Units of Work ................................................................................................................................53
Session Operations ........................................................................................................................54

Chapter 4: Transactions......................................................................................................................55

Short Transactions .........................................................................................................................56
Long Transactions ..........................................................................................................................62

Chapter 5: Locks ...............................................................................................................................66

Short Locks ...................................................................................................................................67

3

VERSANT Database Fundamentals Manual

Persistent Locks .............................................................................................................................85

Chapter 6: General Programming Notes ...............................................................................................95

Name Rules...................................................................................................................................96
Session Firewall .............................................................................................................................99
Database Connection Rule ............................................................................................................ 100
Schema Evolution ........................................................................................................................ 101
Mixing Releases........................................................................................................................... 106
Application Failure ....................................................................................................................... 107
Error Messages that are Incomplete................................................................................................ 108

Chapter 7: Object Movement............................................................................................................ 109

Object Movement Overview ......................................................................................................... 110
Object Migration.......................................................................................................................... 111
Object Checkout.......................................................................................................................... 113
Object Checkin............................................................................................................................ 118

Chapter 8: Object Versioning and Configuration Management .............................................................. 121

Object Versioning ........................................................................................................................ 122
Configuration Management........................................................................................................... 132

Chapter 9: Object Sharing ................................................................................................................ 158

Mixing C and C++ Code and Objects.............................................................................................. 159

Chapter 10: Optimistic Locking ......................................................................................................... 168

Optimistic Locking Overview ......................................................................................................... 169
Optimistic Locking Actions ............................................................................................................ 171
Multiple read inconsistencies......................................................................................................... 178
Optimistic Locking Prototocol ........................................................................................................ 179
Optimistic Locking General Notes .................................................................................................. 184
Examples .................................................................................................................................... 186

Chapter 11: Memory Management .................................................................................................... 195

Overview .................................................................................................................................... 196

4

VERSANT Database Fundamentals Manual

Object Cache .............................................................................................................................. 197
Server Page Cache ....................................................................................................................... 203
Software Modules........................................................................................................................ 204
Multi-Threaded Database Server ................................................................................................... 207
Process Usage Notes .................................................................................................................... 211

Chapter 12: Multiple Processes in a Single Session .............................................................................. 215

Multiple Process Session Concepts ................................................................................................ 216
Multiple Process Session Operations .............................................................................................. 217
Multiple Process Session Usage Notes ............................................................................................ 220

Chapter 13: Multiple Threads............................................................................................................ 227

Thread and Session Alternatives .................................................................................................... 228
Thread and Session Concepts and Terms ........................................................................................ 229
Session Management ................................................................................................................... 232
Thread Management .................................................................................................................... 238
Multiple Threads in the Same Session............................................................................................. 241
Thread Example Programs in C++ .................................................................................................. 245

Chapter 14: Performance Tuning....................................................................................................... 262

Performance Statistics .................................................................................................................. 263
Data Modeling ............................................................................................................................ 266
Memory Management .................................................................................................................. 269
Disk Management........................................................................................................................ 276
Message Management ................................................................................................................. 283
Multiple Applications.................................................................................................................... 285
Application Programming.............................................................................................................. 287

Chapter 15: Statistics Collection ........................................................................................................ 290

Statistics Collection Overview........................................................................................................ 291
Statistics Quick Start..................................................................................................................... 293
Collect Statistics and Store Them in a File ........................................................................................ 299

5

VERSANT Database Fundamentals Manual

Collect Statistics in Memory and View in Real Time .......................................................................... 301
Get Statistics Parameters............................................................................................................... 302
Collect Derived Statistics .............................................................................................................. 303
Statistics Suggestions ................................................................................................................... 304
Statistics Collection Usage Notes ................................................................................................... 307
Statistics Names........................................................................................................................... 309

Chapter 16: Garbage Collection ........................................................................................................ 327

Concepts .................................................................................................................................... 328
Garbage Collection Policy Suggestions ........................................................................................... 329
Garbage Collection Safety............................................................................................................. 330

Chapter 17: Event Notification........................................................................................................... 331

Overview .................................................................................................................................... 332
Event Notification for C and C++ .................................................................................................... 335
Event Notification Performance Statistics......................................................................................... 360
Asynchronous Database Replication............................................................................................... 361

Chapter 18: Roll Forward Archiving ................................................................................................... 365

Roll Forward Concepts ................................................................................................................. 366
Roll Forward Management ............................................................................................................ 367
Roll Forward Usage Rules.............................................................................................................. 369
Roll Forward Procedures ............................................................................................................... 370

Chapter 19: Fault Tolerant Server ...................................................................................................... 372

Concepts .................................................................................................................................... 373
Procedures ................................................................................................................................. 374
Usage......................................................................................................................................... 378

Chapter 20: Controlling Access to Database........................................................................................ 384

Database Users............................................................................................................................ 385
User Authentication ..................................................................................................................... 388
User Privileges............................................................................................................................. 408

6

VERSANT Database Fundamentals Manual

Chapter 21: Internationalization......................................................................................................... 410

Overview .................................................................................................................................... 412
Developing applications using Versant Internationalization ................................................................ 414
Versant Localization ..................................................................................................................... 420
Localizing VERSANT View............................................................................................................. 428

Chapter 22 : Embedding Versant Utilities in Applications ...................................................................... 435

APIs ........................................................................................................................................... 436
SS daemon enhancements ............................................................................................................ 440

Chapter 23: Query Processing........................................................................................................... 441

Search Queries ............................................................................................................................ 444
Search Query Indexes .................................................................................................................. 464
Cursor Queries ............................................................................................................................ 481
VQL Queries ............................................................................................................................... 498
Advanced Queries ....................................................................................................................... 518

Index ............................................................................................................................................. 525

7

VERSANT Database Fundamentals Manual

Chapter 1: System Description
Versant Developer Suite 6.0: An Overview..........................................................................................9
Salient Features of Versant Developer Suite 6.0:...............................................................................9
Scalability & 64-bit support.........................................................................................................9
Query......................................................................................................................................9
Security .................................................................................................................................10
Internationalization (i18N) Support............................................................................................10
Embeddability Enhancements...................................................................................................11
VXML Toolkit .........................................................................................................................11
Integrated Installation ..............................................................................................................11
VERSANT Features ........................................................................................................................12
List of Features...........................................................................................................................12
Scalable Operation .....................................................................................................................15
Distributed Databases.................................................................................................................16
Workgroup Support ...................................................................................................................18
Performance ..............................................................................................................................20
Storage Architecture ......................................................................................................................22
Software Structure .........................................................................................................................24
Language Interfaces .......................................................................................................................25
C/VERSANT Interface.................................................................................................................25
C++/VERSANT Interface.............................................................................................................25
Sharing C++ Objects...................................................................................................................26
J/VERSANT Interface..................................................................................................................26
Standards..................................................................................................................................27
System Usage Notes.......................................................................................................................28

8

This release of Versant ODBMS will support system. Versant ODBMS has established a reputation for exceeding the demands of mission critical enterprise business applications. distributed applications. integrity. Versant introduced the concept of Virtual Attributes that allows you to define derived attributes that are dynamically computed from real class attributes. e-infrastructure software that simplifies the process of building and deploying transactional. These derived attributes or “virtual attributes” can have indices defined on them to improve query performance. The Versant Developer Suite includes the Versant ODBMS.0: An Overview A key part of Versant's application framework is Versant Developer Suite 6. Salient Features of Versant Developer Suite 6. The 32-bit model is specifically for customers with dependencies on other 32-bit products. this is a significant step in the right direction. and productivity. As a standalone database. To this end Versant Developer Suite 6. The main advantage is that all Versant products included in the Versant Developer Suite. Particular focus has been placed on supporting today's generation of 64 bit operating systems. and performance. providing reliability. the C++ and Java language interfaces. work cohesively together.5 ODBMS delivers unsurpassed levels of performance and scalability. In 6. This release focuses on three key areas. whilst the 64-bit release allows massive scaling. scalability. balanced client-server architect and efficient query optimization of 6. The efficient multi-threaded architecture. which with specified criteria will return result(s) in near constant time. From an ease-of-use perspective.0 will natively support both the 64 and 32-bit models. scalability. backup and archive files larger than 2GB. reliability and compatibility with disparate computing platforms and corporate information systems.0. a complete. internal parallelism. Query Extensions to the query capabilities. JDK) versions and adopt the same release schedule. VERSANT Database Fundamentals Manual Versant Developer Suite 6.0: Scalability & 64-bit support Significant enhancements have been made to enable the Versant ODBMS to continue to scale with the demands of our customers. the XML toolkit and Asynchronous Replication framework.5 release. conform to the same compiler (C++. 9 .0. irrespective of number of objects. the Versant ODBMS is designed to meet customers' requirements for high performance. designed to meet the expanding requirements for today's traditional and Internet-based database solutions: internationalization.0.

it is possible to use such encodings for: • Database names • User names & passwords • String attribute values The query enhancements make it possible to build and use indexes and query based on the character encoding and language (locale). The following functionality has been added: • Removed OS user dependency during user authentication (excludes DBA's and DBSA) • Password based authentication for users (exclude DBA's and DBSA) • Provided an option to run SS daemon to run as a user (typically DBA) Internationalization (i18N) Support The Versant ODBMS has been enhanced to support the storage and retrieval of strings that use international character sets and.attribute The ability to define a virtual attribute composed from a number of actual attributes. are stored and manipulated correctly internally. Internationalized Strings The ability to perform queries based on international character sets (see later). For example it would be possible to encode strings as UTF -8 and query these based on the German locale (U and Ü are treated the same). 2.0.attribute predicates. This will help improve query performance for multi. Likewise it would be possible to build an index based on this specific locale to improve performance. Security Enable user authorization independent of operating system while maintaining backward compatibility with existing applications. in conjunction with the query enhancements. 3.VERSANT Database Fundamentals Manual The supported "Virtual Attributes" for the 6. 10 . query them. Versant has certified that 8-bit dean (UTF-8) character encodings. Multi.5 release include: 1. Case Insensitive The ability to perform case insensitive string queries.

VERSANT Database Fundamentals Manual Embeddability Enhancements By introducing a number of new APIs it is now possible to manage a Versant environment completely via API from C. integrated installation offers a single GUI interface to install data-management and connectivity components. This integrated installation eliminates version conflicts when installing and deploying components of the Developer Suite. Via command line tools or Java APIs users can generate XML from defined object graphs and likewise generate objects from XML. VXML Toolkit The Versant XML Toolkit (VXML) adds XML/object mapping support to the Versant Developer Suite product. Integrated Installation A common. C++ or Java. 11 . This functionality is significant for those wishing to embed Versant in their own applications.

• Multiple sessions. • Concurrent access by multiple users. • Polymorphism. • Heterogeneous platforms. • Remote database connections. • Unique identification of objects. • Two-phase commits. including sessions containing no processes. The VERSANT implementation of objects allows: • Custom definition of complex data types. production databases in a distributed. • Inheritance of data and code. • Encapsulation of data and code. 12 . • Navigational and search condition queries. • Unique indexes. • Multiple standard language interfaces. • Recovery from system failures. Database Features — VERSANT database features include: • Persistent storage of data. • You can create a distributed database system containing a combined total of 2^16 databases.VERSANT Database Fundamentals Manual VERSANT Features List of Features Following is a raw list of VERSANT features. • Use of multiple threads by the database server. • Code reuse. • Data versions. • Transaction management. Data as Objects — VERSANT models data as objects. • Use of multiple latches by the database server. • Concurrent access to a session by multiple processes or threads. • User defined security. heterogeneous workgroup environment. General Description — VERSANT is an object database management system that includes all features needed for scalable.

• Transparent event notification. • Object level locking. • Data replication on numerous databases. • Tuning options for applications and databases. • Seamless support for garbage collection. • Support for JDK 1. • Containers and collections of objects. • A client/server model of hardware utilization. including the ability to migrate objects. • Extensible data types. 13 . • Layered database APIs providing transparent and fundamental access to objects. • Object caching on the client and page caching on the server. • Support for multiple compilers. • Parameterized types. • Clustering of instances of a class. • Support for multi-threaded applications. The J/VERSANT interface allows: • Support for elemental data types as well as references. • Checking out of objects to provide local access. multiple process or multiple thread applications. Database System — VERSANT database system features support: • Distribution of data. • Support for the Standard Template Library • Support for Rogue Wave Tools. • Embedding of objects. • On supported platforms and interfaces. • User to specify class of persistence. • Persistence by reachability.2 Collections. • Dynamic management of database schema. • Extensible data types. • Ability to turn locking and logging on and off. VERSANT Database Fundamentals Manual The C++/VERSANT interface allows: • Association of data with links and arrays of links. • Query processing on servers. • Indexing for query optimization. • Support for ODMG. • Either raw devices or files for data storage.h++ • Support for ODMG-93.

Physical Database — A VERSANT database system physically consists of: • System files. savepoints. • Application development tools. • Modification of data definitions. including explicit pinning of data. • Link libraries. nestable transactions. Application Programming — Application programming features include support of: • All features of access languages. • Creation of classes at run time. • Custom and third party libraries of code and data types. C++. • Class libraries for each language interface. How to Use VERSANT — To use VERSANT: • Create data definitions and applications using VERSANT routines along with normal interface commands and methods. • User authorization. • Multiple kinds of atomic work units.VERSANT Database Fundamentals Manual Database Administration — VERSANT database administration utilities support: • Creating. before saving or retrieving persistent objects. • Header files. • Predefined data types and management routines. including short transactions. • Application debugging facilities. • Proprietary and third party programming tools. 14 . checkpoints. • Error handling mechanisms." A session is a period of time in an application during which a VERSANT memory workspace exists in process memory or shared memory and during which you have access to at least one VERSANT database. which are files or raw devices. You can also access databases with SQL statements and parse the results with C or C++ routines using the VERSANT Query Language. • Control of process and shared memory. and long transactions. • Executable utilities. expanding. • Custom system configurations. • At least one database consisting of storage and log volumes. including flow of control. • In your application. start a database "session. and Java. • VERSANT provides application programming interfaces for C. • Backing up data. For the C and C++ interfaces: • Include relevant VERSANT header files and then compile and link with a VERSANT compiled code library to create an executable program. and deleting databases.

A server can support concurrent access by numerous users. which means that it uses distributed resources in such a way that performance does not decrease as the system grows. A client application can access multiple databases concurrently with other client applications. Your application is the database client and runs on a client machine." One of the roles of the server is to process queries. a file/server query causes all objects of a class to be locked and passed over a network even if only one object is desired. To VERSANT. network traffic is reduced to a short query message from the client to the server and the return of only desired objects from the server to the client. VERSANT Database Fundamentals Manual For the Java interfaces: • Use the JVI Enhancer that post-processes the compiled class byte-code to provide transparent persistence. Client/server model VERSANT uses a client/server model of computing. 15 . Processing queries on servers balances database processing responsibilities between the client and the server. The database that provides objects to an application is called the "server. Scalable Operation VERSANT is scalable. distributed database environment by taking full advantage of available platform and network resources including parallel and scalable processors. the terms "client" and "server" refer to roles and not machines or processes. It can result in major performance gains in a large. Because queries are executed on the platform containing the data and because locks are set at the object level. By contrast. The client and server can be on the same machine or on different machines. VERSANT is scalable because of the following features.

16 . Database volumes can be files or raw devices and can be added incrementally either locally or at distributed locations.VERSANT Database Fundamentals Manual Communication between client and server is via TCP/IP. Two-phase commits involve a procedure in which multiple databases communicate with each other to confirm that all changes in a unit of work are saved or rolled back together. Schema management To facilitate the use of distributed databases. you can ask an object the name of its class and then inspect its class definition. instances are updated the next time they are accessed. Lazy updates Changes to class definitions do not paralyze operations. which is called a "lazy update. Two-phase Two-phase commits To ensure data integrity when multiple. Instead. and create or drop attributes and methods in leaf or non-leaf classes. which are storage places on disk. Routines are also provided for creating and modifying classes at runtime and for synchronizing class definitions among multiple databases. Distributed Databases VERSANT supports distributed databases with the following features. Locks The VERSANT locking model provides for high concurrency of multiple users. Volumes can be anywhere Objects are kept in one or more database volumes. VERSANT performs updates with two-phase commits. distributed databases are used." You can create or drop leaf classes. rename leaf or non-leaf classes.

Recovery To ensure data integrity when multiple. tapes. Replication Advanced functionality includes group checkouts. or files. 17 . distributed databases are used. Expansion Databases can be created. VERSANT performs updates with two-phase commits. which can replicate data on numerous databases. Class definitions are stored with objects. Heterogeneity Objects can be moved among heterogeneous platforms and managed in databases on numerous hardware platforms to take advantage of available resources in a network. Backup Data on one machine can be backed up to remote sites. Object migration is possible. Two-phase commits involve a procedure in which multiple databases communicate with each other to confirm that all changes in a unit of work are saved or rolled back together. deleted. which may be customized. which allow access to objects with applications that are running on different platforms and are using multiple interface languages. VERSANT Database Fundamentals Manual Object migration Objects can be migrated while applications still have transparent access to them. Schema management Class definitions can be managed at run time on both local and remote databases. Multiple distributed databases can be backed up to save their state at a given point in time. because objects have identifiers that stay with the object for its lifetime which means that the physical locations of objects are hidden from the application. Security Access to databases and system utilities is controlled through user authorization. This gives transactional consistency across multiple databases. and expanded on local and remote platforms. Database volumes can span devices and platforms.

Connection database Applications can connect to any number of local or remote databases and then manage objects in them as if they were local. You can work on objects in any number of databases at the same time in a distributed transaction. They also specify queuing options when the object you want is not available. Two types of databases VERSANT allows you to create two kinds of databases: group databases. which are only accessible to one user at a time. Checked out objects are tracked in long transactions. which are accessible to many users. Workgroup Support VERSANT supports workgroups with the following features.VERSANT Database Fundamentals Manual Session database VERSANT implements the concept of a session database. There are two basic kinds of VERSANT locks. Checkouts Checking out of objects provide local access to objects over long periods of time. locks are applied at the object level. which handles basic record keeping and logging for a session. and notification of lock related actions performed by other applications. controlled. which can be local or remote. Persistent locks have the same features as a short lock. and personal databases. 18 . Personal checkouts copy objects from a group to a personal database. During the checkout period. Object level locking Object level locking provides for maximum access to data while providing read and modification guarantees. Locking Locks allow multiple applications to access the same objects simultaneously in a cooperative. To maximize concurrency. Short locks reserve objects during a short transaction typically lasting only seconds or minutes. plus persistence from session to session and the ability to set multiple levels of locking priorities. which is useful when you want to update a set of objects over a long period of time without network traffic or local logging or locking. VERSANT places persistent locks which hold even if you disconnect from the source database. and predictable manner.

Variety of transactions VERSANT supports multiple kinds of atomic work units. VERSANT Database Fundamentals Manual Group checkouts copy objects from one group database to another group database and are useful when you want to replicate a set of objects in many locations that may be physically far apart. including short transactions. Each language-specific interface consists of several libraries of precompiled routines and. There is no special VERSANT database language. for typed languages. An interface can include its own development tools. VERSANT object databases are most commonly used with languages that implement the concept of either class or template and either delegation or inheritance. checkpoints. which are not object oriented. VERSANT provides language specific interfaces for C++ and C. savepoints. and can be used with other vendors' software development products. 19 . Any action or data type that can be expressed in the interface language may become a part of a VERSANT database schema. The language specific interfaces map all capabilities and programming styles of a particular language to the object database model. Configuration Management Configuration management allows customized sets of object versions. such as C. but the database is not tightly bound to a particular language. Compilers and debugging facilities VERSANT supports multiple compilers and debugging facilities. and long transactions are for use when objects are needed for hours or days. Short transactions are for use when objects are needed for short periods of time. Standard interfaces Multiple standard language interfaces allow workgroup members to access data from applications written in multiple languages. programming languages are tightly bound to the database. predefined data types. Versions Versioning allows you to trace the evolution of an object over time and is also a way of allowing multiple users to work on the same data. Thus. and long transactions. VERSANT can also be used with languages. In its present release.

There is one object cache per application. This approach combines the best of a page management scheme and an object management scheme. Process tuning VERSANT allows you to set operating parameters for application and server processes. and one page cache per operating database. because the object cache provides for fast access to objects needed in the current transaction while the page cache provides fast access to objects used in preceding transactions and to objects stored on the same page as a recently accessed object. Object migration Because object are persistently and uniquely identified. VERSANT maintains an object cache in virtual memory on the client machine and a page cache in shared memory on server machines with a database in use. Object and page caches During a database session. Performance VERSANT performance features include the following. objects can be redistributed in a system of databases for performance improvements without affecting application code making object references. Shared memory cache Database servers maintain a page cache in shared memory. Custom lock models For situations requiring unusual types of access.VERSANT Database Fundamentals Manual Libraries You can use VERSANT with custom and third party libraries of code and data types. 20 . including explicit pinning and releasing of data. Memory management VERSANT provides numerous mechanisms for managing application memory. you can define your own locks. Tools VERSANT supports a variety of proprietary and third party programming tools.

You can also establish multiple sessions. because original copies of objects remain in their source databases. Turning locking off is safe in a personal database. Indexing You can create indexes on attributes. Multiple processes and threads You can use multiple processes or threads in a session. Raw devices You can use either raw devices or files for data storage. which will improve query performance. which will improve query performance. which reduces network traffic. Local access You can checkout objects to provide local access. 21 . Navigational queries You can use object references to navigate to related objects. because there can be only one user of a personal database at a time. VERSANT Database Fundamentals Manual Clustering You can cluster instances of a class on disk storage. Turning logging off is safe if used in conjunction with checkouts. Locking and logging on or off You can turn locking and logging off to improve performance.

VERSANT Database Fundamentals Manual Storage Architecture Each database consists of a number of volumes. Logical Log Volume Physical Log Volume The Logical Log Volume and Physical Log Volume are used to record transaction activities and provide information for roll back and recovery. The maximum number of databases that can be combined to form a distributed database system is 216. Logical log and physical log volumes are created when a database is created. Data volumes Additional data volumes can be added to a database to increase capacity. A volume can be either a file or a raw device. The basic storage architecture is: There is no structural difference between personal and group databases. It is used for storing class descriptions and for storing object instances. which are storage places on disk. 22 . Database volumes are: System Volume The System Volume for each database is automatically created as a part of the initial process of creating a database.

you must also insert your classes into a database with the Schema Change Utility sch2db. applications and VERSANT libraries are stored as files. With the C++ Interface. you write a program that includes appropriate VERSANT . VERSANT Database Fundamentals Manual For the C and C++ interfaces. You then compile your program and then link it with appropriate VERSANT .h specification files. When you create classes or an application. 23 .a library files.

object validation. long transactions." VERSANT Manager then communicates with a module called "VERSANT Server. and management of storage classes. and locking. short transactions.VERSANT Database Fundamentals Manual Software Structure Internally. a VERSANT Manager may communicate transparently with all parts of a distributed database network. Because of this form of internal communication. and management of queries. this section is provided for your interest only. Internal communications occur through network layers." VERSANT Manager performs object caching. VERSANT is composed of several software modules. 24 . schema. page caching. versions. VERSANT Manager From a developer's viewpoint. The network layers translate messages as appropriate to the network protocol. programs using language interfaces drive all database and object management actions by communicating with a module called "VERSANT Manager. query support. for they operate invisibly. You do not need to know about these software modules. logging. The Virtual System Layer provides portability across hardware boundaries. and checkins. object update. checkouts. links. Thus. Virtual System Layer Between a VERSANT Server and an operating system is a Virtual System Layer specific to the hardware platform. indexes. VERSANT Server VERSANT Server performs object retrieval.

no messaging concept in the pure C environment: when you define methods they are executed as functions. inheritance is limited to virtual inheritance. and can be used with other vendors' software development products. Methods are provided to define embedded. and version relationships. including the ability to define embedded. predefined data types. VERSANT object databases are most commonly used with languages that implement the concept of either class or template and either delegation or inheritance. inheritance. An interface can include its own development tools. there is no runtime binding to functions. association. In its present release. This means that you use standard language statements to manipulate VERSANT. and identifying class attributes. association. Also. VERSANT provides language specific interfaces for C++ and C. Any action or data type that can be expressed in the interface language can become part of a VERSANT database schema. C/VERSANT Interface The C/VERSANT interface can take advantage of most object model capabilities. locating subclass and superclass information. VERSANT Database Fundamentals Manual Language Interfaces Language-specific interfaces map the capabilities and styles of a programming language to the object database model. such as C. and version relationships. Any persistent class can have transient and persistent instances simultaneously. There is no special VERSANT database language. and there is no concept of private versus public functions. for typed languages. Each language-specific interface consists of several libraries of precompiled routines and. inheritance. which are not object oriented. VERSANT can also be used with languages. however. 25 . C++/VERSANT functionality is available through standard C++. There is. either at compile time or at runtime. C++/VERSANT also implements complete VERSANT database functionality as both functions and utilities. This includes dynamic access to the database schema for runtime type checking. C/VERSANT also implements all VERSANT database functionality as both functions and utilities. C++/VERSANT Interface The C++/VERSANT interface implements the full object model.

In order to allow multiple inheritance and class embedding. 26 . Methods are provided to define embedded. Database object model A VERSANT database stores schema information in class objects and data in instance objects. and identifying class attributes. Associations among objects may be defined with links. the attribute names of superclasses may be the same as attribute names in derived classes. JVI functionality is available through standard Java. association and inheritance relationships. locating subclass and superclass information. If the attribute type is another class. VERSANT assigns a unique database name to each attribute. the embedded class name. at run time the compiler assumes that the object has a fixed size and layout. either at compile time or at runtime. there are differences in the C++ languages that limit object sharing. C++ data model Classes defined by C++ may have multiple inheritance. and that each attribute is of a particular domain. Even though the storage layout may be different among different C++ compilers. and classes may be embedded as attributes. refer to the JVI documentation. Any persistent class can have transient and persistent instances simultaneously. J/VERSANT Interface JVI (Java Versant Interface) implements the full object model. This includes dynamic access to the database schema for runtime type checking. For more information about the JVI language binding. The information in the class objects is slightly different depending on what language defined the class.VERSANT Database Fundamentals Manual Sharing C++ Objects Although VERSANT stores objects in such a way that they can be accessed by C++ applications. JVI also implements complete VERSANT database functionality as both functions and utilities. the database attribute name is a concatenation of the class name. For C++/VERSANT applications. the storage layout of an object is defined at compile time. but the objects are accessible to all supported language interfaces. and the attribute name. Following is an explanation of the VERSANT and C++ data models. This name normally consists of the class name concatenated with the attribute name.

X3J16 C++. 27 .) PCTE (Portable Common Tools Environment). • Object Management Group (OMG). • ANSI (American National Standards Institute) X3H2 Structured Query Language. Versant is committed to and/or working on the following: • ISO 9001 Registration for Company-wide Quality Management Systems. • PDES/STEP. VERSANT Database Fundamentals Manual Standards Versant Object Technology Corporation is involved in efforts to define industry standards. X3J4 Object-Oriented COBOL Task Group. X3H7 Object-Oriented Information Systems. • ECMA (European Computer Manufacturers Assoc. • Object Database Management Group (ODMG).

If you are new to databases and/or object programming. you must know how to use them. tune performance. which can help during the start of the programming phase of a project. to reduce network traffic. VERSANT is a powerful and flexible database system. the object model. If you are an experienced database developer or object programmer. Among other things. and move databases after they have been created. it has numerous features that allow you to perform almost any database task. then you will immediately appreciate the power and flexibility that VERSANT offers. we recommend training. no matter what your background. VERSANT is an expression of the object model of data with familiar and natural models for database management and interface usage. and VERSANT must all be understood in order to create efficient application programs. For information about VERSANT training classes or on-site consultation. please call the Versant Training and Consulting Group. the number of VERSANT features is so large that VERSANT may be overwhelming at first. scalable. your program will tend to get deadlock errors. Accordingly. Although our customers and industry studies report order of magnitude gains in productivity with the use of object programming and object databases. However. most also report that an initial period of training in the concepts involved has a high payoff. You must use group operations to retrieve and update large numbers of objects. VERSANT has four different ways to retrieve objects. VERSANT is designed for use as a high-speed. For example. You must use cursor queries instead of simple 28 . change schemas. Versant also offers on-site consulting. heterogeneous. normal database procedures and protocols. invoke database administration utilities at run time. Accordingly. and numerous transaction alternatives. in a workgroup environment. To benefit from these features. For example. you can move objects among databases. you will find VERSANT to be logical and predictable. VERSANT has most features and options found in modern database systems. seven types of locks. you must know when to use update locks or else. either by VERSANT or by third party vendors.VERSANT Database Fundamentals Manual System Usage Notes VERSANT provides a lot of features. production database in a complex. client/server. workgroup environment. If you do not have a database background. create classes at run time. Once you understand the underlying concepts. you must understand that VERSANT provides database features that go far beyond mere object storage. It is up to you to decide how best to use them for your needs.

and languages and provides controlled use of shared memory. VERSANT supports all computational and control features found in its interface languages. you must learn about the best way to implement various tasks. memory management. embedded. VERSANT implements the object model of data. It also extends these languages to provide database. VERSANT uses object languages. VERSANT provides heterogeneity among platforms. and that most objects are found by following links rather than by performing queries. If you have a procedural programming background. has-a (association). and contains-a (embedded) relationships. which means that VERSANT is scalable and provides for the beneficial use of additional hardware resources. you must not use pointers to unpinned objects. these gains depend upon an understanding of the object model. you must learn about messages and classes and learn that switch statements are rarely needed. and multiple language. Also. If you have a database background. provision for controlled use of shared memory by multiple processes. which provides an extraordinary amount of power and flexibility. five options for session memory workspaces. hardware. low-level and high-level variable-length storage types. and process control features. VERSANT extends operating system functionality. VERSANT implements the object model of data. and compiler interfaces. you must learn the differences between is-a (inheritance). However. VERSANT allows you to define your own data types and establish inheritance. which provides important benefits in a heterogeneous. you must remember to turn locking and logging on when using VERSANT in a production environment. and. you must know that although links are always safe. For example. No matter what your background. VERSANT Database Fundamentals Manual queries to reduce the size of the result set. If you have a relational database background. It uses a client/server model. workgroup environment. VERSANT extends operating system functionality. compilers. For example. and association relationships among objects. For example. the extensions that VERSANT provides must be understood to be 29 . VERSANT has numerous functions that control memory. you must remember to perform frequent database backups. For example. as with any production system. The advantages of using objects include dramatic gains in programming productivity and the ability to create applications that were not previously practical.

the usage. Analysis You must have a firm understanding of your situation and project goals before beginning development of your application. VERSANT is a complete database system with orthogonal session. rules. For example. the principal phases of a VERSANT application development effort are analysis/design. and deployment/ maintenance. usage. it is critical to understand that database transactions and the support of multiple users are significant considerations. Some elements of VERSANT. We recommend using a design methodology such as Booch and Rumbaugh along with a CASE tool to record your design. implementation proceeds far more smoothly than with non-object oriented languages. they must be used together in a consistent manner in order to achieve results. development/testing. Also. Design Experience suggests that the design phase of software development is even more critical to the success of object oriented projects than it is to procedural programming projects. versioning. Because interface dependent and interface independent elements are orthogonal but interrelated. VERSANT users have. and interface models provide flexibility. There are new procedures and new usage conventions. There is no sequential. If you have a good design for the classes in your application.VERSANT Database Fundamentals Manual used. you must be in a session before you can interface with a database. ready to be modified at will. however. any other database system. inevitably. Also. thus. conventions. lock-step way to explain VERSANT or. you should carefully identify whether there are any bottleneck objects that must be write-locked by many transactions and will thus be a disproportionate 30 . and object management models. As with any programming project. and usage are language specific. VERSANT concepts are orthogonal but mutually supportive. for that matter. such as the data model and database administration. Other elements. locking. VERSANT should be used in the context of good software engineering practice. Because they are orthogonal. The reason is that the object programming development lifecycle becomes shorter with a higher percentage of the time spent understanding the problem to be solved and designing the needed classes. a systematic presentation of VERSANT is necessarily arbitrary. interface. different backgrounds and skill levels. database. Development/Testing During the Development phase of software development. Following are brief comments related to each of these project phases. are language independent. such as the interface model. Experience suggests that you cannot "retrofit" transactions and concurrency into an application that assumes all of its data is in memory and.

Class-level unit testing is essential early in development to catch minor design problems before they turn into major rework headaches. multi-user testing uncovers subtle flaws in an application's locking and data-sharing strategy. Distribution model (how to maximize available resources. and you can use third party tools with VERSANT. Often.) 4. Ten Tips for Success Based upon our experience with customers. Deployment/Maintenance You should design and implement your application with deployment and maintenance in mind. backup and restore your database? Where will your software reside on the system? How will you reliably move your software from your development environment to your user's machine? How will you handle upgrades to your software and database schema? VERSANT provides tools and services to assist with all these tasks. Usage model (how users interact with the application and what tasks are most performed.) 6. you will probably want to iterate through the design and development stages numerous times. Navigation model (how do you move from object to object. Testing is a key component of any development project. performance tuning is an issue that is often considered during development/deployment iterations. Performance tuning. Because design and development work interact. the software engineer and project manager.) 5. but also with the use load you expect in production. You will probably also want to iterate through development and deployment. Test your database code not just with a single user. How will users build. This is not 31 . maintain. For example.) 3. Important development issues are: 1. but the primary responsibility to ensure that each phase is successful rests with you. where a "semi-final" deployed product results from each iteration. Review of the object model (classes and associations) in the light of implementation issues. Transaction model (how do you maximize concurrency and define units of work. following are ten tips for success in using VERSANT. Test to be certain that each of your classes do what you expect. VERSANT Database Fundamentals Manual source of lock contention. 2. Acceptance testing is critical to ensure that the application meets the user's expectations. Integration testing and multi-user testing is essential to ensure the system works as you intend.

an application may run quickly on a machine with a large amount of physical memory but become sluggish on a smaller machine due to virtual memory paging.VERSANT Database Fundamentals Manual meant as a definitive list of success tips. problems don't show up until a program has been running for days or weeks or tested with extremely large numbers of objects or users. Spend time on design. prepare reports. We suggest that you write monitoring code that can be turned on and off and also write external scripts that log resource consumption in various sectors of your programs. Keep short transactions short and hold locks for a minimum amount of time. It is important to determine what running an application will be like for end users with more modest machines. just a few suggestions based upon common problems. and performance problems tend to surface only when databases similar in size to the target production environment are used. Gather and log performance data on an regular basis. Open transactions hold locks. every time you run into a problem. Use the same hardware as the user. Alternatives are to use timeouts during screen input/output or to gather all input from the user before 32 . Prototype with a realistic amount of data. Developers tend to have high performance machines. concurrency issues are often the most important factor in performance. Use your computers around the clock. and run long test programs when you are not around. so avoid "think times" in which a short transaction is open while the application waits for user input. bugs. When an application is deployed. Holding key objects locked will block other users from doing work. Many design issues. You can use scripts to perform database administration. run batch jobs. Test with multiple users. Data of this kind is extremely useful both in debugging and in performance tuning. The most important thing is to identify the various objects that will be used and the operations that will be performed on them. Sometimes. One of the most important factors in a successful deployment is rigorous testing under a wide variety of conditions. Most projects do not spend enough time mapping logical designs to physical designs. If you run your machine constantly. you can add a unit test to a growing suite of automated tests that can be re-run every time you make a change of any kind. Everything runs fast with fifty objects. For example.

There is so much power and flexibility in using objects that taking time to just learn what can be done is time well spent. In a multi-user environment. Invest in training on a regular basis. VERSANT Database Fundamentals Manual updating objects. 33 . Training in object languages and VERSANT typically pays for itself ten times over. Use update locks when appropriate. They have the additional advantage of guaranteeing you the next write lock. For example. programming the following sequence of events is deadlock prone: begin transaction read objects write lock selected objects update selected objects end transaction Update locks allow you to read objects without blocking other readers. you cannot assume that you will always be the next person to convert a read lock to a write lock.

...........................................................................................................................................................................................................................................44 34 ..............................................42 Object Relationships..........................................37 Object Characteristics............................................................................................................................................................................... This chapter provides an explanation of the VERSANT object data model.......VERSANT Database Fundamentals Manual Chapter 2: Objects VERSANT databases model data as objects..............................................................................38 Object Status....35 Object Elements ............. Object Types.....................

Object A database "object" is a software construction that can encapsulate data and references to other objects. Following is listing of object types. the generic term "object" refers to an object containing data. but it can also refer to other kinds of objects. and pointers to functions are difficult to implement although easy to avoid. an object has a class that defines what kinds of data are associated with the object. Elemental (immediate) values are stored as typed values. Objects are useful if you want to organize large amounts of code. images. VERSANT allows you to convert an instance object to a "versioned object. called a "class object" or "schema object. sounds. and/or make frequent modifications to applications. Usually. perform navigational queries." There can be numerous versions of a particular instance object." that stores your data type definition in a database. VERSANT creates for each class an associated runtime type identifier object that contains additional information needed by C++. Versioned object To track the evolution of the states of an instance object. The term "object" has numerous meanings. model graph structured data. Class object When you create a class. documents. Instance object A database object that holds data is called an "instance object". C++/VERSANT — Objects are defined in a class using normal C++ mechanisms. or references to other objects. bitfields can cause problems in heterogeneous systems. Each instance object has an is_a pointer to its type identifier object in order to identify its class. Only a very few data types are difficult to implement in object databases. You can define classes to contain any kind of data. VERSANT Database Fundamentals Manual Object Types Software objects are a response to programming issues inherent in large and complex software applications. which are clear in context. VERSANT creates a special kind of object. This runtime type identifier object is an instance of the C++/VERSANT class PClass. 35 . including values. In a VERSANT database. handle complex data types. For example.

36 . allowing "large" objects to be lazily instantiated on a per object basis. Stand-alone Stand-alone object C++/VERSANT — A stand-alone object is one created with the C++ new operator. Persistent objects must derive from the VERSANT PObject class. Performance options are provided so that you can explicitly control how referenced objects are read in. only those portions of it which are examined by the user will actually be loaded into memory. or an object defined as a local or global variable. When a complex object is read from a database. Persistent object A "persistent object" is an object can be stored in a VERSANT database. Smart object A smart object automatically selects the correct version of an object based upon a pre-selected configuration. with a C++/VERSANT new operator or function.VERSANT Database Fundamentals Manual Transient object A transient object exists only while the program that created it is running. C++/VERSANT — Both transient and persistent objects are dereferenced with the same syntax. Embedded object C++/VERSANT — An embedded object is an object that is an attribute of another object.

After the class files have been compiled." An attribute is persistent when the object containing it is persistent. which sets the values of the coordinates. consider a C++ class named Coord. After class files have been compiled. 37 . Actual data are stored in instance objects. another object with its own attributes. get_x(). Object methods C++/VERSANT — The parts of an object that store executable units of program code are called methods. C++/VERSANT Example — For example. An attribute can be a literal whose elemental value is self-contained. Methods are defined and implemented in normal C++ class files. Attributes are first defined in normal C++ class files. which returns the value of the x coordinate. methods are linked with an application. Attributes of class Coord are the coordinates x and y. which returns the value of the y coordinate. Methods of class Coord are set(). Object attributes C++/VERSANT — The parts of an object that store data and associations with other objects are called "attributes. attribute definitions are loaded into a database and stored in class objects. and get_y(). or a reference to another object. the implementation of objects involves several discrete elements. an object that is an array of other objects. VERSANT Database Fundamentals Manual Object Elements Although objects are used as if they were a single structure.

Object and database identifiers do not change when an object or database is moved or changed. The overhead in memory of a VERSANT object identifier. on 32-bit cpu architectures. Object migration The ability to migrate objects makes distributed databases practical. A link requires eight bytes. VERSANT assigns each persistent object a unique identifier called its logical object identifier or loid. To ensure that database identifiers are unique. it is guaranteed to be unique among all objects in a system. This identifier is created by VERSANT when the database is created. After an object has been created. Because an object identifier is built upon a database identifier unique within a system of databases and an object identifier unique within a database. even after an object or database has been deleted.VERSANT Database Fundamentals Manual Object Characteristics Following are characteristics of persistent objects. For a particular database system. The object identifier portion of a loid is an identifier that is unique within the creation database. The database identifier portion of a loid is an identifier for the creation database that is unique among all databases in a system of databases. This identifier is created by VERSANT when the object is created. and four bytes for a non-persistent object. your system must be able to modify the system file. is approximately twenty-four bytes per persistent object. which will reduce network traffic. Identifiers are never reused. all databases in a system of databases have their identifiers stored in a single database system file named osc-dbid. but once a database is created you do not need to be connected to a network to perform tasks such as creating or managing objects in a local database. Because the object portion of the identifier is based only upon other objects within the creation database. This means that code that 38 . because it makes possible such features as persistent references to other objects and the ability to migrate objects among distributed databases without having to change code that accesses the objects. or migrate it because disk space is filling up on the machine containing the creation database. you only have to be connected to the creation database when you create an object. When you create a database. Logical object identifiers are composed of two parts: a database identifier and an object identifier. Object identity One of the strongest concepts in object technology is object identity. you can address 2^64 objects in 2^16 databases. you may want to migrate it in order to place it physically closer to where it is most often used.

an attempt to migrate an object with a different class definition will be automatically blocked. In effect. and reference relationships to relate classes to one another results in a model that directly reflects the real situation. Inherited methods can be redefined in sub-classes. inheritance. Schema modification After you have completed a complex application. it exists as an independent object in that database. you will almost certainly want to extend or modify its underlying classes to accomplish new tasks. You can overload a method to work for several classes and a varying number of arguments. For a method to respond. to resolve the differing class definitions. 39 . you may want to redefine methods. if it is not already defined in the target database. such as a "synchronize class" routine. once a class object has been migrated. You can then use any of a variety of mechanisms. Each persistent object must have a class object associated with it that contains its class definition. the message must have both the correct name and the correct signature. The set of object definitions associated with a particular database is called the "schema" of that database. VERSANT Database Fundamentals Manual references an object does not have to be changed each time an object is migrated. This is much more understandable than a flat system of normalized tables whose logic must be reassembled each time they are used in each application that accesses them. Situation modeling An important advantage of using the object model is its ability to model situations in a realistic manner than can be understood by others. However. such as a "print yourself" method. Polymorphism To use a method. Using classes to classify individual elements of a situation and then using embedded. The number and data types of the arguments for a method are called its signature. Dynamic binding When you define a new class that specializes its base class. a particular class object may be duplicated in numerous databases. you do not have to be connected to its creation database. for the new class. If classes of the same name are defined differently in different databases. Because migrating an object instance includes migration of its definition in a class object. you call an object method with a message. This means that to use a migrated object. this is called polymorphism and can simplify control structures significantly. When you migrate an object to a new database. polymorphism binds a message to a particular method at run time in a manner similar to case statements. a copy of its class object is also migrated.

Link — A link stores a reference to another object. List — A list provides ordered variable length storage. C++/VERSANT — C++/VERSANT also predefines the following types. Bi-link vstr — A bi-link vstr provides variable length storage for one or many bi-directional references. The following types available in all interfaces. variable length storage for one or many elemental values. Bi-link — A bi-link stores a bi-directional reference. In many cases. that have identical functionality and differ only in the data type of their contents. Date and Time — Date and time attribute types. Smart — Smart objects automatically select the correct version of an object based upon a pre-selected 40 . inheritance. Predefined types VERSANT predefines many elemental and class types that you can use with embedded. Run-time — Classes that are defined at run-time. Set — A set is an unordered collection of unique elements. and perform existing tasks differently without changing applications that use the classes. perform new tasks. C/VERSANT — C/VERSANT also predefines the following type. and association relationships. you will be able to redefine classes by extending them to hold additional data. Vstr — A vstr provides low overhead. Dictionary — A dictionary is a collection that maps keys to values. such as sets. The C++/VERSANT interface also provides facilities to create the following types: Parameterized — Parameterized types allow single definitions for classes that differ only by the data type of their contents. Link vstr — A link vstr provides variable length storage for one or many references to other objects. This is useful for classes. List — A list provides ordered variable length storage.VERSANT Database Fundamentals Manual You can add to and change the schema of a database at any time. Array — An array is an ordered collection of elements accessed by an index which is an integer.

VERSANT Database Fundamentals Manual configuration. 41 . VERSANT also allows you to use third party class libraries to define your classes.

42 . non-versioned objects into versioned objects." Each version of an object has a unique object identifier. This improves performance significantly. a write lock guarantees that you are the sole user of an object. its old data is overwritten. the old object is preserved and a new object is created with the new data. All versions of an object are maintained by VERSANT in a version graph. because at the time of a commit VERSANT does not have to compare the contents of each object you have used with its original contents in order to determine which objects need to be updated. Versioned objects behave differently from non-versioned objects under certain circumstances. only persistent objects are saved to a database. working or released. When a non-versioned object is updated." which means that it will be updated at the next commit. When a versioned object is checked out for update. Object transient. Following is a list of the status information maintained about each object. VERSANT notes whether it is transient or persistent. transient objects are treated the same as persistent objects. The new is called a "child" of the original "parent" object. versioned objects are checked out with a null lock and become new objects. such as during a checkout and checkin. which is important if you want to update the object. such as transient. For example. Within the scope of a transaction.VERSANT Database Fundamentals Manual Object Status When you create or access a database object. To track object states. Object dirty status When you change an object. a number. and a version status. you must mark it as "dirty. but when you perform a commit. you can convert regular. VERSANT maintains information about its current status. Object lock status Locks provide access guarantees to objects. Object versioned status You may want to track the evolution of the states of an object over time. Versioned objects that share the same parent are called "siblings. For example. persistent status When you create an object.

an object can be checked out from a group database accessible to many users to a personal database accessible to only one user. VERSANT also allows you to set nested pin regions to make it easier to pin and unpin specific sets of objects. 43 ." and then automatically select the correct object versions using a "smart object. Normally. Unless the object is a versioned object." which means that it will not be swapped out of the object cache back to its source database. such as a request to be notified if another user is trying to access the objects you have checked out. An object in the cache can be "pinned. A pinned object is not guaranteed to be in process memory. pinning occurs automatically when you access an object. a copy of it is made and placed into the personal database and a persistent lock is placed on the original object. Versioned objects become new objects when they are checked out and when they are checked in. When you checkout an object. This allows you to work on an object for an extended period of time without network traffic. This replication ends when the possibly changed object is checked back into the group database." Object checkout status To improve workgroup functionality. When an object is checked out. just in virtual memory. you can set persistent object locks which will survive short transaction commits and specify various other options. VERSANT Database Fundamentals Manual Object configuration You can group specific versions of different objects into "configurations. VERSANT maintains an object cache in virtual memory that contains all the objects accessed during a transaction. Object pin status C/VERSANT and C++/VERSANT — To manage memory efficiently and to improve access to objects of current interest. the checkout copy in the personal database shares the same object identifier as the source object in the group database. but you can explicitly unpin objects if you are accessing a large number of objects and virtual memory is limited.

there can be two kinds of inheritance: single inheritance and multiple inheritance. while inheritance is useful to define an employee as a kind of person. Single inheritance describes an object related to ancestors in a stack structure. then each derived class describes only what is new or different about itself. while others can be used as stand-alone objects. and customized. descendant objects "inherit" data and methods from their ancestors. C++/VERSANT — In C++. 44 . An inheritance relationship is called an "is-a" relationship. embedded objects are accessed via the containing object. Object inheritance relationship When you define objects. because the derived class is a special form of its base class. Because derived classes inherit both attributes and methods. and you can manipulate an instance as if it had all of the methods that are available to its ancestors. Embedding predefined types such as dates or custom designed sets can also save a lot of programming time. Some C++/VERSANT classes can be used only as embedded objects. you can specify a hierarchical structure of base and derived classes. The ability to associate objects allows you to create graph structured data relationships. and only one entity is locked. An object that contains an aggregation of embedded objects provides referential integrity and avoids orphaned data. inheritance enables stable data and code definitions to be reused. Object association relationship An important feature of the object model is the ability to associate objects that are logically related but that are of different types. Multiple inheritance describes an object related to ancestors in a tree of stacks. you must create an association to relate an employee to a department. Inheritance is an efficient way to describe a situation: base classes describe once what is common to all of its derived classes. extended. An embedded relationship can also be called a "contains-a" or "containment relationship. because access to an aggregation of objects is done in one step." When you create instances.VERSANT Database Fundamentals Manual Object Relationships Object embedded relationship C++/VERSANT — An "embedded relationship" is created when you use an object as an attribute of another object. Using embedded objects can improve performance. For example. This means that you can store data in an instance as if it had all of the attributes that are in its ancestors. In this hierarchy.

which allow you to associate many objects into a single structure. Links also improve performance because linked objects are retrieved only when you decide that you actually want the object by dereferencing the link. arrays. There are several performance advantages to using links. The transparency of links is important. lists." because they are valid regardless of the location of the object. and many-to-many associations using the predefined VERSANT link and link vstr data types. VERSANT also has data types for "bi-links. and for containers. However. and they remain valid even if you move the object from one database to another. 45 . You can use either links or arrays of links as attributes. and dictionaries. because one object "has a" link to another object. because it allows you to write code that does not depend upon the memory or database location of objects. C++/VERSANT uses "links. Link relationships are called "has-a" relationships. To create persistent database pointers. it is much faster to find an object in a database using a link rather than a query. and pointers are unreliable for objects that are not pinned in virtual memory. assuming that both objects have been assigned a virtual memory address. one-to-many. VERSANT Database Fundamentals Manual C++/VERSANT — The association of objects is similar to using a C++ pointer from one object to another. This means you can move quickly among related objects by traversing the graph of relationships rather than performing repeated queries and joins. sets." Links are sometimes called "smart pointers. many-to-one. You can create one-to-one." which provide referential integrity and cascaded deletes. whether in memory or in a database. pointers are not valid for objects in a database but not in memory. Just as the fastest way to find an object in memory is to use a pointer.

..................................................................................................................................................................................................................53 Session Operations ..........VERSANT Database Fundamentals Manual Chapter 3: Sessions This chapter explains basic session concepts............54 46 .............................................................................................................................................................48 Session Elements ...................................47 Session Memory Areas ..................................................................49 Session Types............. Session Boundaries .........................51 Units of Work ................................................................................................................................................................................................................

47 . and persistent objects. data types. Transient objects of VERSANT data types and transient objects of classes derived from PObject that were created or modified during a session should be deleted before the end of the session. A process or thread can be in only one session at a time. VERSANT Database Fundamentals Manual Session Boundaries Applications perform VERSANT work in sessions. The only exceptions are methods that set session and environment parameters. transient objects of VERSANT data types and transient objects of classes derived from PObject that were created before a session should not be modified in a session. methods. C++/VERSANT When you are using C++/VERSANT. You must start a session to use VERSANT databases.

VERSANT Database Fundamentals Manual Session Memory Areas When you start a session. The server page cache is in shared memory on the machine containing the session database. VERSANT creates the following session memory elements. and long and short transactions. Object cache An object cache in virtual memory improves access to objects used in a transaction. connected databases. and session tables may be created in client machine memory. 48 . cache table. All memory areas are maintained for you by VERSANT. Server page cache Associated with the session database and each connection database is a page cache for recently accessed objects. Object cache table A cached object descriptor table tracks the location of all objects referenced during a session. The object cache. Session tables Various session information tables track your processes.

VERSANT Database Fundamentals Manual Session Elements The following are also associated with sessions. More than one group database can be accessed from a session database. A long transaction object in the session database tracks 49 . but you can change the default after a session has started. Short transaction When you start a "standard" session. To change the database used as the session database. Initially the default database is the session database. Session database A session database is used to manage short transactions that occur during a session and to coordinate two-phase commits. Each database connection starts a new server process on the database machine. It serves as the target of checkouts and is the initial default database. Connected databases Once a session has started. Either a personal database or a group database can serve as a session database. which must be the session database. For example. Specification of a session database does not change the database association of an object. VERSANT begins keeping track of your activities in a short transaction. Only one personal database can be accessed in a session. objects are returned to their source databases regardless of which session database you are using. Long transaction A session is always in a single long transaction. you must end the session and start a new session. Session name The session name is used as the name of the short transactions that occur during the session. Default database A database designated as the default database is the location of new persistent objects and is used by many functions when a null database name is specified as a parameter. you can connect to other databases. when you commit a long transaction while ending a session.

VERSANT Database Fundamentals Manual checked-out objects and persistent locks. 50 .

because the object cache is created in shared memory. you may be able to specify the kind of session that you want. depending upon your interface language. See the chapter "Multiple Processes in a Single Session" for more information. when one process is delayed. connections are made and server processes are started as needed for all other processes in the session. Almost all tasks can be performed using short transactions with commits. 51 . such as waits for locks. a corresponding server process will automatically be started for each existing database connection (including the connection to the session database). and if any application process in the session makes a new database connection. you are always in a short transaction and in a long transaction. or a printing activity. others can continue. VERSANT provides the following session options. The standard VERSANT locking model satisfies most concurrency requirements. rollbacks. you can use multiple processes. In a shared session. user input. and savepoints. A shared session is useful if you have a parallel processing machine or if it is likely that related transactions may encounter delays. checkpoint commits. Shared session In a shared session. If you do not make a specification for session type when you start a session. Each time an application process joins a shared session. and you are using the standard lock model. you will start a standard session. Standard session In a standard session. VERSANT Database Fundamentals Manual Session Types When you begin a session. Multiple threads in a session are usually more efficient than multiple processes. so using multiple threads is recommended over shared sessions.

See the chapter "Optimistic Locking" for more information. During this time. 52 . See the chapter "Multiple Thread(s) in Multiple Session(s)" for more information. although you will get an error if more than one process tries to read or write to a database at the same time. prevents automatic lock upgrades.VERSANT Database Fundamentals Manual Multiple threads and multiple sessions You can start a session in which you can place one or more threads. If you start this kind of session. and each of the additional sessions can have zero or many threads in it. and provides automatic collision notification. Optimistic locking session An optimistic locking session suppresses object swapping. Shared session with high performance option You can start a shared session in which no latches are held on the object cache when a process reads or writes to a database. This option is called the "single writer / multiple reader" option. you can also start additional sessions. other processes can continue to locate and process objects in the cache at memory dereference speed.

) Long transaction Standard session Short transaction Savepoint Standard session with threads Short transaction Savepoint Shared session with multiple processes Short transaction Savepoint Many long transactions can co-exist and do not depend on the kind of session that you start. Short transactions are a sequence of one to many within a session." 53 . Savepoints are a sequence of none to many within a short transaction. VERSANT Database Fundamentals Manual Units of Work Following is the hierarchy of possible VERSANT units of work in various kinds of sessions. Sessions can be a sequence of none to many. (Some interfaces do not allow all types of sessions. See also the chapters "Short Transactions" and "Long Transactions. such as shared or thread sessions.

VERSANT Database Fundamentals Manual Session Operations Begin session Start a session. start a short transaction. terminate the application process. c o_exit() c++ exit() 54 . and commit. rollback. depending upon the option supplied. disconnect the application process from all databases. commit the current short transaction. close all session memory workspaces. or continue the current long transaction. c o_beginsession() c++ beginsession() End session End a session. and start or join a long transaction. c o_endsession() c++ endsession() End process and end session End a session if it has not already ended. and either commit or roll back the current short transaction.

...........................................................................................................................................62 Long Transaction Actions ................................................................................................................................59 Short Transaction Hierarchy...........56 Short Transaction Description ...................................................................................................... VERSANT Database Fundamentals Manual Chapter 4: Transactions Short Transactions .......................................................................................................................63 55 ......................................................57 Short Transaction Usage Notes ................60 Short Transaction Effect on Memory .........................................................60 Long Transactions ..........................................................62 Long Transaction Usage .........................62 Long Transaction Description.........................................................................................................................56 Short Transaction Actions...................................................................................................................................................................................................................................................

When you end a short transaction. a short transaction and a long transaction. no other user can intrude upon your work. see the chapter "Long Transaction". A session is also a unit of work." 56 . Coordinated — Objects in a transaction are locked. which means that your work is coordinated with other users in a workgroup environment. another is automatically started for you. While in a transaction. because they ensure that data is always in a known state. This is an important database feature. Independent — When you are operating on locked objects in a transaction. Durable — Results are either saved permanently or abandoned permanently: no further undo or redo operations are possible. For information about sessions. Short transactions are: Atomic — When a short transaction ends. VERSANT begins keeping track of your activities in two kinds of transactions. If you have a special need you can start sessions in which you can use multiple processes in a transaction. you may want to create special kinds of short transactions. even in a distributed database environment. because it ensures that data is always in a consistent and known state.VERSANT Database Fundamentals Manual Short Transactions Short Transaction Description A short transaction is a logical unit of work whose results are either saved or abandoned as a group. As soon as you start a session. see the chapter "Session. Distributed — A two phase commit protocol ensures that data is always in a known state even when you are working with objects in numerous databases in a distributed database environment. If you are an advanced user. Ever-present — You are always in a short transaction. the results of all actions taken in the transaction are either saved or abandoned. Transactions are an essential database concept. you can operate on your objects as if you were the sole user of a database. For information about long transactions.

However. erases all savepoints. releases short locks. If your application or machine crashes. erases all savepoints. A commit makes no changes to transient objects. Changes made in a short transaction are not visible to other users until you commit them. objects that have been flushed to their database (by swapping. and starts a new short transaction. A commit also releases objects from cache memory. c o_xact() c++ commit() xact() Checkpoint commit short transaction A checkpoint commit performs a save and holds object locks. or deletions) will be visible to users using null locks in dirty reads. However. or deletions) will be visible to users using null locks in dirty reads. asserts persistent locks. 57 . VERSANT will automatically roll back the current incomplete short transaction. erases all savepoints. queries. and starts a new short transaction. asserts persistent locks. A rollback makes no changes to transient objects. and restores databases to conditions at the last commit or checkpoint commit. A checkpoint commit also maintains objects in cache memory. A rollback also releases objects from cache memory. VERSANT Database Fundamentals Manual Short Transaction Actions Commit short transaction A commit saves your actions to the databases involved and releases short locks. and starts a new short transaction. queries. This means that others cannot be confused by seeing partial changes. This means that others cannot be confused by seeing partial changes if they are using read locks. A checkpoint commit makes no changes to transient objects. Changes made in a short transaction are not visible to other users until you commit them. c o_xact() c++ checkpointcommit() xact() Rollback short transaction A rollback abandons your actions. objects that have been flushed to their database (by swapping.

VERSANT Database Fundamentals Manual c o_xact() c++ rollback() xact() Begin session Beginning a session starts a short transaction. Using savepoints is a way of working down a set of instructions toward a solution and then backtracking if some sub-set of the solution fails. 58 . You can set as many savepoints as you want in a normal short transaction. When a savepoint places a record of current conditions in the database log. which resets locks. c o_beginsession() c++ beginsession() End session Ending a session performs a short transaction commit. c o_savepoint() c++ savepoint() Undo to savepoint Undoing a savepoint returns database conditions to the immediately previous savepoint. or transient objects. conditions will be restored to those that existed at the last commit. however. During a session. changes to an object are visible to other users if they access the object with a null lock in a dirty read. Savepoints are not compatible with optimistic locking. Undoing a savepoint makes no changes to databases. locks. if there is no immediately previous savepoint. transient objects. locks. Setting a savepoint makes no changes to databases. or the memory cache. c o_endsession() c++ endsession() Set savepoint Setting a savepoint creates a snapshot of database conditions to which you can selectively return without ending the short transaction. because setting a savepoint flushes objects to their databases. but it does invalidate the object memory cache. you are always in a short transaction.

VERSANT Database Fundamentals Manual c o_undosavepoint() c++ undosavepoint() Short Transaction Usage Notes Following are usage notes related to short transactions. link vstr. bilink. yet they can be hard to retrofit into an application as they are a major structural element. you must enable logging in your database. Transactions are essential to data consistency and workgroup concurrency. or bilink vstr. you must enable locking. the attribute cannot contain a link to a transient object at the time of a commit. Turn logging on To use short transactions in your application. Turn locking on To use short locking in your application. See the VERSANT Database Administration Manual for information on turning logging on and off. Commit when states are consistent Commit a short transaction only when the states of the objects you are working with are internally consistent. See the VERSANT Database Administration Manual for information on turning locking on and off. because locks held by transactions block other users and work not committed will be lost if the application or machine crashes. Do not commit with a link to a transient object If you have an attribute of a persistent object that contains a link. Keep them short Keep short transactions short. 59 . Build in short transactions Build short transactions into your application from the beginning.

and 4 are committed to the database.VERSANT Database Fundamentals Manual Short Transaction Hierarchy The short transaction hierarchy is: Session Short transaction Savepoint For example: Changes in transactions 1. the following effects take place on memory: Memory effects of a short undo rollback checkpoint commit end transaction savepoint commit session Cache and cache table Invalidate object cache yes yes no yes yes Invalidate codtable no no no no yes 60 . Short Transaction Effect on Memory Memory effects of a short transaction — After a short transaction routine has executed. while changes made in transaction 2 are discarded. 3.

VERSANT Database Fundamentals Manual Afterwards for C Can use o_object in a variable yes yes yes yes no Can use a vstr yes no yes no no Can use pointer to persistent obj no no yes no no Afterwards for C++ Can use link held in a variable yes yes yes yes no Can use transient object created in a session yes yes yes yes no modified in a session yes yes yes yes no Can use pointer to persistent obj no no yes no no 61 .

If the linked object is not checked out. VERSANT allows you to checkout objects to a personal database. As soon as you start a session. Each time you check out a non-versioned object with a read or write lock. that object becomes associated with the current long transaction. rolling back. Long Transaction Actions Long transactions are defined by beginning and ending a database session. You can create numerous long transactions to track differing sets of checked out objects. 62 . you are in a long transaction.VERSANT Database Fundamentals Manual Long Transactions Long Transaction Description To improve performance in workgroup settings. When you start a session. the link will point to the object in its original database. If a linked object is also checked out with an object containing the link. A session takes place within a single long transaction that can last any length of time. then a default name is used and you either create or join a long transaction with the default name. See the chapter "Moving Objects" for information about checkins and checkouts. When non-versioned objects are checked out with a read or write lock. The default name is your login user name. When you are done with the checked out objects. This means that links to checked out objects are still valid. the link will point to the object in the checkout database. or continuing a long transaction has no effect on the tracking of checked out objects and persistent locks on objects not associated with that long transaction. you can start a new long transaction by specifying a new long transaction name or join an existing long transaction by specifying the name of an existing long transaction. object identity is maintained. Long transactions are a mechanism to track checked out objects and persistent locks. If you do not specify a long transaction name. you can return them to their source databases in a single step by ending the long transaction. Committing.

including those persistent locks set explicitly without making a checkout. Thus. c o_endsession() c++ endsession() Rollback long transaction A long transaction rollback drops all checked out. are stored and maintained for you by VERSANT in a long transaction object. c o_endsession() c++ endsession() Continue long transaction Continuing a long transaction means that you can rejoin it at a later time with no changes to persistent locks or to the checkout status of objects associated with the long transaction. non-versioned objects associated with that long transaction to their source database and drops the copies made in the personal database used for the checkout. VERSANT Database Fundamentals Manual Begin or join long transaction When you start a session. c o_endsession() c++ endsession() Long Transaction Usage You must access long transactions from your original session database. you can begin or join a long transaction. A long transaction rollback also drops all persistent locks set during the long transaction. A long transaction commit also drops all persistent locks on non-versioned objects that were set during the long transaction. including the objects associated with the long transaction and their source databases. c o_beginsession() c++ beginsession() Commit long transaction A long transaction commit returns write-locked. access to a particular long transaction depends on your choice of a session database. non-versioned objects associated with that long transaction from the checkout database and leaves the checked out objects in their current state in their source databases. 63 . This long transaction object is created and updated in the database used as a session database. including those persistent locks set explicitly without making a checkout. Information about a long transaction.

You can define any number of long transactions to keep track of discrete sets of objects. such as the nestable transaction. and custom locking options. You can override long transaction tracking of objects with an explicit checkin of particular objects. You cannot access a checked out object from its source database. because a checkout with a null lock creates a new object with its own identity and existence. only the objects associated with that long transaction are returned to their source databases and have their persistent locks released. then ending the long transaction does not change the object state but it does release all persistent locks. When you end a long transaction. Once you have created multiple. you can work with all objects that have been checked out to your current session database in all of the long transactions you have created. named long transactions. unless it is a versioned object. explicitly checked in before the long transaction ends. 64 . If you have checked an object out with a null lock. If an object checked out in a long transaction has been previously. you cannot check in objects not associated with the current long transaction. You must be connected to all source databases. shared object cache. You must keep track of the long transaction names you have used. You do not have to end a long transaction to check in objects. you can still access it in its source database. you cannot access it from the target/session database in its source database in either that long transaction or in any other long transaction. Committing a long transaction will fail if you are not connected to all source databases for the checked-out objects. These long transactions can be in the same or different personal databases. While in a session. Once you have checked out an object with a persistent read or write lock in a long transaction. You can create any number of long transactions.VERSANT Database Fundamentals Manual You can override long transactions. Successive sessions in a long transaction can be started with any session option that is valid for your platform and interface. However. although accessing an object in a long transaction other than the one in which it was checked out does not change its association with the long transaction used to check it out. you can move from one long transaction to another within an application by stopping the current database session and starting a new session.

the original objects may or may not have been updated to the states of the checked-out objects. the status of objects being returned by the checkin is indeterminate. VERSANT Database Fundamentals Manual You do not have to turn logging on. persistent locks in source databases are maintained. changes to a database cannot be rolled back if logging is off under the following conditions: • If logging is off in the session database: If a commit fails after a checkout. When the group database recovers. If a commit fails after a checkin. you can continue to work on your checked-out objects. During recovery after a crash. long transactions are reconstructed. If your personal database crashes. the status of persistent locks is indeterminate. the status of objects returned by the checkin is indeterminate. if logging was on. • If logging is off in the source database: If a commit fails after a checkout. Long transaction tracking of checked-out objects occurs whether logging is on or off in either source or target databases. the copies in the session database may or may not have been deleted. the status of long transaction tracking is indeterminate. However. it remembers which objects you have checked out and what locks you placed on them. they may or may not have been set. and objects are restored to their state at the last short commit. If a commit fails after a checkin. copies of the checked-out objects may or may not have been created in the session database. 65 . If you are working on checked out objects in a personal database and a group database crashes.

.................................................................................................................................................................................................................................................................................72 Short Lock Protocol ..67 Short Lock Features ............................................................................85 Persistent Lock Mode .............................81 Short Lock Interactions......................................................................................85 Persistent Lock Description.....................................................................................................................................................69 Short Lock Interactions...88 Persistent Lock Precedence ..........................................................................90 Persistent Lock Actions .....................................................................................................................................................................................................82 Short Locks and the First Instance............................................................................................................................................................................................67 Locks and Transactions .................................................68 Short Lock Types.............................................................................................................................................................................................................................................................................................................78 Short Intention Lock Description ................................87 Persistent Lock Event Notification ..........................................................................93 66 .......................................................................83 Persistent Locks ..................75 Short Locks and Queries............................................................................................................79 Short Intention Lock Mode ........................................................................67 Lock Overview ................................................................................85 Persistent Lock Level...................87 Persistent Lock Queuing...........................................................................................................................70 Short Lock Actions...............................................................................................................VERSANT Database Fundamentals Manual Chapter 5: Locks Short Locks ......................80 Short Lock Precedence ..............................................................................................................................90 Persistent Lock Request Handling......................................................................................................................................................................................................................................................................................

Locks and Transactions Locks and transactions are conceptually related. short locks are held for short amounts of time.) A short lock does not survive a system disruption. Short locks are released when a short transaction ends with a commit or rollback. controlled. for convenience in managing short locks. you would not have to be concerned with locks. such as many minutes. by definition. Persistent locks and long transactions Long transactions manage checkin/checkout operations that take a long amount of time. Persistent locks are not tightly coupled with long transaction checkouts. "short" transactions do not have to be short. However. at times when you are the sole user of a database. short transactions typically define units of work that take a short amount of time. Typically. If you were to be the sole user of a database. 67 . and predictable manner. locks are essential in a multi-user environment. Accordingly. A persistent or long lock manages concurrency during a long transaction. A persistent lock has all the features of a short lock plus added functionality. for concurrency reasons. Short locks and short transactions Short transactions are. database session. or weeks. such as seconds or minutes. units of work in which concurrency is provided by short locks. You can also set a persistent lock if you want to use an object during an extended period of time without checking an object out. such as the ability to survive the end of a short transaction. And. you may want to turn locking off for the database and ignore locks entirely. hours. days. However. Ending a session also ends the current short transaction (you can specify ending a session with either a short transaction commit or rollback. and a system disruption. VERSANT Database Fundamentals Manual Short Locks Lock Overview Locks provide guarantees which allow multiple processes to access the same objects in the same database at the same time in a cooperative. since VERSANT provides mechanisms for upgrading and downgrading locks on specific objects and for writing specific objects to a database.

68 . an object can have only one lock on it at a time. Placing a lock on a class object has the effect of placing the same lock on all instances of a class. versioned objects. A lock provides an access guarantee. An exception to this rule occurs if you are using multiple processes in the same session. Locking an object does not lock objects which are the targets of links in the locked object. In this case. locks are applied at the object level. This is far faster than retrieving all objects of a class and placing individual locks on each object. For example. Locks can be set on all kinds of objects: instance objects. Locks are applied to objects. and class objects. To maximize concurrency. Any object can be locked. The access guarantee is provided by blocking certain kinds of actions by other users. Locks have precedence. The precedence of locks is: write > update > read > null. Linked objects are not locked. the read lock is replaced by a write lock. different processes can place different locks if they are compatible. different processes can request and receive a read lock and an update lock on the same object. If you separately request different locks on the same object. if you request a write lock on an object for which you already hold a read lock. the read lock request is ignored. An object can have only one lock in a transaction. Locking a class object locks all objects of the class. A lock on an object provides an access guarantee. but the net effect is the same to outside users: the highest lock prevails. see the section "Persistent Lock." Short Lock Features Following are features of VERSANT locks. For example. the lock placed depends upon the relative precedence of the locks. In a particular transaction. if you request a read lock on an object for which you already hold a write lock.VERSANT Database Fundamentals Manual For more information on persistent locks.

c WLOCK c++ WLOCK Short update lock An update lock allows you to read an object and get the next available write lock on it. update. Short Lock Types Following are the types of short lock modes and their access guarantees. read. Strict two two-phase -phase locking is used. By "two-phase" is meant that all locks are gathered in one phase and then released in a second phase. You can override the VERSANT implicit locking strategy in several ways. Short write lock A write lock guarantees that you are the sole user of an object and that you are looking at the current state of an object. and/or change the lock wait time. that request may cause a deadlock error that they must handle or have their application terminated. or update lock on a particular object. when the transaction ends. Strict locking prevents other applications from modifying an object while you are using it and is the appropriate strategy in a multiple user environment. VERSANT uses a strict. By default. You can turn locks off. It does not block other requests for a read lock. A request for an update lock is 69 . You can enable or disable short locks. You can explicitly upgrade locks. An update lock provides its guarantee by blocking all other requests for a write or update lock. but if another user tries to change a read lock to a write lock. It is useful when you want to update an object. For example. or write lock. VERSANT Database Fundamentals Manual Locking an object also prevents the class object from being changed. A write lock provides its guarantee by blocking all other requests for a write. change the default lock. When you place a read. Implicit locking is used. A request for a write lock is blocked if the object already has a read or update lock. VERSANT internally places a special kind of lock on the class object which prevents it from being changed while the instance object is locked. By "strict" is meant that locks are set before work starts rather than at commit time when locks might not be available. marking an object as dirty automatically obtains a write lock. VERSANT uses an "implicit" locking strategy in which methods automatically obtain locks as needed. It is useful if you want to look at an object now while knowing that you will later want to update it. two-phase locking strategy.

A read lock provides its guarantee by blocking all other requests for a write lock. read. 70 . is not a lock at all." because there are no guarantees that the object will not be changed while you are looking at it. provides no access guarantees and. Specifying a null lock is useful when you want to look at the current state of an object without placing a lock or waiting for other locks to be released. A request for a read lock is blocked if the object already has a write lock. a null lock does not block other requests for a write. strictly speaking. also called a "snapshot" lock. Looking at the current state of an object without placing a lock is sometimes called a "dirty read." Short read lock A read lock guarantees that an object will not be changed while you are looking at it. see the following section "Locking Protocol. A request for a null lock is never blocked.VERSANT Database Fundamentals Manual blocked if the object already has a write or update lock. That is. c ULOCK c++ ULOCK For a further explanation of the importance and usage of update locks. c RLOCK c++ RLOCK Short null lock A null lock. c NOLOCK c++ NOLOCK Short Lock Interactions Blocking of locks The following summarizes how short locks interact. It does not block other requests for a read or update lock. or update lock. It is useful when you want to look at an object but not change it.

If your request times out. a read lock is not granted on an object that already has a write lock. 71 . you will receive a "lock timeout" error. For example. since turning locking off for a database disables short locks but has no effect on persistent locks. single-database deadlocks with any number of clients and any number of locked objects. If your request for a short lock is blocked by an incompatible short or persistent lock. It differs if you have turned locking off for a database. and the second user receives a "would-cause-deadlock" error message. the system immediately tries to obtain it. For example. The length of time a request waits is determined by the value of the lock_wait_timeout parameter in the Server Process Profile. that if locking has been turned off. Deadlocks Potential deadlocks are detected immediately and a "would-cause-deadlock" error is sent to the user creating the potential deadlock. your application pauses either until the object becomes available or until your request times out. If your request succeeds. for example.) VERSANT directly handles complex. the first user would receive the lock if a lock wait time-out did not occur. This means. if two users have read locks on an object and then both request a write lock. Since the lock mode of a persistent lock specifies a matching short lock. • There are no persistent locks with an incompatible lock mode. but you will be able to set a persistent write lock which will have the same effect as a short write lock. the first user to request a write lock is blocked. VERSANT Database Fundamentals Manual When you request a short lock. you will not be able to set a short write lock. (In this case. the system places your short lock immediately. A short lock is granted on an object if the following conditions are true: • There are no incompatible short locks. (An example of a "complex" deadlock is "A waiting for B waiting for C waiting for D waiting for A".) VERSANT uses timeout mechanisms to detect multiple database deadlocks. this condition is usually similar to the first condition.

c o_acquireilock() set intention lock o_acquireplock() set persistent lock o_checkin() check in objects o_checkinreturnobjs() check in objects o_createvsn() create version o_deleteobj() delete object o_deletevsn() delete version o_dropattr() drop attribute o_dropclass() drop class o_dropinst() drop instances o_gcheckout() check out objects o_gdeleteobjs() delete objects o_getclosure() find object and linked objects o_greadobjs() get objects o_locateobj() get object o_locatevsn() get version o_new_attr() create attribute o_pathpcheckout() find and checkout object o_pcheckout() find and checkout object o_preptochange() set object dirty o_preptoversion() create versioned object o_refreshobj() refresh object o_refreshobjs() refresh objects o_renameattr() rename attribute o_select() find object o_setdirty() dirty object c++ (type*)() cast link acquireilock() set intention lock 72 . c o_acquireslock() set short lock o_upgradelock() upgrade lock c++ acquireslock() set short lock upgradelock() upgrade lock Set short lock implicitly The following set a short lock implicitly or allow you to specify a short lock in a parameter.VERSANT Database Fundamentals Manual Short Lock Actions Set short lock explicitly The following set a short lock explicitly.

c o_endsession() end session o_endtransaction() commit or rollback o_exit() exit process o_xact() commit or rollback o_xactwithvstr() commit or rollback 73 . VERSANT Database Fundamentals Manual acquireplock() set persistent lock checkin() check in object createvsn() create version delete delete object deleteobj() delete object deletevsn() delete version dirty() set object dirty gcheckout() check out objects gdeleteobjs() delete objects getclosure() find object and linked objects greadobjs() get objects locateobj() get object locatevsn() get version operator*() dereference link or pointer operator ->() dereference link or pointer operator delete delete object pcheckout() find and checkout object preptochange() set object dirty preptoversion() create versioned object refreshobj() refresh object refreshobjs() refresh objects select() find object setdirty() dirty object Release short lock explicitly The following release short locks explicitly. c o_downgradelock() downgrade lock c++ downgradelock() downgrade lock Release short lock implicitly The following release short locks implicitly.

VERSANT Database Fundamentals Manual c++ abort() rollback commit() commit endsession() end session exit() exit process rollback() rollback xact() commit or rollback xactwithvstr() commit or rollback 74 .

checkpoint commit pin object release object set savepoint undo savepoint unpin object write objects zap object cache Short Lock Protocol The goal of a locking protocol is to maximize concurrent use of objects. You can reset the default. Of course. This allows others also to read the object. • Use a read lock for objects that you know you do not want to modify. To avoid deadlocks and maximize concurrency. then request a null lock. the state of the object you get may become obsolete almost immediately. the default short lock is a read lock. VERSANT Database Fundamentals Manual Get default short lock c++ get_default_lock() get default lock Set default short lock When a session begins. and neither transaction can continue because both are waiting for the other to release their read lock. but if not followed by all users. You will then get the object with no waiting and no blocking. c o_beginsession() begin session o_setdefaultlock() set default lock c++ beginsession() begin session set_default_lock() set default lock No effect None of the following affects short locks. A "deadlock" occurs when two transactions both hold read locks on the same object. 75 . both transactions then attempt to upgrade their locks to a write lock. unexpected situations may occur. Locking protocols are voluntary. the following voluntary locking protocol is recommended: • If you want to snapshot read the current state of an object.

This keeps your write lock as short as possible. If you decide to change the object. The idea is to avoid a situation where one application asks for its locks starting with the beginning of a list of objects and another application asks for its locks starting with the end of the same list of objects (in which case. 76 . Time 3 — Other users release their read locks by committing or rolling back their transactions. because this can create a deadlock situation. • If you want to immediately change an object. both applications would get some of the objects needed. then request a write lock at that time. Example using a write lock Time 1 — Other users have a read lock on an instance. This allows others also to read the object. and you obtain a write lock on that instance. • If multiple applications are accessing the same group of objects.) Following are examples of typical usage of short locks. • Never upgrade directly from a read to a write lock. but both would be blocked from getting all needed objects. Time 6 — You commit the change and release the write lock. your application resumes. The request is blocked and your application waits until the request can be granted or the request times out. do not upgrade from a read lock to an update lock: get an update lock right from the beginning. Time 2 — You want to update the same instance. Time 4 — If your request has not timed out. then you might also want to develop a protocol in which the different applications and/or transactions lock objects in the same order. Also. so you ask for a write lock on it. C++ — Dirtying an object is the same as requesting a write lock.VERSANT Database Fundamentals Manual • Use an update lock to read objects that you may later modify. Time 5 — You change the instance. then request a write lock from the beginning.

Time 4 — The first user requests a write lock. your application resumes and acquires an update lock. Time 3 — You decide that you want to read and then update the same object. VERSANT Database Fundamentals Manual Example using a read lock Time 1 — Someone has a write lock on an instance of a class. "You" and "UserB" 77 . your read lock on the class object is now granted and coexists with other read locks on instances of that class. and they all have read locks on that object. and many others have read locks on other instances of the same class. If your request has not timed out. Time 6 — The other user finishes. Example that violates locking protocol The following example illustrates lock interactions and lock precedences. This means that no other user can modify any instance of the class. although you would not be guaranteed to be looking at the latest state of the objects. Time 5 — You can now print your report knowing that you are dealing with the latest state of all objects at that moment in time. Time 2 — Someone decides to first read and then update an object and requests an update lock. Time 2 — You want to create a report using the latest state of all objects at a particular moment in time. so you request an update lock. Time 5 — Other users with read locks finish and the user with the update lock gets a write lock. Your application waits. and the object becomes available. but your request is blocked by the write lock on one instance of the class. Your application waits until the request can be granted or until the request times out. In the example. Time 3 — The user with a write lock on the instance executes a commit. which releases the write lock. Time 4 — If your request has not timed out. if you are creating a report. You are now guaranteed to be the next person to get a write lock on that object. If the request times out. But everyone has decided to follow recommended locking protocol for updates. Example using an update lock Time 1 — Numerous users are using a particular object. You may also get an inconsistent set of objects. This lock upgrade request is blocked by existing read locks by other users. The request is blocked because an update lock already exists on that object. You request a read lock on the class object. The request is granted even though other users also have read locks. you might want to consider asking for a null lock on the instances to gain immediate access.

UserB waits because you have an update lock. When you dereference an object in the array and bring it into memory. Short Locks and Queries A query will return an array containing links to the returned objects. Time 4 You request an upgrade to a write lock per recommended protocol. even though you follow the recommended protocol. Time 2 You request an update lock. Time 3 You have an update lock. 78 . UserB requests a write lock in violation of protocol. UserB gets the write lock and continues. The recommended protocol is for UserB to request an update lock at Time 1. because two users are now waiting for a write lock. UserB still has a read lock. You get a "would cause deadlock" error. Time 5 Unless you handled the error and rolled back your transaction. your application continues to get a "would cause deadlock" error.VERSANT Database Fundamentals Manual both try to use the same object. UserB gets a read lock on the object. In the example. Even though you followed the recommended protocol. the default lock will be set on the object. Time 1 You have done nothing yet. your work is disrupted because "UserB" does not follow the recommended protocol. UserB continues to wait for a write lock. You get the update lock. UserB requests a read lock.

Some will set the default lock on a class. because VERSANT automatically sets them on class objects whenever you set a lock on an instance object. This is a topic you do not need to understand in order to use VERSANT. an intention lock on a class object has no direct effect on instance objects. For example. if you set a read lock on an object. a corresponding intention lock must also be set on the class object. an intention read lock on a class object prevents it from changing. The effect will be the same as setting a read or write lock on all instances of the class and subclasses involved in the query. If you want to lock all objects of the classes involved in the query. which will be done automatically when you dereference the links. To maximize access to objects. 79 . In that case. If you do not want to lock objects returned by the query until you dereference them. but an intention read lock does not block an intention write lock. Intention locks are relevant only to class objects. If set to TRUE. Intention locks have the same effect on a class object that a normal lock has on an instance object. an intention read lock on a class object does not block a write lock on an instance of that class. VERSANT Database Fundamentals Manual Depending on your interface language. For example. only on the class object. your choice of short lock will be set on both the class object of the query class and on the class object of each subclass instance returned by the query. because to place a lock on an instance. then you may need to know about intention locks. intention locks on class objects have an important indirect effect on instances. If you have specified either an intention lock or have specified a null lock in a query statement. The purpose of intention locks is to prevent changes to class objects while you are using an instance of the class. You do not need to know about intention locks unless you have special concurrency needs. and others will let you set an instance and/or class lock. Intention locks are set implicitly on class objects when you request a lock on an instance. called an "intention read lock". there may be several forms of a select routine. VERSANT actually only sets a read or write lock on the class objects for the instances returned. The effect is to prevent the class objects from being changed while you are looking at their instances. You can set an inheritance flag in a select statement. although. However. You can place a normal or intention lock on a class object. then you must place instance locks separately. then specify a read or write lock in the query method. If your concurrency needs are unusual. VERSANT will set an intention read lock on the class object. VERSANT will set a special kind of read lock. For example. to improve performance. Short Intention Lock Description This section explains intention locks. except that intention locks do not block one another. the inheritance flag will cause the query to evaluate instances of both the specified class and also its subclasses. then do not specify a short lock mode. If you do set the inheritance flag.

Intention read lock An intention read lock on a class object prevents it from being changed. 80 . A request for an intention read lock on a class object is blocked only if it has a write lock. You should not set intention locks on instances. It will not be blocked by another intention read or intention write lock. They will also still be able to read the class object.VERSANT Database Fundamentals Manual If you use a query routine without specifying a lock mode argument. or write lock. An intention write lock is set implicitly by VERSANT on a class object when you request a write lock on an instance of the class. If you have an intention read lock on a class object. this is not good practice. An intention write lock is useful when you want to prevent the class object from being changed or read. However. update. then the intention lock equivalent of the current default short lock is placed on the class objects for the instances returned. as soon as you try to do something meaningful. An intention read lock is set implicitly by VERSANT on a class object when you request a read lock of an instance of the class. other users can still use instances of the class in a normal manner. and a write lock on an instance of the class. An intention read lock on a class object is compatible with an intention write lock on the class. such as using the "get attribute" routine in C/VERSANT or dereference an object in C++/VERSANT. An intention read lock is useful if you want to prevent others from changing a class object while you are using instances of the class. Short Intention Lock Mode VERSANT defines the following intention lock modes. Although setting an intention lock has the same effect as a normal lock. an appropriate lock is set. c IRLOCK c++ IRLOCK Intention write lock An intention write lock on a class object prevents other users from reading or updating it but allows them to use instances of the class. The terms "intention read lock" and "intention share lock" are synonymous. A request for an intention write lock on a class object is blocked if it has a read.

The terms "read with intention to write lock" and "share with intention exclusive lock" are synonymous. 81 . c RIWLOCK c++ RIWLOCK Short Lock Precedence The following shows lock precedence for both normal locks and intention locks. has the highest precedence. A null lock has the lowest precedence. VERSANT Database Fundamentals Manual The terms "intention write lock" and "intention exclusive lock" are synonymous. A write lock. c IWLOCK c++ IWLOCK Read with intention to write lock A read with intention to write lock prevents a class object from being changed and has the same effect as placing read locks on all instances of the class. at the top.

82 . These interactions are the same for both instance and class objects. multiple read locks on the same object are compatible. This behavior means that • The definition of a class cannot change while an object is locked. you must also get an intention read lock on the class object. For example. the guarantees of the new lock must be compatible with the guarantees of any existing locks. so that the process with the write lock is the sole user of the object. but an object can have only one write lock. a write lock blocks a read lock. a write lock blocks an intention read lock. For example. The interactions of normal locks are relatively straightforward. For example. Because instance locks cause class object intention locks: • A lock on an instance object can block a request for a lock on a class object. the guarantees of the new intention lock must be compatible with the guarantees of any existing locks. because a read lock on an instance also sets an intention read lock on the class object. To provide their guarantees. There can be two kinds of lock interactions: Interactions of normal locks Interactions of normal locks occur when a process requests a lock on a object that already has a lock: to be granted.VERSANT Database Fundamentals Manual Short Lock Interactions A lock provides a guarantee for a specific set of actions. a read lock on an instance of a class blocks a request for a write lock on a class object. The interactions of normal and intention locks are more logically indirect. Interactions of normal and intention locks Interactions of normal and intention locks occur when a process requests a lock on an instance and the system then attempts to place a matching intention lock on its class object: to be granted. For example. a write lock on a class object blocks a read lock on an instance of the class because to get a read lock on an instance. certain kinds of locks block other locks. and an intention read lock blocks a write lock. • Locking a class object with a normal. • A lock on a class object can block a request for a lock on an instance object. However. non-intention lock has the effect of locking all instances of a class.

intention write lock Blocks write. the creation of the first instance of an empty class is treated as a special case. and update locks. The following table summarizes how locks interact.0. read/intention write. intention read read/intention write Blocks write. update. inten. VERSANT acquires an "Intention Write Lock" on the class object in order to prevent the class definition from being changed while you are creating or modifying an instance of that class. VERSANT Database Fundamentals Manual Locks interact in the following ways. update lock Blocks write. and read lock locks. 83 . intention write. read/intention write. and read locks. intention read lock Blocks write lock. update. and intention write locks. null lock Blocks nothing. inten. read/intention write. read.0. read lock Blocks write. write lock Blocks write. update. intention write. when you create or modify an instance of a class. blocks blocks blocks blocks blocks write intention write blocks blocks blocks blocks update blocks blocks blocks blocks read blocks blocks blocks intention read blocks null Short Locks and the First Instance Implicit Write lock on class object when inserting first instance Normally. Interactions write write write update read read null write blocks blocks blocks blocks blocks blocks read/inten. An Intention Write Lock allows multiple transactions to create or modify instances. intention write. Short read/ Lock inten. Beginning with Release 6. read/intention write. read/intention write.

84 . This situation rarely occurs in production applications. because this behavior may mean that you may need to add application code to handle a deadlock or lock timeout. VERSANT acquires the much stronger Write lock on the class object. but it creates the possibility of a deadlock or lock timeout should multiple transactions try to simultaneously insert instances on a previously empty class. The dummy instance can later be deleted. You may need to be aware of this behavior if you are installing a new production database or working in a development environment. This change eliminate all possibilities of transaction inconsistencies when inserting the first instance of a class.VERSANT Database Fundamentals Manual When inserting the first instance. whenever you define a class. Alternately. because the case of an empty class is not common. This stronger lock will block all other transactions trying to insert instances. you might want to insert a dummy instance and commit the change to initialize the class. after other instances have been created.

Because persistent locks imply a short lock. Persistent write lock As with a short write lock. Queuing What happens if an object already has a blocking lock. Other users cannot check out the same object. Lock level Whether your lock can be broken by another user. the copy in the personal database replaces the source object. When you check in a write locked object. A checkout of an object with a write lock creates a copy of the locked object in your personal database and places a persistent write lock on the object in the group database. Persistent locks imply a short lock and have additional functionality. A write checkout does not change the identity of the object. 85 . VERSANT Database Fundamentals Manual Persistent Locks Persistent Lock Description Persistent locks span transactions and sessions and survive a system disruption." Persistent Lock Mode Following are persistent lock mode options. see also the section "Short Lock. Persistent locks have the following elements: Lock mode Short lock functionality. Notification Notification if certain events occur. Each of the above persistent lock elements is explained in a following section. a persistent write lock guarantees that you are the sole user of an object.

When you end the long transaction with which the checked out object is associated. A checkout of an object with a read lock creates a copy of the object in the personal database and places a persistent read lock on the object in the group database. Other users can also check out an object that has a persistent read lock. A read checkout does not change the identity of the object. and the lock on the source object is released. any requests for a hard or soft lock level or for a particular queuing option are ignored. When you check in a read locked object. a persistent snapshot lock provides no access guarantees and is really no lock at all. the copy in the personal database is not dropped. but they cannot modify it. c O_PL_READ c++ O_PL_READ Persistent null lock As with a short null lock. Explicitly checking in an object checked out with a null lock is the same as migrating an object to a new database. It is useful when you want just to view data in its current state without modifying it and do not want to wait for release of any lock placed by another user. a persistent read lock guarantees that an object will not change.VERSANT Database Fundamentals Manual c O_PL_WRITE c++ O_PL_WRITE Persistent read lock As with a short read lock. A null lock checkout creates an unlocked copy of the object with a new object identifier. A checkout of an object with a null lock creates a copy in your personal database without regard to its current lock state and without placing a lock yourself. If you request a null lock in association with a checkout. the copy in the personal database is dropped. 86 .

which means that there is already an incompatible persistent lock on the object. Persistent lock wait If the object is not available for locking. If the object becomes available before the request times out. VERSANT will immediately return the error message 87 . you can specify queuing options that cause your application either to wait.be. or give up. Persistent Lock Queuing If a persistent lock request cannot be granted immediately. then the lock request will be granted. VERSANT Database Fundamentals Manual c O_PL_NOLOCK O_PL_SNAPSHOT c++ O_PL_NOLOCK O_PL_SNAPSHOT Persistent Lock Level You can set a persistent lock level of hard or soft. c O_PL_SOFT c++ O_PL_SOFT When you try to commit a transaction involving an object with a broken lock. c O_PL_HARD c++ O_PL_HARD Persistent soft lock A soft level means that your persistent lock can be broken by another application process. an error occurs. then the error message OM_LO_BE_INCOMPAT will be returned. If the object is not available after the request times out. place a lock reservation. The length of the time-out period is determined by the value of the server process parameter lock_wait_timeout in the database server profile file profile. c O_PL_WAIT c++ O_PL_WAIT Persistent lock reserve If the object is not available for locking. Following are the queuing options. Persistent hard lock A hard level means that your persistent lock cannot be broken by another application process. VERSANT will keep trying to obtain the lock until the request times out.

and then place a lock reservation on the object. c O_PL_LOCK_BROKEN c++ O_PL_LOCK_BROKEN st #LOCKBROKEN Persistent lock pending Send notification when someone else is waiting for your lock. and make no further attempts to acquire the lock. c O_PL_NO_BLOCK c++ O_PL_NO_BLOCK Persistent Lock Event Notification You can request notification if your persistent soft lock has been broken. c O_PL_RESERVE c++ O_PL_RESERVE Persistent lock give up If the object is not available for locking. which means that there is already an incompatible persistent lock on the object. Placing a lock reservation on an object means that a notification message O_PL_OBJ_READY will be sent when the object becomes available. VERSANT will immediately return the error message OM_LO_BE_INCOMPAT. if someone else is waiting for your persistent lock.VERSANT Database Fundamentals Manual OM_LO_BE_INCOMPAT. c O_PL_REQ_PENDING c++ O_PL_REQ_PENDING st #REQPENDING 88 . Getting the O_PL_OBJ_READY message does not mean that you now have a lock: you must repeat your lock request and that request will be evaluated again in the context of any other locks that exist at the moment when the request is made. or if your reserved object is now ready: Persistent lock broken Send notification when your soft lock is broken by another user. which means that there is already an incompatible persistent lock on the object.

VERSANT Database Fundamentals Manual Persistent lock object ready Send notification when an object is ready. c O_PL_OBJ_READY c++ O_PL_OBJ_READY st #OBJREADY Persistent lock event notification description The persistent lock event notification options can be combined with the logical OR operator. The To: field identifies the user affected by the event. You can also monitor objects for object related events by using a separate "monitor object" statement. Electronic mail notifications have the following general format: Versant Event Notification: To: user@host From: user@host Event: event Object: object identifier in "dbname" The From: field identifies the user who generated the event. or committed an update on an object previously checked out in write mode. c o_monitorobj() c++ monitorobj() st monitorOnEvents: 89 . Monitoring an object tells you if another application process has versioned an object. notification when an object is checked out in read mode. Event notifications are normally sent in the form of electronic mail. The system evaluates your outstanding message requests each time a short transaction ends with a commit or rollback. but is not limited to. Monitor object You can also monitor objects for object related events by using a "monitor object" function or method. The read option includes. read an object. For instructions on how to customize event notification. please call Versant Technical Support. but you can customize event notification.

This parameter is reserved for future use. Persistent locks are always enabled. they are granted in two steps: 1. you cannot set a persistent lock on an object in a personal database. • Either there are no persistent locks with an incompatible lock mode. but not always. For example. or there are only persistent lock reservations with lock modes incompatible with other active locks. other users will be blocked by the persistent write lock just as if you had set a short write lock. Persistent lock attempt At the next commit or checkpoint commit. what happens 90 . Persistent locks are usually. or all persistent locks with an incompatible lock mode have a soft lock level and you have requested a hard lock level. if you have a persistent write lock on an object. 2. lock precedence and interaction rules apply to persistent read and write locks as if they were short read or write locks. This means that you can set persistent locks even if short locking has been turned off in a group and/or personal database. If you are not immediately granted a short lock matching your persistent lock mode parameter. the system tries to set your persistent lock. Persistent locks are not set immediately upon request. Rather.VERSANT Database Fundamentals Manual C/VERSANT — Some functions require use of a an "intent" parameter. A short lock matching the lock mode specified in your persistent lock request is granted if all of the following conditions are true: • There are no incompatible short locks. Persistent Lock Precedence Since setting a read or write lock mode in a persistent lock has the same effect as setting a read or write short lock. used in conjunction with object checkouts. Turning locking off for a database disables short locks but has no effect on persistent locks. • Either you have reserved the object with a persistent lock compatible with all active persistent locks. Persistent Lock Request Handling Because personal databases allow only a single user. even if you have turned locking off in the server process profile for a database. Short lock attempt The system immediately tries to set a short lock that matches the lock mode specified in your persistent lock request and then logs your request for a persistent lock. even if short locking has been turned off in its database.

If you are granted a short lock that matches your persistent lock mode parameter: • A subsequent short transaction rollback will drop both the persistent lock request and the matching short lock. then your lock continues until you release it. VERSANT Database Fundamentals Manual next depends upon other parameters you have supplied: • If you have specified either "give up" or "place reservation if blocked" in the lock wait option of your persistent request. • If you have specified "wait" in your lock wait option. After your persistent lock request has been granted. The notifications you will receive depend upon your notification options: Lock broken If you specified the "lock broken" option when you made the lock request. What happens to your lock depends upon your level: Hard lock level If you have a hard lock. 91 . then you will be notified immediately if your lock is broken. Soft lock level If you have a soft lock. your queuing options are irrelevant and what happens next depends on your lock level and your notification requests. then your entire persistent lock. then you will be notified if another user is waiting for your lock. Request pending If you specified the "request pending" option when you made the lock request. then the system gives up immediately. the system keeps trying until the request is timed out. An error will be raised if you try to checkin an object with a broken lock or if you try to commit a long transaction with which a broken lock is associated. then your lock can be broken at any time by a request made by another application process for an incompatible hard lock. • A subsequent undosavepoint has no effect on either the short lock or the persistent lock request. and event requests. wait. • A subsequent short transaction commit or checkpoint commit records the persistent lock in the database. is granted and logged. including the level. If at commit time the requested objects have still not been locked at a harder level by another user. An error will also be raised if you try to check in an object with a broken lock or if you try to commit a long transaction with which a broken lock is associated.

If the object is not available after the request times out. but the system keeps trying until timed out. suppose you request the following persistent lock: Lock mode — read Lock level — hard Wait option — wait Upon receiving this request. If you request another persistent lock for the same object in the same short transaction. If timed out. the system immediately logs your request and then tries to get a short read lock. for example. For example. No wait option If you specified the "no wait" option. Whether you wait or not depends on your queuing options: Wait If you specified the "wait" option. For example. the system may or may not retry to gain the lock: • The system will retry if you request a lock level with higher precedence than you already have. at the next commit. if you have a persistent read lock. • If a short read lock exists: You immediately get a short read lock. if you have a write lock. VERSANT will keep trying to obtain the lock until the request times out. If nothing else changes. • The system ignores a request for a lock with a lower precedence level than a lock that has already been granted. • A request to unlock a persistent lock. is always granted at the next commit. • If a short write lock exists: Then you are blocked. an unlock request does not immediately release any existing short locks in case it is followed by a higher level request. you receive a "lock 92 . you get your persistent read lock. you will immediately receive the error message OM_LO_BE_INCOMPAT. However. a request for a read lock is ignored. your lock level options become irrelevant and what happens next depends on your queuing and notification requests. if last in a sequence of requests in a short transaction. you will receive the error message OM_LO_BE_INCOMPAT.VERSANT Database Fundamentals Manual If your persistent lock request is not granted. the system retries if you request a persistent write lock.

• If a persistent read lock exists: You immediately get a short read lock. and the system keep trying until timed out. that user receives an error message. As soon as the other user performs a checkin or long transaction commit. Persistent Lock Actions Set persistent lock c o_acquireplock() set persistent lock o_gcheckout() check out object o_pathpcheckout() check out object o_pcheckout() check out object c++ acquireplock() set persistent lock gcheckout() check out object pcheckout() check out object Persistent locks are not set until a commit or checkpoint commit occurs. • If a persistent hard write lock exists: You are blocked. at the next commit. at the next commit. If nothing else changes. the persistent lock is released at the next commit or checkpoint commit. you get your persistent read lock. • If a persistent soft write lock exists: You immediately get a short read lock. 93 . VERSANT Database Fundamentals Manual timeout" error. If nothing else changes. Release persistent lock c o_checkin() check in objects o_checkinreturnobjs() check in objects o_endsession() end session o_releaseplock() release persistent lock c++ checkin() check in objects endsession() end session releaseplock() release persistent lock After a request to release a persistent lock. you get your read persistent lock.

C++/VERSANT — Persistent locks are described in an instance of VLockDesc. 94 .VERSANT Database Fundamentals Manual Persistent Lock Description C/VERSANT — Persistent locks are described in the o_lockdesc data type.

............. 107 Error Messages that are Incomplete............................................................................................................................................ VERSANT Database Fundamentals Manual Chapter 6: General Programming Notes This chapter contains general programming rules and usage notes relevant to all interfaces............................ Name Rules.......................................................................................................................................................................... 101 Deleting a Class .............................................................................. 101 Overview ........................................................ 101 Adding a Class .................................................................................................. 104 Verifying Schema ........................................................................... 102 Adding.............. 106 Application Failure ... Please refer to the respective language (C/C++/JVI) reference manuals for further details.. 102 Changing an Inheritance Tree ..................................................96 Session Firewall .................................................................................................................................................................................................................. Deleting or Renaming an Attribute ......................................................................................................................................................................... 100 Schema Evolution ............................................................................................................................................................................................................................ 105 Mixing Releases......................... 103 Propagating Schema Changes................................................................................................................................................................................................................................................................................ 108 95 .......99 Database Connection Rule .................................................................................... 103 Changing an Attribute's Data Type ............................. 101 Renaming a Class ...........................................................

should be null terminated. should be null terminated. also limited by compiler Method 16.268. 96 . Name of an attribute Attribute names should be unique to their class and superclasses. default is user name Short transaction 31. also limited by compiler Attribute 16.VERSANT Database Fundamentals Manual Name Rules Name length Maximum name lengths and default values imposed by VERSANT are: Name Maximum number of characters Site 223. When objects are checked out or migrated. default is user name Long transaction 31 less username less 1.cxx implementation per your operating system and compiler Class 16. default is user name (VERSANT internally appends !username to any name you specify) Name characters VERSANT does not allow spaces in names. Name of a class Class names should be unique to their database. should be null terminated. Name of remote database Specify a remote database with dbname@site syntax. class names cannot conflict with existing class names in the target database. including login and database names. should be null terminated. also limited by compiler Session 31. should be null terminated .268.h specification file per your operating system and compiler . should be null terminated User 31 Database 31.268.

97 . Logical object identifiers for new objects are generated from the session database. Name for null database C++/VERSANT — In every C++/VERSANT method except beginsession(). VERSANT Database Fundamentals Manual Specifying a name with a variable C/VERSANT and C++/VERSANT — When using a variable to supply a name. Names returned to a vstr C/VERSANT and C++/VERSANT — Several methods and functions. The query and index methods that need a precise name are select(). remember to deallocate the vstr memory using a routine such as o_deletevstr(). you can create a dictionary whose values are a list: VEIDictionary<o_u4b. For example: newAttrName = malloc(sizeof("ANewNameOfAnyLength")+1). Remember to add one character for the null terminator. so you should specify a database when you begin a session with beginsession(). as in Employee::age. persistent object with O_NEW_PERSISTENT() creates that object in the current default database. return names to a vstr. For example. such as o_classnameof(). since creating a new. you must first allocate memory for the variable with malloc() or the equivalent for your operating system. When you begin a session with the PDOM beginsession() method. When you are finished using the names returned in the vstr. It does change the database in which objects are created. Before a session starts. Name of nested collection C++/VERSANT — C++/VERSANT allows you to nest Collection classes to any depth. you can specify NULL to use the default database. o_err o_renameattr(.. You can later change the default database by using the PDOM::set_default_db() method. This precise name qualifies the attribute name with the class name. the database specified becomes the session workspace and the default database. even if it is not the default database. there is no default database. Changing the default database does not change which database is being used as a session workspace..VIList<myObject> > Name of attribute in query and index methods C++/VERSANT — Methods which query or index on an attribute need a precise database attribute name even when referring to a private attribute. whenever you see a database name argument.

Precise attribute names are needed by these methods. Even if there is no initial ambiguity. and deleteindex(). classes may later be created which do cause ambiguity.VERSANT Database Fundamentals Manual pcheckout(). because a derived class could conceivably inherit attributes with the same name from numerous superclasses along one or more inheritance paths. createindex(). 98 .

The only exceptions are functions and methods that set session parameters. VERSANT Database Fundamentals Manual Session Firewall You must start a session before using VERSANT functions. and persistent objects. 99 . methods.

After beginning a session. To change the default database. to connect with other databases. use a "begin session" function or method. To connect with the session database.VERSANT Database Fundamentals Manual Database Connection Rule You must explicitly connect with a database before accessing it. 100 . use a "set default database" function or method. use a "connect database" function or method. Connecting to a database does not change the default database.

VERSANT Database Fundamentals Manual Schema Evolution Overview For each class of object that is stored in a VERSANT database. The exceptional schema changes that require global conversions are noted below. This stored definition (schema) must be identical to the class definition in your program files to avoid unpredictable results. so references to affected objects remain valid after the conversion. For details. For this reason. and must therefore be inserted into an inheritance chain. This "lazy updating" feature spreads the cost of instance conversions over time. when you change a class definition. Adding a Class Adding a new class has no impact on existing objects in the database. The new class is defined in the usual language-specific way. The class name must be unique within the relevant databases. each intended subclass must be redefined and its instances must be converted. Most kinds of schema changes do not require explicit conversion of instances.sch file from . c o_defineclass() c++ Use schcomp utility to generate . The following summarizes the basic mechanisms and provides an overview of the language-specific variants. please see the reference manual for your language interface. existing instances of the changed class must adapt to the new definition. Each programming language requires different mechanisms for communicating schema changes to a VERSANT database. VERSANT automatically adjusts the object's structure to the current class definition as needed. All instances of the 101 . and avoids the need to shut out applications while global conversions are performed. lazy updating is preferable to manual conversion involving the creation of new objects. If the new class is intended to become a superclass of any existing class. Each time your applications access an object. For more language-specific detail. In addition. This section tells how to update stored class and instance objects with evolving class definitions. shown below. Lazy updating does not alter object identifiers.imp file Deleting a Class Deleting a class requires a language-specific drop-class method or function. so no special precautions are necessary. see "Changing an Inheritance Tree" below. the class definition is also stored.

if class B has an attribute Link<A> that references an instance of A. Add a new class that has the desired class name. deleting a class also deletes any class with an attribute containing a link to the class being dropped. as most other schema changes can. 3. however. as most other schema changes can. For example. Create and run a program to create instances of Publication based on instances of Book. and with it. all instances of Book. a multi-step conversion is required: 1. This prevents dangling references. 4. Create and run a program to create instances of the new class based on the instances of the old class. however. 102 . suppose you want to rename the Book class so its name is Publication: 1. substitute a reference to the equivalent publication. Therefore. 2. Repair any references to the old instances. With the C++/VERSANT interface. Rename the class whose inheritance chain is being altered (see "Renaming a Class" above). 2. based on the Book class definition. c o_dropclass() c++ dropclass() util dropclass Renaming a Class With the C or C++ interfaces. 3. then dropping A also drops B. 4. Delete the old class. 3. as well as subclasses and their instances. Delete the Book class.VERSANT Database Fundamentals Manual target class are deleted from the database. Add a new class that has the original class name and the new inheritance chain. For example. renaming a class invalidates instances in a way that cannot be accommodated via lazy updating. For each reference to a book. Add a new Publication class. a multi-step conversion is required: 1. changing a class's inheritance chain invalidates instances in a way that cannot be accommodated via lazy updating. Therefore. 2. Repair any references to the old instances. Create and run a program to create instances of the new class based on the instances of the old class. and with it the old instances. 4. Changing an Inheritance Tree With the C or C++/VERSANT interfaces.

2. subclass instances are also updated automatically. and with it the old instances. Delete the old class. but the steps differ depending on whether you are using a typed or untyped programming language. In C or C++. 5. VERSANT updates instances automatically as they are accessed. Rename Book to OldBook. Add a new attribute with the new data type. might also need to be removed from Book's definition. VERSANT Database Fundamentals Manual 5. the steps are: 1. Deleting or Renaming an Attribute You can add. Changing an Attribute's Data Type Changing an attribute's data type requires multiple steps. then use sch2db to update database. For example. Adding. If you modify the attributes in a superclass. o_dropattr(). delete or rename an attribute in a single step. such as price. Data in other attributes also is not affected. With the C++/VERSANT interface. adding or dropping an embedded class or struct requires manual conversion of the class and its instances. Add a new Book class that has Product as its superclass. Delete the OldBook class. 4. resulting in the following inheritance chain: Object Product Book The steps for accomplishing this conversion would be: 1. Rename the attribute. initializing a new attribute's value to zero or NULL. c o_newattr(). You want it to inherit from a newly created Product class. Use synclass() to synchronize other databases.) 3. suppose a hypothetical Book class currently inherits from Object. substitute a reference to an equivalent Book. Create and run a program to create instances of Book based on instances of OldBook. 2. and with it all instances of OldBook. 103 . o_renameattr() c++ Modify schema files. For each reference to an OldBook. (Product attributes. Data in a renamed attribute is not affected.

For example. When the data type is inferred. Add a new attribute named price. This lazy updating mechanism spreads the cost of schema evolution over time. you would need to create an informal program to fetch each old object. The few exceptions to this rule are noted in the discussions of specific kinds of changes above. however. no special action is required: VERSANT accommodates values of any recognized data type automatically. If the class is already defined in both the source and target databases. Class changes that are propagated in this way do not affect object identifiers. Instances of a changed class. and stores the result in the price attribute. If an object is moved to a database in which its class has not been loaded. or of its subclasses. Create and run a program that casts each old-attribute value to the new data type. and then stores the resulting value in the new attribute. The C/VERSANT interface provides a 104 . If the database contains old instances. Propagating Schema Changes Communicating a schema change to one or more VERSANT databases depends on the programming language. Delete the oldprice attribute. an error is generated unless the two class definitions are identical. C Because the C language does not support class definitions. the C/VERSANT interface requires that you create a C program to implement each set of schema changes.VERSANT Database Fundamentals Manual 3. and then update the object in the database. 2. 3. this results in a mix of old and new data types for the attribute. so references to the affected objects within an application remain valid even after the class is changed. 4. In that case. with float as its data type. Rename the price attribute to oldprice. Create and run a program that casts each book's oldprice integer as a float. 4. Delete the old attribute. and avoids the need to perform a global sweep that would shut out normal database usage. are aligned with the new class definition only as they are accessed. No special action is required when migrating or checking in objects. to change the data type of Book's price attribute from int to float: 1. VERSANT automatically migrates the class object as well as the instance. recast the target attribute's value to the new data type. which may cause problems for your applications.

Each of the VERSANT interfaces for class-based languages. Verifying Schema At any given moment. Because of this potential for mismatch. see the C++/VERSANT Reference Manual. you can run the Schema Change Utility separately on each database. 105 . such as C++ provides a facility for confirming the schema. can also be used to report mismatches without making any changes. In each case. or run it on one database and then reconcile differences in other databases with the synclass() method. C++/VERSANT The Schema Change Utility (sch2db). such as o_dropclass() or o_renameattr(). depending on how recently and how rigorously you and other developers on your team have synchronized these two views of the schema. the nature of the facility is tailored to the development environment. especially on large. To reload a class definition in multiple databases. For details about the Schema Change Utility and the synclass() method. it's a good idea to confirm the schema before testing or deploying your applications. C++ In the C++/VERSANT interface. the Schema Change Utility (sch2db) is used to propagate changes in schema (. which is normally used to change class definitions in a VERSANT database so they match the definitions in schema files. multi-developer projects. the schema as known to the database may or may not be identical to the schema as known to your application code. This reporting feature is enabled with the -n flag on the command line that is used to invoke sch2db. VERSANT Database Fundamentals Manual specific method for implementing each type of schema change.sch) files to a database.

osc06yyzz to .zz database: • To access with VERSANT 5. Applications created with previous releases and linked with the VERSANT one process system library.oscxxyyzz file.0. and C Set++ compilers and with xlC compiler independent releases. although they can continue to access databases created with previous releases that exist on other machines. 106 .8 copy . Most objects can be shared C++ objects may be shared among applications created with Visual C++. libosc.0. your applications compiled with previous releases will only be able to access 6.osc050202.yy. the installation process will have created a file /etc/.osc06yyzz. After making this change.VERSANT Database Fundamentals Manual Mixing Releases Compatibility of Releases The following describes the compatibility of this release with previous releases. where yy is your minor release number and zz is your maintenance release number.osc06yyzz to .yy. On the machine containing the Release 6 database.osc050008.zz databases on the target machine. To invoke convertdb: convertdb databasename You must end all long transactions and then stop the database with stopdb before and after running convertdb. Release 5 databases can be converted to Release 6 databases using convertdb utility.2. • To access with VERSANT 5.2 copy . Some Release 5 applications can use Release 6 databases Applications linked with the VERSANT Release 5 two process system library. and delete objects in VERSANT Release 6 databases if you create a new . liboscfe. create. On the machine containing the 6. can access.a.0 databases. The purpose of this file is to tell VERSANT at runtime the location of its software root directory.a. cannot access VERSANT 6. update.

VERSANT will automatically rollback all incomplete transactions that may be corrupting the database and restore conditions to a consistent state. 2. Restart the database with startdb. If an application does not finish normally. To reset the database: 1. VERSANT uses shared memory and semaphores for its inter-process communications. shared memory resources may not be released. To release shared memory resources after a failed application: 1. then the next time you try to use the database. 107 . by using the UNIX ipcrm command. 2. you will have to forcibly stop the database. manually remove shared memory. If step 1 does not succeed. you will probably have to reset the database. VERSANT Database Fundamentals Manual Application Failure If an application terminates abnormally and you are running with logging turned OFF. call Versant Customer Support. This is because with recovery features turned off. You can use the UNIX ipcs command to verify that all shared memory and semaphores have been released. 4. 3. If logging and recovery are turned ON. Run the stopdb utility. Restart the database with startdb. If stopdb fails for some reason. VERSANT will not be given an opportunity to restore the database to a consistent state. if any. Run the stopdb utility. For information on how to forcibly stop a database.

then either your VERSANT installation is incomplete or needed environment variables have not been set correctly. See the "Installation" chapter in your Release Notes.VERSANT Database Fundamentals Manual Error Messages that are Incomplete If error numbers are displayed without an accompanying error message. 108 .

.................................. 117 Object Checkin......... 118 Object Checkin Overview............. Locks........................... 113 Object Checkout Overview.............................. 119 Object Checkin General Usage Notes .................................................................................................. and Versions ................................................ 111 Object Migration Actions....................... 116 Checkout General Notes ............................. 112 Object Checkout................................................................................................................................................................................................. Locks............................................................................................................................................................................... and Links ........ 118 Object Checkin Actions................................... VERSANT Database Fundamentals Manual Chapter 7: Object Movement Object Movement Overview ........................................ 113 Object Checkout Actions..................................................................................................................... Locks................................................................................................................................................................ and Versions ................................................................... 113 Checkouts...................................................... 114 Checkouts................................................................................................. 120 109 ........................... 110 Object Migration...................................................................................................................................................................... 118 Checkins.................................................................................................. 111 Object Migration Usage Notes ..........................................................

Object checkin A checkin moves a new or previously checked out object from a personal database to a group database. 110 .VERSANT Database Fundamentals Manual Object Movement Overview VERSANT allows you to move objects from one database to another with the following mechanisms: Object migration Migrating an object moves it permanently from one database to another. Object checkout A checkout creates an object in a personal database that is a copy of an object in a group datatabase.

Checkin routines You cannot use a checkin routine to migrate an object from a group database to another database. the object identifier of the object is not changed. To resolve differences in schema definitions. Schema When you migrate an object. This means that you do not have to change code that references an object or update other objects that have links to the migrated object even though the object has been moved to a new location. you must first return it to its source database and then move it from there. An attempt to migrate a checked-out object will cause an error. Checked-out Checked-out objects You cannot migrate a checked-out object. VERSANT Database Fundamentals Manual Object Migration Object Migration Usage Notes Migrating an object moves it permanently from one database to another. An attempt to migrate a versioned object will cause an error. an error will be returned. reduce network traffic by placing data near users. and/or move data from a development environment to a production environment. This ensures that you are the sole user of the object when you migrate it. Migrating an object is useful when you want to distribute data to take advantage of available hardware. you can use the "synchronize" method or other interface specific mechanisms. copies of class and superclass objects are made in the target database. Object identity When you migrate an object. To migrate a checked-out object. Locks Migration routines acquire a write lock if the object does not already have one. You 111 . Versioned objects You cannot migrate a versioned object. If a class or superclass exists with the same name in the target database but with a different definition.

Object Migration Actions Migrate object c o_migrateobj() o_migrateobjs() c++ migrateobj() migrateobjs() Check in object A checkin can migrate a new object from a personal database to a group database. Links to objects in personal databases When you check in or migrate objects created in a personal database to a group database. c o_checkin() c++ checkin() 112 . either all the objects will be migrated if the transaction commits successfully or all objects will be returned to their original databases. Commits A migration is not persistent until committed. If multiple objects are migrated in a transaction. make sure that the checked in or migrated objects do not reference objects left in a personal database.VERSANT Database Fundamentals Manual can use a checkin to explicitly return a checked out object to its source database.

VERSANT Database Fundamentals Manual Object Checkout Object Checkout Overview A checkout creates an object in a personal database that is a copy of an object in a group datatabase. Object Checkout Actions You can check out objects either specifically or with a query. The group checkout method will first search a specified database and then continue to search all connected databases. The net result can be a significant improvement in performance. The new object gets a logical object identifier that is different from that of the source object. VERSANT will automatically associate it with the current long transaction. stopping as soon as all desired objects have been found. The copy object has the same logical object identifier as the source object. Also. A checkout of a non-versioned object with a null lock creates a new object in a personal database that is a copy of the source object. you can return all objects associated with that long transaction simply by ending the long transaction. specified and linked objects can come from any number of different databases. because the original objects remain in their source databases. For information on group checkouts. please call Versant Technical Support. 113 . a checkout causes a personal database to become an extension of a group database. In a sense. Checkouts are useful when you want to work on particular objects for a long period of time with a minimum of network traffic and while optionally being disconnected from other databases. The new object a logical object identifier that is different from that of the source object. A checkout of a non-versioned object with a persistent read or write lock copies it from a group to a personal database. In a group checkout. Later. Group checkout of objects — Group checkouts allow you to replicate frequently used objects in multiple group databases. A checkout of a versioned object creates a new version of the object in a personal database. you can safely elect to turn off transaction management and recovery in your personal database and thus bypass locking and logging overhead. Checkout specified objects A group checkout copies specified objects to a personal database and optionally copies linked objects to a given number of link levels. When you check out an object.

VERSANT Database Fundamentals Manual Even though you can use group checkout objects from multiple databases. the requested persistent lock is set on the source object in its source database. but you can specify whether you want instances of subclasses also to be evaluated and checked out. you must be connected to the source group database at the time of the request. or null lock on the original object in the group database. performance is much better if all of the objects in a particular group checkout belong to the same database. you might want to make a separate group checkout for each database from which you want objects. After the checkout. Checkout non-versioned non-versioned objects When you check out an object. You cannot use a predicate checkout also to checkout linked objects. If you upgrade the lock. write. Thus. Locks. Find and check out objects of a class c o_pathpcheckout() o_pcheckout() c++ pcheckout() Checkouts. you can place a persistent read. If you release the lock. and Versions What happens when you check out an object depends upon your lock request and whether the object is versioned or non-versioned. the checkout of that object will be rolled back. but queries made by others will see the object in the source database. For a lock upgrade or release request to succeed. you can upgrade or release a persistent lock on the copy in your personal database. If you need to check out linked objects. A checked out. the upgrade will occur on the source object. to improve performance. non-versioned object with a persistent read or write lock becomes associated with the current long transaction. Also. your queries will see the object in your personal database and not in the source database. you can use a multi-level select query to identify the objects that you want to checkout and then check them out with a group checkout. The copy of the source object that is created in your personal database will have the same object identifier as the original. This means that later you can check in all such objects to their source databases 114 . After the checkout. Persistent write or read lock — A checkout of a non-versioned object with a persistent read or write lock copies it from a group database to the personal database used as a session database. c o_gcheckout() c++ gcheckout() Checkout found objects A predicate checkout copies objects that satisfy a search predicate to a personal database.

the checkout will occur. as hard locks are not breakable. By definition. VERSANT Database Fundamentals Manual simply by ending the long transaction. If there is a blocking lock. You can check out a mixture of versioned and non-versioned objects. because there is no contention. you must convert an object to a versioned object with the prepare to version routine before checking it out. For example. If there is no blocking lock. and that ending a long transaction will not perform a checkin of the copy object. you can override the soft lock with a hard lock and then check out the object. Persistent null lock — A checkout of a non-versioned object with a null lock creates a new object in a personal database that is a copy of the source object. A persistent write-hard lock will break a persistent read-soft lock or a write-soft lock. and a read-hard lock will break a write-soft lock. To use versioning behavior with checkouts. The behavior that occurs will automatically differ depending upon the type of object involved. you must first use an explicit "set persistent lock" routine to acquire the necessary hard lock. Checkout versioned objects A checkout of a versioned object always creates a new version of the object in a personal database. To break the soft lock. If you attempt to delete a non-versioned object which has been checked out in write or read mode. even if short locking has been turned off in its database. A read-hard lock will not break a read-soft lock. To delete the object. other users will be blocked by the persistent write lock just as if you had set a short write lock. If you invoke a prepare to version routine on a checked out object. the checkout will not occur. This means that a checkout can set persistent locks even if short locking has been turned off in a group and/or personal database. If an object has been previously checked out with a persistent read or write soft lock. The new object will have a new object identifier and have no connection to the original object. This routine will fail if there is a conflicting persistent hard lock on the object. one in your personal database and one in the source database. an error will occur. 115 . you must check it in and then delete it from its source database. existing locks are tested against the lock requested by the checkout. This means that a query based upon search conditions will see two similar objects. if you have a persistent write lock on an object. Checkout all objects For both non-versioned and versioned objects. an error will be returned. no persistent lock will be set on the source object. A persistent lock will not be set on the source object. because the checked out object is new and exists only in the personal database. even if requested. Turning locking off for a database disables short locks but has no effect on persistent locks.

If you check out an object with a null lock or a versioned object but do not check out its linked objects. This behavior for read and write mode checkouts occurs regardless of when the checkouts occur. that accessing a linked object will require a remote access and a remote database connection. whether the object is versioned or non-versioned. whether in one operation or in separate checkouts of objects and their linked objects. the links in the new object will continue to point to the target objects in their source databases. A link always points to the current location of an object. and Links What happens when you check out an object depends upon whether you also checkout linked objects.VERSANT Database Fundamentals Manual Since the purpose of group databases is to allow access to objects by multiple users. links will point to the target objects in their new locations in the personal database. 116 . This means that accessing a checked out linked object will not require a remote access or remote database connection. because links are based upon object identifiers and checking out objects in read or write mode does not change identifiers. If you check out both a non-versioned object and its linked non-versioned objects in read or write mode. If you are accessing objects in your personal database with multiple processes. If you check out a null locked or versioned object and also checkout its linked objects in a single group checkout. Checkout non-versioned non-versioned objects with read and write locks If you check out a non-versioned object with a read or write lock but do not check out its linked objects. Locks. links are handled somewhat differently than in read and write mode checkouts. the links in the new objects will be adjusted to point to the new linked objects created in the personal database. then you should normally leave short locking on. However. Behavior may also depend upon whether you check out objects and linked objects in one operation or in separate operations. the links in the new object will point to the original objects in their source databases. Checkout versioned objects and non non-versioned -versioned objects with null locks Since null lock and versioned object checkouts create new objects. This means. Checkouts. it is rarely safe to turn short locking off in a group database. the links from the checked out object to the linked objects will continue to point to the target objects in their source databases. If you check out a null locked or versioned object and later checkout its linked objects in a separate operation. for performance reasons you may want to turn short locking off in a personal database if you are accessing the objects with only a single application process. and what kind of lock you request.

logging must be turned on to roll back a checkout or checkin. VERSANT Database Fundamentals Manual Checkout General Notes Checkout and long transaction A long transaction tracks checked out objects using long transaction objects in the databases that are the sources of the checked out objects. Checkout and transaction commit A checkout is not persistent until committed. These class definitions are needed so that you can access the checked out object. a checkout will also copy its class object and the class objects for superclasses. Checkout and schema evolution For each object. a long transaction object in its database is updated. Long transaction objects are maintained even if logging has been turned off in a database. 117 . This means that you cannot use checkout/checkin mechanisms to change schema. the checkout will return an error. VERSANT will prevent changes from being made to class and superclass objects during the period of the checkout. One way is to change a class definition in one database and then use an interface specific "synchronize class" routine or utility to change it in another. create new objects of the same class. and embedded objects if they do not already exist in the personal database. Although VERSANT will allow you to change the class objects in the personal database. Another way is to change class definitions separately in all databases involved. There are numerous ways to evolve schema in different databases in a consistent manner. Each time an object is checked out. and you must stop and synchronize the definitions in order to make the checkout. create new subclasses. When a non-versioned object is checked out with a read or write lock. you must resolve any differences in class definitions before you can make a checkin. even if you explicitly checkout a class object. and use embedded classes normally. linked objects. If a class already defined in the personal database has the same name but a different definition. This means that a checkout is atomic: either all objects involved in a checkout are checked out when the transaction commits or none are. However.

Checking in a non-versioned object previously checked out with a null lock migrates it from a personal database to a group database and drops the object in the personal database. Checking in a versioned object creates a new. Checking in a non-versioned object previously checked out with a read or write lock returns it to its source database and drops the copy in the personal database. or continue the current long transaction. Committing a long transaction checks in all objects that have been checked out in the current long transaction and releases all locks held on the checked out objects. A checkin is useful if you have been working on objects in a personal database while being disconnected from other databases and now want to update other databases with your results. Object Checkin Actions You can check in objects by ending a long transaction or by using an explicit checkin routine. c o_endsession() c++ endsession() Check in specified objects An explicit checkin will check in specified objects. rollback. Continuing a long transaction leaves the checked out objects in the personal database and maintains persistent locks from one session to another.VERSANT Database Fundamentals Manual Object Checkin Object Checkin Overview A checkin moves a new or previously checked out object from a personal database to a group database. Checking in a new non-versioned object migrates it from a personal database to a group database and drops the original object in the personal database. These objects can either be new objects that you want 118 . Check in objects by ending a long transaction When you end a long transaction. you can commit. child version of the object in a group database and leaves the parent object in the personal database. Rolling back a long transaction drops the checked out objects from the personal database and releases all locks held on the checked out objects.

and Versions Checkin behavior depends upon locks previously set and differs for versioned and non-versioned objects. A checkin always returns a checked out object to its source database even if you specify a different database in the checkin routine. ending its long transaction will have no effect on that version. New object or null lock — If an object has been checked out with a null lock or was created in a personal database. you will not be able to checkin or migrate that object. Write lock — If a non-versioned object has been checked out with a write lock. VERSANT Database Fundamentals Manual to migrate to the group database or objects that have been previously checked out. but you can use either an explicit "check in" or a "migrate object" routine to migrate it from the personal database to a group database. ending a long transaction will have no effect on it. If you check in a mixture of versioned and non-versioned objects at one time. a checkin will replace the original object in the source database with the checked out object and delete the copy in the personal database. If you use an explicit "check in" routine on a previously checked out versioned object. Checkin non non-versioned -versioned objects Checkins of non-versioned objects do not change object identity. although what happens differs depending upon whether the object is a new object or an object previously checked out with a persistent write or read lock. Broken lock — If you checked out an object with a persistent read or write lock with a soft level and if the soft lock has been broken by another user requesting a hard lock. a checkin will not change the original object in the group database but will drop the copy in the personal database. what happens will depend upon the type of object involved. c o_checkin() o_checkinreturnobjs() c++ checkin() Checkins. Checkin versioned objects If a versioned object has been checked out. Read lock — If an object has been checked out with a read lock. a new version of 119 . An explicit checkin allows you either to hold locks on previously checked out objects or to set locks on new objects being checked in. because checking it out created an entirely new version in the personal database with only a child-parent relationship with the source object in the group database. Locks.

However. If you try to checkin an object whose class name is the same as a class that exists in the target database but whose definition is different. If you handle the error and continue. Deleting a versioned object from a personal database has no effect on the version derivation graph in the group database. the next checkin caused by ending the long transaction will restore the original object in its source database and release its persistent lock. VERSANT will traverse the version graph to find the original parent object in the group database and. use it for the checked-in version. Checkin and source database Checkins always return checked out objects to their source database even if you specify a different database in an explicit "check in" routine. Checkin object deletion You cannot use a checkin to delete an object. You will then have to resolve the differences in definitions. After a checkout of a versioned object. If the parent has been deleted. In other words. If you rollback a checkin or if the system crashes before a checkin is committed. Object Checkin General Usage Notes Checkin and schema evolution You cannot use checkins to change class definitions. Checkin and transaction commit A checkin is not persistent until committed. you can specify a new parent as a parameter in the checkInTo: message. If you check an object out in read or write mode. a checkin is atomic: either all objects involved in a checkin are checked in when the transaction ends or none are. 120 . an error will be raised. by default. class and superclass objects for both checked out and new objects remain in the personal database even if all of their instances have been checked in or migrated.VERSANT Database Fundamentals Manual that object will be created in the group database. an attempt to delete it will cause an error. Checkin and class objects After a checkin. the original parent object may be deleted in the source group database. then the checkin will have no database effect. a checkin of a versioned object will create a new version derivation graph with the checked in object as the root of this graph. The checkin will not delete the versioned object in the personal database.

.................................................................................................... 132 Overview ........... 132 Architecture .................................................................................................... 122 Versioning Actions ................................................................................................................. 138 Example Demo Program................................................................ 133 Usage ............................................................................................. 123 Versioning Example ............................................................ It uses a "smart object" architecture for connecting objects logically to create different versions of the same data............ VERSANT Database Fundamentals Manual Chapter 8: Object Versioning and Configuration Management Object versioning is a VERSANT feature that allows you to track the evolution of object states.................................................................................................. Object Versioning ..................................................................................................................................................................... 122 Overview ............. 145 121 ................................................... Configuration management is a low-level framework upon which you can build a configuration management system......................................................... 129 Configuration Management................................................................................................................................................

Automatic maintenance of the version graph means that you do not have to keep track of derivation histories across databases. which is important since you may not know what other applications are doing. If you do specify a parent during a checkin. The first version of an object becomes the root of the object's version derivation graph. The derivation graph branches when sibling versions are created and merges when a single version is created from multiple parent versions. such as creation time and creator identification.VERSANT Database Fundamentals Manual Object Versioning Overview Versioning purpose One of the purposes of versioning is to allow the tracking of the evolution of object states. points to the versioned object itself. Version Derivation Graph VERSANT tracks the version derivation history of objects across databases in a database system. One of the versions is a default version. Another purpose of versioning is to make a particular object always available for checkout to a personal database regardless of the locks that have been set on it. Each node of the derivation graph references all predecessors and successors. These virtual links are then used by the Version Manager module of the VERSANT Manager to find a proper parent for a version during subsequent checkouts and checkins. by using a version derivation graph. which is an extension of a version derivation graph for a single database. An object or a group of objects can have any number of versions whose interrelationships are automatically logged. the Version Manager records the new derivation link and does not traverse the derivation hierarchy. Initially the default 122 . even when objects are checked out. because checking in a versioned object always creates a new version of that object. The coordination of version derivation across database boundaries is achieved through the concept of a "virtual" version derivation graph. In a virtual version graph. Constant availability is consistent with locking. and contains some descriptive information about the versioned object. VERSANT can resolve version relationships at runtime with dynamic binding to a generic instance. related versions in different databases are connected through virtual links automatically created by checkout and checkin operations. and the current default is recorded in the generic instance. You can override the default handling of version derivations by explicitly naming a parent version in a target database.

all versioned object that meet the selection criteria are returned. Versioned objects are persistent objects in the full sense. When you query the database by selection. in addition to any non-versioned objects. Once an object is versioned. it is automatically handled differently from a non-versioned object. including any versioned objects. and can have parent. The default version is recorded in a "generic instance" associated with the versioned object. child. A versioned object is always associated with the database in which it was first created. 123 . the generic version is also deleted. Each version of an object has a unique object identifier. Versioning Actions Create versioned object Is versioned object Any object can be explicitly or implicitly changed from a normal object to a "versioned" object. At runtime you can use the generic instance to find the version that has most recently been specified as the default version. You can then use various routines to determine if an object is versioned and what its version status is. a version status. There is only one generic object instance for a versioned object. However. any versioned objects that meet the search predicate are returned. When you perform a query on a versionable class. An application program can also statically bind to a specific version. when you create a database index. You can also create a versioned object implicitly by creating a child version of it with a "create version" routine. it will index all objects of a class. When the last version in a version tree for a database is deleted. and you can ask any object whether or not it is a versioned object. Versioned objects cannot be migrated. Likewise. you can set the default. even if some versions have been checked out. and/or sibling relationships to other versions. VERSANT Database Fundamentals Manual version is the most recent version in the derivation graph.

124 . regardless of how similar it may be to its predecessors. VERSANT stores each complete version. make it a versioned object. When you create the first version of an object. you must check it in. and a generic object instance is created. After a non-versioned object has been checked out and you want to make a version of it.VERSANT Database Fundamentals Manual Create versioned object c o_preptoversion() c++ preptoversion() Is versioned object c o_isvsninst() c++ isvsninst() Create version Create version with checkout Create version with checkin After an object is versioned. You cannot version a checked out non-versioned object. and optionally check it out again. Each version is given a version number. If you try to create a version of a non-versioned object. assigned a status. and its parents and children are stored in a version graph. additional versions can be created either explicitly with a "create version" routine. or automatically via checkout and checkin procedures. the object will automatically be changed to a versioned object before the new version is created. the original object becomes the root of the object's version tree.

You can explicitly add a parent version to an object. if you have merged two parent objects and want to designate the new parent version as a parent of a particular child. VERSANT Database Fundamentals Manual Create version c o_createvsn() c++ createvsn() Create version with check out of a versioned object c o_gcheckout() o_pathpcheckout() o_pcheckout() c++ gcheckout() Create version with check in of a versioned object c o_checkin() o_checkinreturnobjs() o_endsession() c++ checkin() endsession() Get version children Get version parents Add version parent A new version of an object is called a "child. further versions can be explicitly created or implicitly created by use of checkouts and checkins." Each new version of an object has a child relationship to its source object. 125 ." Versions that share the same parent are called "siblings. say. Once an object has been versioned. This is useful." while the original object is called a "parent. You can find all children or parents of any versioned object or the generic instance.

which is frozen and cannot be updated. A working version can be deleted to recover space. You can use routines to set and get their status.VERSANT Database Fundamentals Manual Get version children c o_getchildvsns() c++ getchildvsns() Get version parents c o_getparentvsns() c++ getparentvsns() Add version parent c o_addparentvsn() c++ addparentvsn() Get version status Set version status Versions have status levels assigned to them to provide update constraints. and you cannot downgrade a non-leaf version to a transient version. Accordingly. a transient version can only occur as a leaf on a version graph. Working version — When a version becomes stable. although its derivation history persists in a version graph because there may still be versions derived from it. 126 . Released version — A version can be upgraded to released status which means that it cannot be updated or deleted. When a transient version is deleted its description is also deleted from the version derivation graph. if you want to delete a released version. A version cannot be modified if there are versions derived from it. That is. if a child version is derived from a transient version. You can downgrade or demote a version's status. downgrade it to a working version and then delete it. it can be promoted to a working version. the parent transient version is automatically upgraded to a working version. For example. Transient version — A transient version is treated as an ordinary object and it can be updated or deleted.

VERSANT Database Fundamentals Manual Get version status c o_getvsnstatus() c++ getvsnstatus() Set version status c o_setvsnstatus() c++ setvsnstatus() Get version You can bring a versioned object into memory using its version number or version status. If the default version number is less than zero. Initially the default version number is the most recent version in the derivation graph. You can set this 127 . most recent released version. or most recent version. When you get a versioned object (with a "locate object" routine or by dereferencing it. When the last version in a version tree for a database is deleted. If the default version number is greater than zero. then the default version is dynamically bound at run time to the corresponding versioned object instance. the default version is statically bound to the corresponding version of the object. even if some versions have been checked out. The generic object stores the version derivation graph for a versioned object and also stores the version number of the default version. the original object becomes the root of the object's version graph and a generic object instance is created. the generic version is also deleted.) the generic object is brought into the object cache along with the versioned object. representing most recent transient version. most recent working version. There is one generic object instance for each versioned object. Get version c o_locatevsn() c++ locatevsn() Get default version Set default version Get generic object Is generic object When you create the first version of an object.

An application can statically bind to any version of an object. including the default version. you may need to change your application code to either statically bind to a specific version or dynamically bind to the default version.VERSANT Database Fundamentals Manual number explicitly with the "set default version" routine. Unless you want to create new versions with each checkin. Until the lock on the generic object is released. an application using the generic object to dynamically bind to the default version is locked out. This short lock is released at the end of the short transaction. Review your applications to see if they access objects that have been or will be versioned. Making a new version automatically locks the generic object which contains the version graph. Get default version c o_getdefaultvsn() c++ getdefaultvsn() Set default version c o_setdefaultvsn() c++ setdefaultvsn() Get generic object c o_getgeninst() c++ getgeninst() Is generic object c o_isgeninst() c++ isgeninst() 128 .

VERSANT Database Fundamentals Manual Delete version You can delete a versioned object without removing its description in the version graph. you can delete an entire hierarchy by deleting the generic instance. db1. Get version number c o_getvsnno() c++ getvsnno() Versioning Example Version management across database boundaries Following is an example of version management involving three databases. db2. If the instance involved is a generic instance. The example shows the coordination of versions among databases for a single object with multiple versions. a group database. the version number of the current default version is returned. Delete version c o_deletevsn() c++ deletevsn() Get version number You can get the version number of a version instance. Alternately. db3. a personal database. and a personal database. 129 .

The original object becomes. is created. Because object db1/v2 is a versioned object. at time three a second child version of the object in database one is created as object db1/v3. 130 . the child version in group database two. t3 To illustrate parallel version derivation. t2 At time two. a child version is created in the second personal database as object db3/v2. db1/v1. t1 At time one a child version object. there are three version derivation hierarchies corresponding to two personal databases and a group database. The Version Manager uses virtual link information to maintain a derivation history across the databases. one in each database. in personal database one. the checkin does not delete it from the personal database. db1/v2.VERSANT Database Fundamentals Manual In the above example. through checkouts and checkins. object db1/v2. is checked into the group database as object db2/v1. t5 At time five. t4 At time four. This object is a sibling to object db1/v2 and shares the parent object db1/v1. three different versioned objects. t0 At time zero there is one version object. the child version in database one. is checked out from the group database into another personal database as object db3/v1.

VERSANT Database Fundamentals Manual t6 At time six. in personal database one. t7 At time seven. a child version. a similar situation occurs when the latest version in the group database. Its parent is db1/v2. t8 At time eight. is checked out to the first personal database. a child version is created in the first personal database as object db1/v4. object db2/v2. is created in the second personal database with parent object db3/v2 and grandparent object db3/v1. which becomes object db1/v5. The Version Manager chooses as a parent object db2/v1 by traversing up the derivation hierarchy for the second personal database db3 and finding that the grandparent object db3/v1 was derived from object db2/v1 in the group database. Again. Thus. t9 At time nine. object db2/v2. object db3/v4. This object is a sibling to object db3/v2 and shares the parent object db3/v1. it becomes a new version. t10 At time ten. Because the checked in object is new. the child version object db3/v4 is checked into the group database. the Version Manager traverses up the derivation hierarchy to find that the parent object db2/v1 was derived from object db1/v2. a parallel child version is created in the second personal database as object db3/v3. object db1/v2 is made the parent of the checked-out object. The checkin creates a version object db2/v2 from the parent object db2/v1. 131 . in database two.

Smart objects serve as intelligent proxies. Following are key terms related to configuration management. Smart Objects contain two important features: • A configuration table A configuration table links smart objects to specific object versions. Configuration objects are normally developed in a tree hierarchy that identifies all configurations associated 132 . In a configuration.VERSANT Database Fundamentals Manual Configuration Management Overview VERSANT configuration management is a low-level framework upon which you can build a higher-level configuration management system with policies appropriate for each of your applications. the latest or released). Configuration Object — A configuration object is an object that you define to identify a unique configuration. a member object is just a regular object. VERSANT configuration management has a "smart object" architecture for versioning objects. when dereferenced yield the correct version of the original objects (e. When we talk about versions in a configuration. The smart object connects these objects together logically. • A resolve function A resolve function processes the configuration table to return the specific version based on your current configuration. with no generic object or version tree) whose only connection is that they are pointed to by the same smart object. Smart objects are useful when large composite objects require versioning of individual components and it is not practical to maintain multiple versions for the entire object. which. it is completely different from VERSANT versioning and has no dependence on it. This is similar to implementing a many-to-many association. not a versioned object with a generic object and version graph. Important Note — While configuration management can be used to build a versioning scheme. we actually mean that we have different objects (non-versioned. except that only one pair of the association is valid for any specific configuration. indicating that they contain different versions of the same logical data.g.

to dynamically resolve the target objects. based on the configuration list specified by the user. User Application — A user application uses configuration lists and smart objects. To make resolution of higher priority items faster. Member List — A member list is the set of member objects that associated by one or more similarities and are linked to a single smart object. A configuration list and a smart object are required to resolve a target object or versioned object. Member Object — A member object is an object associated with a specific smart object. VERSANT Database Fundamentals Manual within a configuration management scheme. with the highest priority configuration appearing last. Management Application — A management application manages the configurations and smart objects. A member list typically contains versions of a single. Target Object — A target object is the object resolved dynamically based your priority scheme (configuration list) and the configuration table in the smart object. specific object. member objects may have the same parent. Most of the functions and methods described in this document are used only by a management application. This binding is done at run time. A member object can be associated with at most one smart object. Architecture Smart Object Model A smart object (S1) can be conceptually modeled with the following table. 133 . the configuration lists are in reverse order of priority. Smart Object — A smart object (C interface) or smart link (C++ interface) is an object that dynamically binds a configuration object to a target object. Configuration List — A configuration list is an ordered list of configuration objects which specifies the order used when binding a reference from a smart object to a target object. Configuration Table — A configuration table links configuration objects with the member objects in a smart object. For example.

In the above. This allows you to make the target column longer than the configuration column and store the unmapped targets in the extra portion of the target column. most of them are standard methods such as creation or get and put for the attributes. Resolving — Resolving is the process by which a smart object is dynamically bound to a target object in the context of a configuration list. highest priority first) for (configurations T in table) if (L == T) return target associated with T return NULL Since this could become expensive during heavy dereferencing. Since you are responsible for managing the table. The only unique method is the "resolve" operation. The second way is to take advantage of the fact that the two columns are implemented as two separate vstrs. T4 and T5 are specified as unmapped members. configuration list L) returns target object { configuration C = highest priority in L with an entry in the S table return the target object T associated with C in the S table } The most simple and general purpose algorithm for implementing the resolve operation is a nested loop of order MN. It is defined just as you might expect when you consider that a configuration list is a prioritized list of configurations: resolve(smart object S. two optimizations to this algorithm are 134 . you can decide on a target by target basis which of these two methods to use. The first way is to specify a NULL configuration.VERSANT Database Fundamentals Manual Configuration Target Object C1 T1 C2 T2 NULL T3 C3 T1 T4 T5 Notice that there are two different ways that targets can be specified as members without mapping them to a configuration. as is the case with T3. You can think of it as a function which maps a smart object and a configuration list to a target object. where M is the size of the configuration list and N is the size of the smart object's table: for (L in configuration list. Smart Object Operations Although there are many operations on the smart object.

In other words. we can implement the following linear time algorithm: for (configurations T in table) if (priority(T) is defined && priority(T) is the highest priority so far) result = T You can further optimize this algorithm if you are willing to accept the following restriction: • The relative order of the configurations in the configuration lists and in the tables of smart objects must always be the same. C4. it was not necessary to look for a match with to a lower priority configuration such as C1. For example to forward S2 to S1. C2. This being the case. Resolve can be described by considering the smart object S1. Smart Object Forwarding The concept of smart object forwarding aids in the merging of two smart objects. the loop can be modified to terminate early as follows: for (configurations T in table. Optimize Caching Each smart object caches the most recent result of the resolve operation. it would resolve the target object T2. Optimize Hash Table The VERSANT ODBMS configuration management concept incorporates a small hash table for each configuration list which maps configurations to their position in the list. the contents of S2's table could be merged into S1 and the table of S2 could 135 . VERSANT Database Fundamentals Manual available. This is highly effective on the front end where normally a single configuration list is used repeatedly for long periods of time. This implies that the first case where priority (Tx) is defined is also the highest priority. If S1 is resolved with the configuration list {C1. the option to specify whether or not the restriction has been accepted is provided. the entries in the tables must be sorted in order of increasing configuration priority. Using this hash table. A smart object can be instructed to forward its resolve operations to another smart object by placing a special value in its table. highest priority first) if (priority(T) is defined) return T return NULL Since you may or may not feel the extra optimization is worth the restriction. was not associated with a target object in S1. Since C2 was associated with T2. Note that the highest priority. C4}.

in a lazy incremental fashion. This API implements a "set smart object" operation and must be invoked by the user whenever a member is added to or removed from a smart object. In this case. Forwarding can easily be limited to one level by resolving multiple levels of forwarding at merge time. This implies that the query and gwrite remote procedure calls send the default lock to the backend. To avoid deadlock. you must specify the smart objects before the target objects when performing a group read. the user can replace references to S2 with references to S1 as they are encountered. Since you maintain the smart object's.VERSANT Database Fundamentals Manual then be set as follows: Configuration Target Object S2 S1 To avoid the expense associated with an extra level of indirection. You may also consider using queries to preemptively find and fix objects that reference S2. For more information on optimistic locking refer to the VERSANT Database Fundamentals Manual. If you are not interested in using the query support. you can choose to save space by not maintaining the backpointer. Locking Smart objects are read with the default lock mode. target object next. it reads the target first but has special logic to avoid deadlock. it can be done in the background during non-peak time periods. you can also elect to store only the members that are associated with a configuration 136 . When a group write is performed the objects are partitioned into two groups: smart objects and non-smart objects. Group read makes the assumption that you have specified the smart objects first and then the targets. the standard order for obtaining locks is smart object first. locks are obtained in order. Query is an exception to this rule. following the forwarding chain. To prevent potential deadlocks. To increase system performance a timestamp attribute is provided to support optimistic locking. In the forwarding case where there are multiple smart objects. Locks are first obtained for the smart objects. If this is not done there can be a deadlock. you must also maintain the backpointer via a VERSANT supplied API. Optimistic Locking The smart objects can come under heavy contention in a multi-user environment. Query Support Each member object maintains a backpointer to its smart object to accommodate execution of a query for a particular configuration list. Since such an operation can be expensive.

C2} and update the tables in the smart objects of your 10 changed objects to map C2 to the new objects in addition to the original mapping of C1 to the old objects. C3. For example. You can also decide whether to return matches that are not bound to a smart object by setting a flag to the select APIs.000 "released" objects. Configuration Lists The configuration list model can be used to implement an efficient delta versioning system. In the future. if you wanted to make an additional change to 1 of your 10 changed objects. Users without access to the changes would keep their configuration list set to {C1}. Later you might want to make changes to 5 more previously unchanged objects (configuration C1). C2. C3}. C2. specify the O_CM_RETURN_TARGETS option in your query. You would then map the four configuration {C1. consider the scenario where you are changing 10 objects in a database of 100. A configuration object C1 can represent the original unchanged configuration of the database and C2 can represent your new configuration. set your configuration list to {C1. set your configuration list to {C1. VERSANT Database Fundamentals Manual object in a smart object's table. To test the configuration changes. C4} and the database into a tree similar to the following illustration: The path from the current version (C3) to the original root version (C1) would then be used as the 137 . you could create a new configuration C3. If you want to resolve the smart objects returned as a result of your query. and add an entry mapping C3 to the new version of the target object.

000 smart objects with entries for C1. Routines C/VERSANT o_greadobjs() o_pathselect() o_pathselectcursor() NOTE: you cannot use the following configuration management options in: o_select(). O_CONFIG_ORDERED Assume that the configurations in configuration lists and tables of smart objects are always in the same relative order. the default configuration list is NULL. Query and Group Read Options Configuration management can improve performance by avoiding unnecessary reading of objects. O_CONFIG Enable configuration management routines. 10 smart objects with entries for C2. because o_select() does not take a query option. C2. and C3 as a leaf configuration representing a small change used by one person. or when a routine involves a configuration list but provides no way to specify one. Usage Session Options Routines C/VERSANT o_beginsession() C++/VERSANT PDOM::beginsession() Configuration management options To use configuration management routines. When NULL is passed to a routine which takes a configuration list. C3}. there were 100. Notice that the number of smart objects with entries for a particular version tends to be much greater for the lower priority configuration objects than for the high ones. and 1 smart object with an entry for C3. or you will get the error OM_CM_WRONG_MODE.VERSANT Database Fundamentals Manual configuration list {C1. you must specify one or both of the following in the options parameter. 138 . This makes sense when you think of C1 as a root configuration shared by everyone. Until you set it otherwise. In our example. this default configuration list is used. Each session has a default configuration list associated with it.

it just has to have a smart object. if it does not have a smart object. O_CM_MUST_HAVE_SMART If specified. If used with O_CM_MUST_HAVE_SMART. if it has a smart object (it does not have to be a target of a smart object. 2.) An object will not be returned if does not have a smart object. If used with O_CM_VALIDATE. a server performing a query or group read will return an object that satisfies the find or get criteria: 1. a server performing a query or group read will: 1. if it is a smart object. 3. VERSANT Database Fundamentals Manual C++/VERSANT PDOM:greadobjs() PDOM::select_with_vstr() PClass:select() VCursor::VCursor() Configuration management options If you have enabled configuration management when you started your session. O_CM_VALIDATE If specified. a server performing a query or group read will return to the client application an object that satisfies the find or get criteria: 1. if it is a smart object. 2. you can specify one or more of the following in the options parameter. then only objects that have smart objects will be returned. An object will not be returned if it has a smart object but is not a target of its smart object when resolved with the default configuration list. resolve smart objects that satisfy the find or get criteria and only return target objects. if it is the target of a smart object. return objects that satisfy the find or get criteria if they do not have a smart object. you must make sure that the appropriate smart objects are flushed in addition to instances of the class being selected. 139 . then only targets that are results of the resolve operation on their smart objects will be returned. O_CM_RETURN_TARGETS If specified. Before doing a select. 2.

you can specify one or more of the following in the options parameter. The target objects are read (without read locks. a lock conflict can occur even in an optimistic locking session. a group read or single object fetch will obtain a read lock on all fetched objects and then. This option can be used only in an optimistic locking session. If used in a strict locking session. it will return an error. Because a read lock is applied during the duration of the operation. when a smart object is encountered. If smart objects are involved. By default. smart objects will be transparently resolved when passed an argument to functions. The smart objects are fetched. O_DROP_RLOCK_TIMESTAMP_ONLY If specified for a thread. and the read locks are dropped. drop the read locks on smart objects and on objects containing a time stamp. O_CONFIG_RESOLVE If specified for a thread. when the entire read has finished. a server performing a query or group read will not resolve a smart object. the following occurs to the smart objects: 1.VERSANT Database Fundamentals Manual O_CM_DONT_RESOLVE If specified. 3.) During the time between the dropping of locks on the smart objects and the time of the resolve operation. the server will resolve it in the default configuration and return both the original smart object and the resulting target object. The smart objects are resolved. 2. The purpose of this option is to ensure that a group of objects are read consistently in an optimistic locking session. Thread Options Routines C/VERSANT o_setthreadoptions() C++/VERSANT VSession:setthreadoptions() Configuration management options If you have enabled configuration management when you started your session. there is a window of time during which the smart objects could be modified by 140 .

Configuration Management Routines C/VERSANT o_cmgetconfiglist() Get the default configuration list. Link<type>::invalidate_cache() Invalidate cache entries related to a smart obj. o_cmgetsmartobject() Get smart object. o_cmissmartobject() Is this a smart object. C++/VERSANT Link<type>::get_configurations() Get configuration objects. 4. o_cminvalidatecache() Invalidate cache entries related to a smart object. Call a check timestamps routine (o_checktimestamps() in C) on all dirty smart objects. Link<type>::is_smart() Is this a smart object. Re-apply your edits to the objects that have been refreshed. o_cmnewsmartobject() Create a smart object. Link<type>::get_targets() Get target objects. 141 . This will place a write lock on all the edited smart objects and return a list of objects that are out of date. 2. dirty smart objects . o_cmgettable() Get configuration table. Link<type>::resolve() Resolve smart object. which would invalidate the resolve operation. VERSANT Database Fundamentals Manual another transaction. o_cmsetsmartobject() Set smart object. Turn the O_DROP_RLOCK_TIMESTMP_ONLY option on and reset the default lock mode. Turn the O_DROP_RLOCK_TIMESTAMP_ONLY option off and set the default lock mode to write lock. o_cmresolve () Resolve smart object. Link<type>::resolve_target() Resolve smart object. 1. The following methodology represents one way safely to update optimistically locked smart objects. o_cmsetconfiglist() Set the default configuration list. 3. Refresh the out-of-date. Link<type>::new_smart() Create a smart object. Commit the changes 6. 5.

o_deleteobj() Resolve the smart object and delete the result. PDOM::get_configuration_list() Get the default configuration list. o_getattroffset() From the result of the resolve. o_checktimestamps() Determine the objects that have changed since copies have been read into the object cache. o_gdeleteobjs() Resolve the smart objects and delete the results. o_getattr() Retrieve the value of the attribute from the result of the resolve. retrieve the attribute value whose offset is specified as one of the arguments. PObject::set_smart() Set smart object. o_downgradelock() Downgrade the lock on the target object. If some of the objects are smart. o_classobjof() Retrieve the class object of the result of the resolve on the smart object. o_findremoteobj() Return the name of the database that contains the result of the resolve operation. downgrade or release locks on the smart objects as well as their resolves without flushing them from the application cache. o_downgradelocks() If some of the objects specified are smart. 142 . o_getattrpos() From the result of the resolve. o_classnameof() Retrieve the class name of the result of the resolve on the smart object. PDOM::set_configuration_list() Set the default configuration list. retrieve the attribute value whose position is specified as one of the arguments. o_cleardirty() Mark as clean the target of the resolve. o_compareobj() Resolve the smart object and apply the compare operation on the result. Standard Routines that Can Respond to Smart Objects C/VERSANT o_acquireplock() If one or more of the objects specified are smart. resolve them and check if either of the smart or target objects have been modified.VERSANT Database Fundamentals Manual PDOM::gdeleteobjs() Delete smart or member objects. PObject::get_smart() Get smart object. transparently apply the resolve operation on them and acquire the lock on their targets.

o_setattrpos() Set a write lock on the result of the resolve on smart if it does not already have one. then follow the links from the result of the resolve operation. mark it as dirty. o_migrateobj() Move the smart object and all the member objects associated with it to the new database. o_setattroffset() Set a write lock on the target of the resolve operation if it does not already have one. o_iseqobj() Resolve the objects if they are smart and apply the operation on the results. o_preptochange() Mark as dirty the target of the resolve operation on the smart object. o_refreshobjs() Update the smart object and the result of its resolve in the object memory cache with their current state in the source database. 143 . mark the object as dirty. o_migrateobjs() Move the smart object and all the member objects associated with it to the new database. o_releaseobj() Release the memory space used by the target of the resolve operation on the smart object. o_refreshobj() Update the smart object and the result of its resolve in the object memory cache with their current state in the source database. o_releaseobjs() Release the memory space used by the target of the resolve operation on the smart object. If a returned object is a smart object. o_isinstanceof() Return TRUE if the result of the resolve is an instance of the class specified as one of the arguments. o_locateobj() Resolve smart object and get target object. VERSANT Database Fundamentals Manual o_getclosure() Evaluate the objects objs in the database dbname and for the number of levels specified as levels follow all links to their target objects. mark the object as dirty. o_setattr() Set a write lock on the target of the resolve if it does not already have one. and set the specified attribute to the new value in the specified buffer. o_moveobjs() Move the smart object and all the member objects associated with it to the new database. o_setdirty() Mark as dirty the target of the resolve operation on the smart object. o_unpinobj() Clear any pins on the smart object and the result of its resolve that have been set in the current pin region. and set the attribute with the specified position to the new value in the buffer specified as buffer. and set the attribute whose offset is offset to the new value in the buffer specified as buffer.

LinkAny::deleteobj() Delete smart and target object. mark it as dirty. Link<type>::migrateobj() Move the smart object and all the member objects associated with it to the new database. LinkAny::setattr() Set a write lock on the target of the resolve if it does not already have one. transparently apply the resolve operation on them and acquire the lock on their targets. checkpoint commit. 144 . downgrade or release locks on the smart objects as well as their resolves without flushing them from the application cache. Link<type>::setattr() Set a write lock on the target of the resolve if it does not already have one. o_xactwithvstr() Commit. PDOM::downgradelock() Downgrade the lock on the target object. PDOM::acquireplock() If one or more of the objects specified are smart. and set the specified attribute to the new value in the specified buffer. If a returned object is a smart object. PDOM::getclosure() Evaluate the objects objs in the database dbname and for the specified number of levels follow all links to their target objects. Link<type>::unpinobj() Clear any pins on the smart object and the result of its resolve that have been set in the current pin region. Link<type>::operator*() Resolve smart object and cast link to target object. PDOM::downgradelocks() If some of the objects specified are smart. resolve them and check if either of the smart or target objects have been modified. and set the specified attribute to the new value in the specified buffer. LinkAny::unpinobj() Clear any pins on the smart object and the result of its resolve that have been set in the current pin region. C++/VERSANT Link<type>::operator->() Resolve smart object and get target object. If the smart objects are not dirty.VERSANT Database Fundamentals Manual o_upgradelock() Upgrade the lock on smart and the result of its resolve to the specified lock mode and options. mark it as dirty. operate on both. operate only on the results of their resolve. then follow the links from the result of the resolve operation. PDOM::checktimestamps() Determine the objects that have changed since copies have been read into the object cache. PDOM::gdeleteobjs() Delete smart and target objects. or rollback changes to objects in the session database. LinkAny::migrateobj() Move the smart object and all the member objects associated with it to the new database. If some of the objects are smart. otherwise.

* */ #include <omapi. The demo APIs are: o_cmaddconfig() o_cmremoveconfig() o_cmsetconfig() /* * * cmdemo. VERSANT Database Fundamentals Manual PDOM::refreshobj() Update the smart object and the result of its resolve in the object memory cache with their current state in the source database. PDOM::refreshobjs() Update the smart object and the result of its resolve in the object memory cache with their current state in the source database. operate only on the results of their resolve. target) pair to * smart's table at a specified position. operate on both. checkpoint commit. PDOM::releaseobjs() Release the memory space used by the target of the resolve operation on the smart object. A position 145 . PObject::migrateobjs() Move the smart object and all the member objects associated with it to the new database. PDOM::upgradelock() Upgrade the lock on the smart object and the result of its resolve to the specified lock mode with the specified options. otherwise.h> /* * o_cmaddconfig: Add the specified (config. PDOM::xactwithvstr() Commit. If the smart objects are not dirty. o_cmsetsmart() and o_cminvalidatechache. Example Demo Program For the demonstration program three higher level APIs developed on top of o_cmgettable(). or rollback changes to objects in the session database. PDOM::refreshobjs() Release the memory space used by the target of the resolve operation on the smart object. PObject::unpinobj() Clear any pins on the smart object and the result of its resolve that have been set in the current pin region.c: Demo/example for implementing Configuration Management * tests.h> #include <oscerr. PObject::migrateobj() Move the smart object and all the member objects associated with it to the new database.

if (newConfigObjects == NULL) return o_errno. newTargetObjects = (o_object *)malloc(targetVstrSize + sizeof(o_object)). &configVstr. o_object target. /* Get the Configuration and Target Vstrs for smart */ err = o_cmgettable(smart. o_vstr *configVstr.) */ 146 . TRUE). which not true in general. o_4b configVstrSize.VERSANT Database Fundamentals Manual * of -1 indicates that the entry should be added at * the end of the table with the highest priority. /* Insert the pair at the end of the table if position == -1 */ /* (the following assumes that the configuration list and the */ /* target list have the same length. /* * Create the new config/target object list */ newConfigObjects = (o_object *)malloc(configVstrSize + sizeof(o_object)). o_4b targetVstrSize. &targetVstr. o_4b i. targetVstrSize = o_sizeofvstr(targetVstr). o_vstr *targetVstr. o_object config. if (newTargetObjects == NULL) return o_errno. o_4b position ) { o_err err. if (err != O_OK) return err. o_object *newTargetObjects. */ o_err o_cmaddconfig ( o_object smart. /* get the sizes of the vstrs */ configVstrSize = o_sizeofvstr(configVstr). o_object *newConfigObjects.

} /* Insert config at the end of the configuration list */ newConfigObjects[i] = config. i++) { newConfigObjects[i+1] = ((o_object *)*configVstr)[i]. } /* Insert target object at the specified position */ for (i=0. (o_u1b *)newConfigObjects). i < configVstrSize/sizeof(o_object). i < position. } /* Insert target at the end of the target list */ newTargetObjects[i] = target. 147 . } else { /* Insert config object at the specified position */ for (i=0. i < configVstrSize/sizeof(o_object). } } /* Reset smart's table */ *configVstr = o_newvstr(configVstr. /* Construct the new list of target objects */ for (i=0. i++) { newTargetObjects[i+1] = ((o_object *)*targetVstr)[i]. i++) { newConfigObjects[i] = ((o_object *)*configVstr)[i]. i++) { newTargetObjects[i] = ((o_object *)*targetVstr)[i]. i++) { newConfigObjects[i] = ((o_object *)*configVstr)[i]. } newConfigObjects[i] = config. i < targetVstrSize/sizeof(o_object). i < position. configVstrSize+sizeof(o_object). for(i=position. } newTargetObjects[i] = target. i++) { newTargetObjects[i] = ((o_object *)*targetVstr)[i]. VERSANT Database Fundamentals Manual if (position == -1) { /* Construct the new list of configuration objects */ for (i=0. i < targetVstrSize/sizeof(o_object). for(i=position.

/* dirty the smart object */ err = o_preptochange(smart). /* unpin the smart object */ err = o_unpinobj(smart. set it to NULL */ if (config == ((o_object *)*configVstr)[i]) { ((o_object *)*configVstr)[i] = (o_object)NULL. targetVstrSize+sizeof(o_object). } /* * o_cmremoveconfig : Remove the entry associated with config from * smart's table. i++) { /* If the object is found. if (err != O_OK) return err. if (err != O_OK) return err. TRUE). return O_OK. o_vstr *targetVstr. (o_u1b *)newTargetObjects). /* Look for config in smart's config table */ for (i=0. make sure that the target is not * removed from smart's target array. free(newConfigObjects). &targetVstr. /* Get smart's table */ err = o_cmgettable(smart. 148 . if (err != O_OK) return err. o_err err = O_OK. o_4b i.VERSANT Database Fundamentals Manual *targetVstr = o_newvstr(targetVstr. */ o_err o_cmremoveconfig ( o_object smart. o_object config ) { o_vstr *configVstr. i < o_sizeofvstr(configVstr)/sizeof(o_object). &configVstr. free(newTargetObjects). TRUE). If there is a target associated * with config.

*/ o_err o_cmsetconfig ( o_object smart. return err. &targetVstr. set its target object. i++) { /* * If the object is found. Make sure that * you save the previous target object */ if (config == ((o_object *)*configVstr)[i]) { /* Save the old target object in a temporary variable */ 149 . o_4b i. VERSANT Database Fundamentals Manual break. /* Get the Configuration and Target Vstrs for smart */ err = o_cmgettable(smart. if (err != O_OK) return err. if (err != O_OK) return err. o_object config. } } /* dirty the smart object */ err = o_preptochange(smart). TRUE). o_object oldConfig. making sure that the old target is not removed * from smart's target array. TRUE). /* unpin the smart object */ err = o_unpinobj(smart. /* Object not found if this point is reached */ } /* * o_cmsetconfig: Sets the target associated with config in smart's * table. o_object target ) { o_err err = O_OK. o_vstr *configVstr. i < o_sizeofvstr(configVstr)/sizeof(o_object). o_vstr *targetVstr. &configVstr. /* Search for config in smart's configuration table */ for (i=0. o_object oldTarget.

sizeof(attrPtrs). NULL. /* copy it to a vstr */ o_vstr attrsVstr = o_newvstr(&attrsVstr. return err. NULL. /* unpin the smart object */ err = o_unpinobj(smart. { "z". "" }. "o_4b". O_SINGLE. &attrs[2] }. /* create the class */ 150 . oldTarget. /* Error if this point is reached */ } o_err defineClasses(char *dbname) { o_object schema. 0. err = o_cmaddconfig(smart. O_SINGLE. * Associate this target object with a NULL configuration * object */ oldConfig = (o_object)NULL. -1). NULL }. { "". { "". "o_4b". if (err != O_OK) return err. } } /* dirty the smart object */ err = o_preptochange(smart). &attrs[1]. 0. NULL } }. static o_attrdesc *attrPtrs[] = { &attrs[0].VERSANT Database Fundamentals Manual oldTarget = ((o_object *)*targetVstr)[i]. { "". TRUE). (o_u1b *)attrPtrs). /* statically set up stuff for o_defineclass */ static o_attrdesc attrs[] = { { "x". if (err != O_OK) return err. NULL. "" }. 0. NULL }. O_SINGLE. { "y". return O_OK. /* Set the target object associated with config to target */ ((o_object *)*targetVstr)[i] = target. /* * Insert the old target at the end of the target vstr. oldConfig. if (attrsVstr == NULL) return o_errno. "o_4b". "" }.

if (err != O_OK) goto error. /* The configuration objects */ o_object targetObjects[10]. if (configObjects[i] == NULL) { 151 . NULL). argv[0]). /* The target objects */ /* parse args */ if (argc != 2) { printf("usage: %s <dbname>\n". err = o_beginsession(NULL. target. VERSANT Database Fundamentals Manual schema = o_defineclass("point". o_object smart. char *dbname. char **argv) { o_err err. forwardedSmart. /* create the configuration objects */ for (i = 0. return. } void main(int argc. err = defineClasses(dbname). if (err != O_OK) goto error. return O_OK. TRUE). NULL. NULL. opts). ++i) { configObjects[i] = o_createobj("point". o_opts opts. if (schema == NULL && o_errno != SCH_CLASS_DEFINED) return o_errno. NULL. o_bool isSmart. o_object configObjects[10]. opts[0] = O_CONFIG . /* define the classes */ printf("defineClasses\n"). } dbname = argv[1]. /* begin the session */ printf("o_beginsession\n"). /* populate database */ { o_4b i. i < sizeof(configObjects)/sizeof(o_object). /* free vstr */ o_deletevstr(&attrsVstr). dbname. attrsVstr. dbname.

/* unpin the smart object */ 152 . (o_u1b *)configObjects). TRUE). err = o_cmnewsmartobject(&smart. o_vstr *configVstr. goto error. o_vstr *targetVstr. err = o_cmgettable(smart. if (err != O_OK) goto error. TRUE). &targetVstr. dbname. } err = o_preptochange(smart). /* Set up smart's table */ { *configVstr = o_newvstr(configVstr. } } /* create the target objects */ for (i = 0. sizeof(configObjects). if (targetObjects[i] == NULL) { err = o_errno. NULL. if (smart == NULL) { err = o_errno. goto error.VERSANT Database Fundamentals Manual err = o_errno. goto error. TRUE). } } /* create a new smart object */ printf("o_cmnewsmartobject\n"). if (err != O_OK) goto error. &configVstr. sizeof(targetObjects). (o_u1b *)targetObjects). ++i) { targetObjects[i] = o_createobj("point". printf("o_cmgettable\n"). } } /* set up smart's table */ { o_4b i. *targetVstr = o_newvstr(targetVstr. i < sizeof(targetObjects)/sizeof(o_object).

++i) if ((((o_object *)*configTestVstr)[i] != configObjects[i]) || (((o_object *) *targetTestVstr)[i] != targetObjects[i])) printf(" Error in o_cmgettable\n"). &configTestVstr. NULL. NULL. /* Make sure smart's table has been set up properly */ { o_vstr *configTestVstr. NULL. o_object config2 = o_createobj("point". TRUE). /* test o_cmaddconfig */ { /* insert the (config1. "cmtest"). "cmtest"). if (err != O_OK) goto error. if (err != O_OK) goto error. if (err != O_OK) goto error. VERSANT Database Fundamentals Manual err = o_unpinobj(smart. target1) pair into smart's table */ printf("o_cmaddconfig. 6). target1. if (err != O_OK) goto error. err = o_cmaddconfig(smart. NULL. o_vstr *targetTestVstr. /* make sure objects aren't cached */ err = o_xact(O_COMMIT. TRUE). &targetTestVstr. FALSE). o_object target1 = o_createobj("point". } } /* test demo APIs */ { /* define the new (config. /* compare to what we put in */ for (i = 0. if (err != O_OK) goto error. 6\n"). TRUE). target) pairs */ o_object config1 = o_createobj("point". config1. TRUE). o_object target2 = o_createobj("point". err = o_cmgettable(smart. 153 . TRUE). i < sizeof(configObjects)/sizeof(o_object). /* make sure objects aren't cached */ err = o_xact(O_COMMIT.

FALSE). if (err != O_OK) goto error. /* get smart's table */ err = o_cmgettable(smart. &configTestVstr. if (err != O_OK) goto error. /* verify if the config/target pair is present in the table */ if ((((o_object *)*configTestVstr)[6] != config1) || (((o_object *)*targetTestVstr)[6] != target1)) printf(" Error in o_cmaddconfig\n"). err = o_cmaddconfig(smart. target2. o_vstr *targetTestVstr. } } /* * re-test o_cmaddconfig. this time inserting items at the end * of the table */ { /* insert the (config2. -1). config2.VERSANT Database Fundamentals Manual /* check to make sure o_cmaddconfig works properly */ { o_vstr *configTestVstr. /* make sure objects aren't cached */ err = o_xact(O_COMMIT. &targetTestVstr. if (err != O_OK) goto error. /* check to make sure o_cmaddconfig works properly */ { o_vstr *configTestVstr. FALSE). o_4b configVstrSize. "cmtest"). 154 . &configTestVstr. &targetTestVstr. o_vstr *targetTestVstr. if (err != O_OK) goto error. /* get smart's table */ err = o_cmgettable(smart. -1\n"). target2) pair into smart's table*/ printf("o_cmaddconfig. configVstrSize = o_sizeofvstr(configTestVstr)/sizeof(o_object). o_4b targetVstrSize.

/* make sure objects aren't cached */ err = o_xact(O_COMMIT. configVstrSize = o_sizeofvstr(configTestVstr)/sizeof(o_object). /* verify if config2 has been removed */ if ((((o_object *)*configTestVstr)[configVstrSize-1] != NULL)|| (((o_object *) *targetTestVstr)[targetVstrSize-1] != target2)) printf(" Error in o_cmremoveconfig\n"). VERSANT Database Fundamentals Manual targetVstrSize = o_sizeofvstr(targetTestVstr)/sizeof(o_object). } 155 . targetVstrSize = o_sizeofvstr(targetTestVstr)/sizeof(o_object). "cmtest"). &targetTestVstr. } } /* test o_cmremoveconfig */ { printf("o_cmremoveconfig\n"). /* remove config2 from smart's table */ err = o_cmremoveconfig(smart. /* verify if the config/target pair is present in the table */ if ((((o_object *)*configTestVstr)[configVstrSize-1] != config2) || (((o_object *) *targetTestVstr)[targetVstrSize-1] != target2)) printf(" Error in o_cmaddconfig\n"). if (err != O_OK) goto error. o_4b targetVstrSize. if (err != O_OK) goto error. o_vstr *targetTestVstr. /* check to make sure o_cmremoveconfig works properly */ { o_vstr *configTestVstr. o_4b configVstrSize. if (err != O_OK) goto error. /* get smart's table */ err = o_cmgettable(smart. &configTestVstr. config2). FALSE).

o_vstr *targetTestVstr. targetVstrSize = o_sizeofvstr(targetTestVstr)/sizeof(o_object). i < configVstrSize. ++i) { if (((o_object *)*configTestVstr)[i] == config1) { if (((o_object *)*targetTestVstr)[i] != newTarget) printf(" Error in o_cmsetconfig\n"). o_4b configVstrSize. /* check to make sure o_cmsetconfig works properly */ { o_vstr *configTestVstr. o_4b i. /* get smart's table */ err = o_cmgettable(smart. /* set the target associated with config1 */ printf("o_cmsetconfig\n"). /* make sure objects aren't cached */ err = o_xact(O_COMMIT. TRUE). FALSE). config1. newTarget). if (err != O_OK) goto error. break. } } /* Check if the last item in the target table is target1 */ 156 . if (err != O_OK) goto error. configVstrSize = o_sizeofvstr(configTestVstr)/sizeof(o_object).VERSANT Database Fundamentals Manual } /* test o_cmsetconfig */ { o_object newTarget = o_createobj("point". if (err != O_OK) goto error. &targetTestVstr. &configTestVstr. "cmtest"). o_4b targetVstrSize. NULL. err = o_cmsetconfig(smart. /* Check if the target associated with config1 is newTarget */ for (i = 0.

if (err != O_OK) goto error. NULL). err = o_endsession(NULL. error: { printf(" => err #%ld\n". VERSANT Database Fundamentals Manual i = targetVstrSize. /*Check if the last item in the config table is NULL*/ i = configVstrSize. return. err). } } 157 . } } } /* end the session */ printf("o_endsession\n"). return. if (((o_object *)*targetTestVstr)[i-1] != target1) printf(" Error in o_cmsetconfig \n"). if (((o_object *)*configTestVstr)[i-1] != (o_object)NULL) printf(" Error in o_cmsetconfig \n").

........... 165 Object Sharing Methods ............................................................................................................................................................................................. 166 158 ............................................ 164 Storage Transforms for Vstr Types ................................................................................................................VERSANT Database Fundamentals Manual Chapter 9: Object Sharing Mixing C and C++ Code and Objects...................................... 162 Storage Transforms for Special Embedded Types ....................................................................................................... 164 Storage Transforms for Fixed Array Types ........................................... 159 Storage Transform Concepts............................................ 162 Storage Transforms for Elemental Data Types ................................................

• For vstrs. use o_preptochange() instead of the C++ PObject::dirty() method. or PObject*.h" // wrong way . you should include cxxcls/pobject. o_setattr(). type*. • For link vstrs. Use the following approach to access C objects with the C++ Interface: • Include the C interface header file in the following manner: extern "C" { #include "omapi. VERSANT Database Fundamentals Manual Mixing C and C++ Code and Objects The best way to handle objects created with C++/VERSANT is with C++ applications. use o_locateobj().your C++ compiler will think that the C/VERSANT functions in omapi. use either Vstr<type> or VstrAny. acquire a write lock.h. • To access C++ objects with the C Interface. use o_createobj() rather than the C++ O_NEW_PERSISTENT() syntax. • To acquire a write lock and mark an object for update.h before omapi.h" }. 159 . • For a link. use LinkVstrAny instead of LinkVstr<type>. If your C++ object uses simple inheritance. use LinkAny or o_object instead of Link<type>. the easiest way is to write in C++ and use the C++ interface to handle the C++ objects and simultaneously use the C Interface to handle the C objects. and o_getattr() in a normal manner to retrieve and access C++ objects. use o_setattr() instead of a C++ method.. • To create a new C object. or vice versa. • To modify an attribute. use the C function o_locateobj() instead of the C++ dereference operators ->. you can use casting to a struct pointer to access the fields. and mark an object for update. • To retrieve objects from a database. To handle both C and C++ objects in the same application. The best way to handle objects created with C/VERSANT is with C applications. which will result in linker errors for each C/VERSANT function referenced. // right way If you include the C interface header file as: #include "omapi. Also.h should have a C++ linkage. The only times that it makes sense to mismatch interfaces is when you want a C object to reference a C++ object.

A sample program which allows a user to manage a VVSet<Type> collection can be found in the VERSANT filein/demos directory. You can use /VERSANT to access and manipulate all C++/VERSANT collection classes if you implement hash functions in both C++ and that operate in the two environments in the same way. Float. Double. because native C++ and hash functions work differently. You can compute a combined hash value by using #vElementalCombinedHash:. ByteString. in the PVirtual class. This is particularly useful if you need to view schemas defined from C++/VERSANT which are not intended for object sharing. You can store transient. then create and reserve an attribute in the class when you define it in C++. runtime information. but you should not use them to store runtime information. runtime information or relationships in attributes defined as having the #VSI_ST_NIL storage transform. With these hashing methods. Attribute names added by C++/VERSANT. for each member. You cannot run the methods on an object created with the C Interface since the internal C++ pointers are not initialized properly. In other words.VERSANT Database Fundamentals Manual Objects deriving from PObject have one attribute of type PClass* that will show at the top of your objects. you can develop a sharable persistent collection that involves hash look up. Character. You can perform queries over imported classes using the same /VERSANT methods that you would use 160 . You can browse through the class definitions in a database by sending the message #metaInfoFor: to the /VERSANT VMetaType class.. You can store transient. or PObject. because future VERSANT releases may suppress these attributes when classes are imported into /VERSANT. If you want to use an attribute to store transient. You will receive a VMetaType instance that describes the corresponding database schema without your having to import the corresponding class. runtime information. your hash function must return the same hash value in both C++ and . such as __what and __vptr also have a #VSI_ST_NIL storage transform. This requirement requires care. There are some restrictions on queries over imported classes. You can compute an elemental hash value by sending #vElementalHash to an instance of Integer. All C++/VERSANT collection classes may be used. You can browse a database using VMetaType class.

Database types and their corresponding type indicators are: VDate <VSI_ST_VDATE> VTime <VSI_ST_VTIME> 161 . because of possible variants in the way can map values (to SmallInteger or LargeInteger). /VERSANT will do any necessary conversions between instance variable names and database schema attribute names. you must prefix the value key with a type indicator in a pair of angle brackets. To get actual database names corresponding to an instance variable name. if you are querying on an age attribute in a Person class. you must use the actual database attribute names and types known to the database rather than the variable names and types associated with the class as it appears in your Image. you can send the following message to the class with the instance variable: #databaseAttributeNameFor: • When you perform a normal query. the data types defined for the class in its database are often mapped to corresponding /VERSANT data types (see the following section for information on how types are mapped. you must also provide a type indicator. there are some restrictions and differences in usage. For normal queries. VERSANT Database Fundamentals Manual for any other persistent class. then you must specify the query string as age=<VSI_ST_U1B>55 rather than age=55. For example.) For example. you can use instance variable names as they appear in the class definitions in your Image. • If you are querying on a date or time attribute defined with the C++/VERSANT VDate or VTime classes. When you import a class. The database types and their corresponding type indicators are: o_u1b <VSI_ST_U1B> o_u2b <VSI_ST_U2B> o_2b <VSI_ST_2B> o_u4b <VSI_ST_U4B> o_4b <VSI_ST_4B> The default type indicator is <VSI_ST_4B>. • When you perform a path query. and the age attribute has the database type o_u1b. However. • If you are querying on an elemental data type.

unsigned integer). while the corresponding database data type char can only assum the values between -128 and 127. attribute values are converted to native objects. Storage Transforms for Elemental Data Types C++ Database Transform Allowable o_1b char #VSI_ST_CHAR 0 to 127 char char #VSI_ST_CHAR 0 to 127 162 . This can cause problems. The first column of the table list the data type that you might be using in your C++/VERSANT application when define the persistent classes. In general. When that object is written back to a database. you must take responsibility for choosing the right C++ data type when creating classes whose instances will be used by both C++ and applications. for an embedded VTime attribute. Similarly. the data type o_u1b will be mapped to the class SmallInteger. For basic elemental data types. all the following predicate strings are both valid and equivalent to one another: "Use actual seconds of the VTime attribute. the mapping between a database data type and type may be supported only within a given range. the supported data range is also listed. because a SmallInteger can contain a larger value than o_u1b. p valuesAt: #(#x) put: (Array with: timestamp). The fourth column gives the corresponding storage transform symbol. p := VPredicate from: 'time = <VSI_ST_VTIME>:x'. The following table lists all the type mapping supported in the current /VERSANT interface. suppose that a database contains a class with an attribute of data type o_u1b (a one-byte. VERSANT will attempt to convert the value of type SmallInteger back to type o_u1b. The third column is the name of the class that the corresponding database data type would be mapped to. Due to language differences." 'time = 811836204' "Use the Timestamp formatted string." | timestamp pred | timestamp := Timestamp readFrom: '9/22/95 11:04pm'. Storage Transform Concepts When an object is read from a database into a Image.VERSANT Database Fundamentals Manual For example. The second column lists the data type that the corresponding first column would be converted to. When an object of that class is read from a database. these objects are converted back to values of their database domain type. a Character can have value from 0 to the largest SmallInteger. For example." 'time = <VSI_ST_VTIME>''9/22/95 11:04pm''' "Use term key substitution. When an object in an Image is written to a database.

VERSANT Database Fundamentals Manual signed char char #VSI_ST_CHAR 0 to 127 o_bool o_u1b #VSI_ST_U1B 0 to 255 o_u1b o_u1b #VSI_ST_U1B 0 to 255 unsigned o_u1b #VSI_ST_U1B 0 to 255 o_2b o_2b #VSI_ST_2B -32768 to +32767 short o_2b #VSI_ST_2B -32768 to +32767 signed o_2b #VSI_ST_2B -32768 to +32767 o_u2b o_u2b #VSI_ST_U2B 0 to 65535 unsigned o_u2b #VSI_ST_U2B 0 to 65535 short o_4b o_4b #VSI_ST_4B -2147483648 to +2147483647 int o_4b #VSI_ST_4B -2147483648 to +2147483647 long o_4b #VSI_ST_4B -2147483648 to +2147483647 signed int o_4b #VSI_ST_4B -2147483648 to +2147483647 signed long o_4b #VSI_ST_4B -2147483648 to +2147483647 o_u4b o_u4b #VSI_ST_U4B 0 to +4294967295 unsigned o_u4b #VSI_ST_U4B 0 to +4294967295 unsigned o_u4b #VSI_ST_U4B 0 to +4294967295 int unsigned o_u4b #VSI_ST_U4B 0 to +4294967295 long o_float o_float #VSI_ST_FLOAT -10**38 to -+10**38. 14 digits of accuracy double o_double #VSI_ST_DOUBLE -10**307 to +10**307. 14 digits of accuracy type* o_ptr #VSI_ST_NIL nil Link<Type> Link<Type #VSI_ST_OBJECT > o_object o_object #VSI_ST_OBJECT 163 . 6 digits of accuracy float o_float #VSI_ST_FLOAT -10**38 to -+10**38. 6 digits of accuracy o_double o_double #VSI_ST_DOUBLE -10**307 to +10**307.

Mapping these types to the Date and Timestamp class allows objects to share the behavior of the two existing classes. attributes are instantiated as instances of Date and Timestamp. it eliminates the need to duplicate the effort in providing methods for manipulating related attributes in each application specific imported class. Storage Transforms for Fixed Array Types C++ Database Transform o_1b[n] char[n] #VSI_ST_CHAR_ARRAY char[n] char[n] #VSI_ST_CHAR_ARRAY signed char[n] char[n] #VSI_ST_CHAR_ARRAY o_u1b[n] o_u1b[n] #VSI_ST_U1B_ARRAY unsigned char[n] o_u1b[n] #VSI_ST_U1B_ARRAY o_2b[n] o_2b[n] #VSI_ST_2B_ARRAY short[n] o_2b[n] #VSI_ST_2B_ARRAY signed short[n] o_2b[n] #VSI_ST_2B_ARRAY o_u2b[n] o_u2b[n] #VSI_ST_U2B_ARRAY unsigned short[n] o_u2b[n] #VSI_ST_U2B_ARRAY o_4b[n] o_4b[n] #VSI_ST_4B_ARRAY int[n] o_4b[n] #VSI_ST_4B_ARRAY long[n] o_4b[n] #VSI_ST_4B_ARRAY signed int[n] o_4b[n] #VSI_ST_4B_ARRAY signed long[n] o_4b[n] #VSI_ST_4B_ARRAY o_u4b[n] o_u4b[n] #VSI_ST_U4B_ARRAY unsigned[n] o_u4b[n] #VSI_ST_U4B_ARRAY unsigned int[n] o_u4b[n] #VSI_ST_U4B_ARRAY unsigned long[n] o_u4b[n] #VSI_ST_U4B_ARRAY 164 . These two embedded types are handled specially. because they are widely used in C++/VERSANT applications. Methods are available to do date and timestamp value conversion between Date to VDate and between Timestamp and VTime. Also. When brought into .VERSANT Database Fundamentals Manual Storage Transforms for Special Embedded Types C++ Database Transform VDate VDate Date #VSI_ST_VDATE VTime VTime Timestamp #VSI_ST_VTIME VDate and VTime are C++/VERSANT classes used for attributes.

VERSANT Database Fundamentals Manual o_float[n] o_float[n] #VSI_ST_FLOAT_ARRAY float[n] o_float[n] #VSI_ST_FLOAT_ARRAY o_double[n] o_double[n] #VSI_ST_DOUBLE_ARRAY double[n] o_double[n] #VSI_ST_DOUBLE_ARRAY type *[n] o_ptr[n] #VSI_ST_NIL_ARRAY Link<Type>[n] Link<Type> [n] #VSI_ST_OBJECT_ARRAY o_object[n] o_object[n] #VSI_ST_OBJECT_ARRAY Storage Transforms for Vstr Types C++ Database Transform Vstr<o_1b> Vstr<char> #VSI_ST_CHAR_VSTR Vstr<char> Vstr<char> #VSI_ST_CHAR_VSTR PString Vstr<char> #VSI_ST_CHAR_VSTR VString Vstr<char> #VSI_ST_CHAR_VSTR Vstr<o_u1b> Vstr<o_u1b> #VSI_ST_U1B_VSTR Vstr<unsigned char> Vstr<o_u1b> #VSI_ST_U1B_VSTR Vstr<o_2b> Vstr<o_2b> #VSI_ST_2B_VSTR Vstr<short> Vstr<o_2b> #VSI_ST_2B_VSTR Vstr<signed short> Vstr<o_2b> #VSI_ST_2B_VSTR Vstr<o_u2b> Vstr<o_u2b> #VSI_ST_U2B_VSTR Vstr<unsigned short> Vstr<o_u2b> #VSI_ST_U2B_VSTR Vstr<o_4b> Vstr<o_4b> #VSI_ST_4B_VSTR Vstr<int> Vstr<o_4b> #VSI_ST_4B_VSTR Vstr<long> Vstr<o_4b> #VSI_ST_4B_VSTR Vstr<signed int> Vstr<o_4b> #VSI_ST_4B_VSTR Vstr<signed long> Vstr<o_4b> #VSI_ST_4B_VSTR Vstr<o_u4b> Vstr<o_u4b> #VSI_ST_U4B_VSTR Vstr<unsigned> Vstr<o_u4b> #VSI_ST_U4B_VSTR Vstr<unsigned int> Vstr<o_u4b> #VSI_ST_U4B_VSTR Vstr<unsigned long> Vstr<o_u4b> #VSI_ST_U4B_VSTR Vstr<o_float> Vstr<o_float> #VSI_ST_FLOAT_VSTR Vstr<float> Vstr<o_float> #VSI_ST_FLOAT_VSTR 165 .

type — Answer the attribute type. ByteString vElementalHash — Answer a hash value for a ByteString object. name — Answer the name of a database class. loadSourceFromDB: — Load file-out source. PVirtual vElementalCombinedHash: — Answer a combined hash value. VMetaType allCXXDefinedSchemsFromDB: — Answer descriptions of all database classes. attributes — Answer descriptions of class attributes. vElementalHash — Answer an integer value that can be used as a hash index in a collection. repeatFactor — Answer the attribute repeat factor. VAttribute domain — Answer the database class name. PObject fileInSourceFromDB: — Answer file-out source text. ODBInterface importSchema: — Import a class definition. metaInfoFor: — Answer a description of a database class. 166 .VERSANT Database Fundamentals Manual Vstr<o_double> Vstr<o_double> #VSI_ST_DOUBLE_VSTR Vstr<double> Vstr<o_double> #VSI_ST_DOUBLE_VSTR LinkVstr<Type> LinkVstr<Type> #VSI_ST_OBJECT_VSTR Object Sharing Methods Following are methods useful when sharing objects. storageTransform — Answer the derived storage transformation symbol for the attribute. name — Answer the attribute name. storeSourceToDB: — Store file-out source. supers — Answer descriptions of super classes.

167 . VERSANT Database Fundamentals Manual Character vElementalHash — Answer a hash value for a Character object. Double vElementalHash — Answer a hash value for a Double object. Float vElementalHash — Answer a hash value for a Float object. Integer vElementalHash — Answer a hash value for an Integer object.

........................................................................................................................ C++/VERSANT Example .................. 186 Optimistic Locking............................................................................... 186 168 .......................................... 179 Optimistic Locking General Notes ........................................................................ 169 Optimistic Locking Actions ...................................... 184 Examples ...................................................... 178 Optimistic Locking Prototocol .................................................................................................................................................................................................................................................................... 171 Multiple read inconsistencies................VERSANT Database Fundamentals Manual Chapter 10: Optimistic Locking Optimistic Locking Overview ..................................

which means that you will get immediate access. which only defers the issue of which version is the "correct" one. you could version the object you want to access. holding a lock on all objects you access can interfere with the work of others. Optionally use event notification methods. update. VERSANT Database Fundamentals Manual Optimistic Locking Overview Sometimes locking is too costly Standard VERSANT read. but that each change will create a new version. 169 . do the following. How to use optimistic locking features To use VERSANT optimistic locking features to work with unlocked objects. For example. VERSANT provides optimistic locking features that allow you to work with objects without holding locks. and then check it in. you may want to read a large number of objects but update only a few of them. • Start an optimistic locking session. however. In this situation. However. Following an optimistic locking protocol will ensure the coherence and consistency normally provided by locks. you can safely checkout an object without a lock. which will allow fine-grain control over the objects you want to change. update it. These guarantees are necessary and appropriate under most circumstances. • Follow an optimistic locking protocol. but the side effects of the alternative approaches might not be right for your situation. and write locks provide consistent and coherent access guarantees in a multiple user environment. • Optionally use event notification. Or. Or. You do not have to use optimistic locking features to safely access and update unlocked objects. which may not be what you want. Optionally use performance related methods. you may be in a situation where there is only a small chance that the objects you want to work with will be updated by others. which will let you know when objects held with optimistic locks are modified. Accordingly. Sometimes. checking in an unlocked object will create a new object with a new logical object identifier. • Optionally use special methods. • Add a time stamp attribute to class definitions.

170 . At the same time. and group write time will still keep databases consistent. delete. which will improve performance and improve concurrency of access among multiple users. you will get a shorter duration of locking. the time stamp validation at commit.VERSANT Database Fundamentals Manual By doing the above.

" add a time stamp attribute to the class definitions for the objects you will be accessing. However. Thereafter. If an object has a time stamp attribute. When an object with a time stamp attribute is created. delete. and check time stamp methods will automatically use the time stamp to detect obsolete copies in the object cache and prevent you from using the obsolete copies as the basis for changing the database object. group write. C/VERSANT To define a time stamp attribute in a C class. An obsolete copy will occur if. add the following lines to your attribute descriptions: 171 . and group write method will overwrite changes made by another user since you read your object. both because of the necessary fetching of objects and because of the time required to make detailed evaluations of each attribute in each object. For example. When you detect an obsolete copy by checking time stamps. you will automatically be told if your commit. delete. you might want to refresh your copy of the object. its time stamp attribute is set to 0. VERSANT Database Fundamentals Manual Optimistic Locking Actions Add time stamp attribute To make a class "optimistic locking ready. each update written to a database will increment the attribute by 1 during the normal commit and group write process. and delete methods to tell you if you have an obsolete copy. and then reapply some or all of your modifications. no matter who does the updating and no matter the kind of session used. Once you add a time stamp attribute to an object. while you are working with an unlocked copy of an object. what you do next is up to you. An obsolete copy will also occur if you try to modify an object that another user has already deleted. the time stamp attribute will be updated. the VERSANT commit. You could avoid having obsolete copies by first refreshing every unlocked object you wanted to change before proceeding to a commit. inspect it. another user updates the original object in the database. Or you may simply want to abandon your update. If your object has a time stamp attribute. You can rely on normal commit. this would be costly. or you can detect obsolete copies in your object cache by using the "check time stamp" method before your commit. Time stamps are a convenience feature. The procedures to add a time stamp attribute to a class is tightly bound to your interface language. group write.

O_SINGLE. all implicit lock upgrades are suppressed. add the following lines to your class definitions: class SampleClass : public PObject { public: O_TS_TIMESTAMP. before calling o_defineclass(). C++/VERSANT To define a time stamp attribute in a C++ class. In an optimistic locking session. When 172 . You must be careful to check both the objects marked dirty and the objects inter-related to them. . as long as you like. } clsInstance.VERSANT Database Fundamentals Manual static o_attrdesc clsAttrs[] = { {TIMESTAMP_ATTR_NAME_STR. . as soon as you mark an object dirty. c o_beginsession() with O_OPT_LK c++ beginsession() with O_OPT_LK Check time stamps Check time stamps to detect any obsolete copies in the object cache. }. VERSANT will attempt to acquire a write lock on that object. NULL. 0}. Of course.""}. Begin optimistic locking session In other kinds of sessions.{"". add the following lines to your class definition struct: typedef struct { O_TS_TIMESTAMP. without setting and holding a lock. An optimistic locking session will also suppress object swapping and provide automatic detection of obsolete copies. . . }. . Then. a write lock will still automatically be set on dirty objects when you commit. . Suppression of implicit lock upgrades allows you to continue working with your objects. TIMESTAMP_ATTR_TYPE_STR. which is the point of using optimistic locking.

you must be careful to place in the vstr or collection all objects marked dirty and all objects inter-related to them. (Exceptions are the C++/VERSANT commit() and rollback() methods. However. in an optimistic locking session. you should consider both hierarchial relationships (such as subclass objects) and logical relationships. c o_xactwithvstr() c++ xactwithvstr() Commit and retain cache Rollback and retain cache Most commit and rollback routines allow you optionally to prevent flushing of the object cache. 173 . c o_downgradelocks() c++ downgradelocks() Delete objects Delete objects in a vstr or collection. say. This method enhances performance by deleting a group of objects with the least possible number of network messages. c o_checktimestamps() c++ checktimestamps() Downgrade short lock Release locks on specified objects without flushing objects from the object cache. An example of a logical relationship is when. In this case.) However. you should consider both hierarchial relationships (such as subclass objects) and logical relationships. say. VERSANT Database Fundamentals Manual you consider inter-related objects. you want to change B only if A is greater than 10. An example of a logical relationship is when. When you consider inter-related objects. if you use a group commit or rollback. c o_gdeleteobjs() c++ gdeleteobjs() Checkpoint commit short transaction with group Perform a checkpoint commit on objects in a vstr or collection and maintain objects in the object cache. a better way to handle the object cache is to use commit and rollback routines that operate only on objects in a vstr or collection. you want to change B only if A is greater than 10. you should check both B (the changed object) and A (the logically related object) in order to prevent changing B if the value of A has changed since you read it.

If you are using optimistic locking. If you know that you always want to downgrade read locks on fetched objects. use a "set thread options" routine with the O_DROP_RLOCK option. drop read locks when objects are retrieved from a database. This might be useful. To automatically downgrade read locks. This option will have no impact on intention read locks set on the class objects corresponding to the instance objects retrieved. O_DROP_RLOCK For this thread. Following is a description of the O_DROP_RLOCK option. Read locks are held on instance objects during the duration of the read operation (which protects you from seeing uncommitted objects) and then dropped when the read operation is finished. you will want to drop the read lock on the fetched object as soon as possible.VERSANT Database Fundamentals Manual Commit and retain cache c o_xact() c++ xact() Commit a group of objects c o_xactwithvstr() c++ xactwithvstr() Rollback and retain cache c o_xact() c++ xact() Rollback a group of objects c o_xactwithvstr() c++ xactwithvstr() C/VERSANT and C++/VERSANT An option in o_xact() and xact() allow you to prevent flushing the entire object cache after a commit. Drop read locks automatically When you fetch an object. 174 . This approach does not require you to keep track of fetched objects and reduces network calls. but normally you would use the commit with vstr routine in an optimistic locking session. many routines will place a read lock on the object. you can specify automatic lock downgrading. One way to drop a read lock is to track the objects fetched and then explicitly drop the lock with a routine such as the C/VERSANT o_downgradelock() function.

If you toggle O_DROP_RLOCK in the middle of a cursor select. except that only read and intention read locks are dropped. the new option will take effect at the next retrieval of objects. o_getthreadoptions() — Get thread options. VERSANT Database Fundamentals Manual If you want to always drop read locks after fetching objects. because it causes locks to be dropped by the database server process. By comparison. If you toggle O_DROP_RLOCK in the middle of a cursor fetch. o_refreshobj() — Refresh object. Thread option routines C/VERSANT thread option functions o_setthreadoptions() — Set thread options. Read locks are dropped if the lockmode parameter is RLOCK or IRLOCK. Read locks will be dropped if the instlock parameter in o_pathselectcursor() is specified as RLOCK or IRLOCK and O_CURSOR_RELEASE_LOCK is not specified in the options parameter. A read lock is dropped if the lockmode parameter is 175 . when invoked by a thread for which O_DROP_RLOCK has been set. o_locateobj() — Get object. this option reduces network calls. This option may be used in a standard session or an optimistic locking session. o_fetchcursor() — Get object with cursor created by o_pathselectcursor(). dropping locks with a down grade lock routine requires a separate network message from the application process to the server process. Read locks will be dropped if the instlock parameter is specified as RLOCK or IRLOCK and O_CURSOR_RELEASE_LOCK is not specified in the options parameter. C/VERSANT functions that are affected by O_DROP_RLOCK The following routines. will drop read locks on fetched objects. o_unsetthreadoptions() — Restore thread options to their defaults. o_getclosure() — Get object closure. o_pathselectcursor() — Find object with cursor. This behavior is the same as setting the options parameter to be O_DOWN_GRADE_LOCKS parameter. the new option will take effect at the next retrieval of objects. Read locks are dropped if the lockmode parameter if RLOCK or IRLOCK. A read lock will be dropped if the lockmode parameter is RLOCK or IRLOCK. o_greadobjs() — Get objects.

the new option will take effect at the next retrieval of objects. greadobjs() — Get objects. when invoked by a thread for which O_DROP_RLOCK has been set. The default is to not drop read locks when objects are fetched. If you toggle O_DROP_RLOCK in the middle of a cursor fetch. o_getattr() — Get attribute value.VERSANT Database Fundamentals Manual RLOCK or IRLOCK. select() — Find object with cursor. locateobj() — Get object. will drop read locks on fetched objects. Read locks will be dropped if the instlock parameter VCursor() is specified as RLOCK or IRLOCK and O_CURSOR_RELEASE_LOCK is not specified in the options parameter. This behavior is the same as setting the options parameter to be O_DOWN_GRADE_LOCKS parameter. getclosure() — Get object closure. o_refreshobjs() — Refresh objects. Different threads in the same session may have different settings for thread options. unsetthreadoptions() — Restore thread options to their defaults. C++/VERSANT thread option methods setthreadoptions() — Set thread options. If you toggle O_DROP_RLOCK in the middle of a cursor select. o_getattroffset() — Get attribute offset. C++/VERSANT methods that are affected by O_DROP_RLOCK The following routines. fetch() — Get object with cursor. getthreadoptions() — Get thread options. Read locks are dropped if the lockmode parameter 176 . except that only read and intention read locks are dropped. Read locks are dropped if the lockmode parameter is RLOCK or IRLOCK. Read locks are dropped if the lockmode parameter if RLOCK or IRLOCK. A read lock will be dropped if the lockmode parameter is RLOCK or IRLOCK. Read locks will be dropped if the instlock parameter is specified as RLOCK or IRLOCK and O_CURSOR_RELEASE_LOCK is not specified in the options parameter. Read locks are dropped if the default lock mode is RLOCK or IRLOCK. the new option will take effect at the next retrieval of objects. Read locks are dropped if the default lock mode is RLOCK or IRLOCK.

getattroffset() — Get attribute offset. Read locks are dropped if the default lock mode is RLOCK or IRLOCK. 177 . VERSANT Database Fundamentals Manual is RLOCK or IRLOCK. A read lock is dropped if the lockmode parameter is RLOCK or IRLOCK. refreshobjs() — Refresh objects. Read locks are dropped if the lockmode parameter is RLOCK or IRLOCK. get_attribute_value() — Get attribute value. Read locks are dropped if the default lock mode is RLOCK or IRLOCK. refreshobj() — Refresh object.

178 . no lock specified. Object B: state 2. no lock database it as state 2. no lock Time 6 You read Object B with a read lock. read lock automatic downgrading has been Object B: state 1. read lock Time 7 You see Object A with state 1 and Object A: state 2. no lock Object B: state 1. no lock Object B: state 2. Example of Multiple Read Inconsistency — the danger of using implicit read lock downgrade mechanisms. no lock Time 3 You see Object A with state 1. because the objects were retrieved at different times and their read locks were dropped at different times. Object B: state 2. read lock Object B: state 1. write lock Object B and commits the changes. Object B: state 2. Because Object A: state 1. because operations may have been performed on your objects between your reads. Object cache (what you see) Server cache (what database sees) Time 1 Object A: state 1. your objects may not be consistent. your read lock is downgraded. Time 4 Another session modifies Object A and Object A: state 2. no lock Object B with state 2. write lock Time 5 You see Object A with state 1. but to the Object A: state 2. no lock What you see at Time 7 is inconsistent with both the initial and the current database states. Object A: state 1. no lock Time 2 You read Object A with a read lock. you must be able to tolerate multiple read inconsistencies. Object A: state 2. If you are going to use the O_DROP_RLOCK option.VERSANT Database Fundamentals Manual Multiple read inconsistencies If you perform multiple reads in separate operations and have set the O_DROP_RLOCK option on.

Read locks are necessary to ensure consistency among the objects in your optimistic transaction set. When you use optimistic locking. In an optimistic locking session. • You are working within an optimistic locking session. which would compromise consistency. because the next time you touched a swapped object. In an optimistic locking session. VERSANT Database Fundamentals Manual Optimistic Locking Prototocol In other kinds of sessions. Downgrade locks. Normally. 179 . you must take responsibility for coherence and consistence by following an optimistic locking protocol. Optimistic locking protocol assumes: • The objects involved have time stamp attributes. 3. 2. locks ensure that your objects and databases are coherent and consistent. This could cause problems. a subclass object might be updated while you were fetching a superclass object. you should observe the following protocol. For example. copying an object from a database will normally set a read lock and pin the object in your object cache. use a "downgrade locks" routine to drop locks without changing the pin status. In other kinds of sessions. if you did not fetch your objects with a read or stronger lock. you must take responsibility for coherence and consistence by following an optimistic locking protocol. although you must set the right locks at the right time. Pins are necessary to avoid automatic flushing. The group of objects you bring into your object cache is called the "optimistic transaction set. although you must set the right locks at the right time. Once you have a consistent group of objects. 1." Unless you change the default lock or override the default lock in a group read method. locks ensure that your objects and databases are coherent and consistent. Read objects with locks and pins. Fetch your objects from their databases with read locks and pins. if you run out of virtual memory for your cache. Start an optimistic locking database session. you would get a new copy which might not be consistent with the rest of your original optimistic transaction set. VERSANT will swap unpinned objects back to their databases at its own discretion.

You can either choose a method that will keep your objects in your cache. so if you do find objects that are obsolete. Commit or rollback changes. or group delete only on the desired group of objects (as explained in a following step). Because you are in an optimistic locking session. for a thread. VERSANT will not set a write lock on the object. For example. you may want to refresh your copy with the "refresh objects" routine. Per normal behavior. VERSANT does the following: a. or choose a method that will flush objects to their databases. and versioning methods will continue to implicitly set write locks on class objects. Keeping inter-dependent objects together is important. At any time. if you change an object. you will probably want to place all objects that you change into a vstr or collection. VERSANT increments the time stamp (if it exists) of each dirty 180 . For performance reasons. 6. you can set automatic lock downgrading on. check out. check in. for example. be sure that you also place in the group all objects with inter-dependencies with the changed objects. by dereferencing an object outside the optimistic transaction set. this can happen. In C++ . so that you can continue working with them. either at the time of a group commit or in an explicit time stamp checking step. During this stage. if you touch an object not fetched during the read phase. This will allow you to perform a commit. If you call these methods in an optimistic locking session. In the application process. Before proceeding to a commit.VERSANT Database Fundamentals Manual Alternately. but it is better to avoid fetching additional objects to prevent introducing an object not consistent with the original set of objects. Check time stamps (preferred). If you place only the objects that you change into a vstr or collection (rather than all objects in the optimistic transaction set). Using normal procedures. schema evolution. you can. a read lock may be set by default. Browse and update. browse and update the optimistic transaction set. 5. 4. group write. The check time stamp method will set the default lock on all objects checked. you will want to make sure that the time stamps for its associated objects are also checked. these implicit locks will be held until your enclosing short or long transaction ends. when you mark an object dirty. During this time. set the default lock to a null lock. At commit time. if you want. you can save or roll back your updates with a transaction commit or rollback. you should use the "check time stamp" routine to determine which of your changed objects have become obsolete.

" If all objects pass the time stamp validation. e. you should use a read lock. then the commit succeeds. If one or more objects fail the time stamp validation. Application_1 and Application_2. and the check made in ‘e’ constitutes a "time stamp validation sequence. If the time stamp of the dirty object is not greater than the time stamp of the source object by one. suppose that you have two applications. Rolling back the transaction will restore the objects to their values before they were modified. perhaps because some objects have outdated time stamps or have been deleted by another user. The refreshed objects will be different from the timestamp failed objects or they will have been deleted (in which case. To improve performance.. If your commit fails. c.) For example. If the time stamp of the dirty object is greater than the time stamp of the source object by one. suppose the following sequence of events occurs. you can optionally use a method that will commit or rollback changes only to objects in a vstr or collection. This allows you to limit the scope of the objects to be locked during the commit and whose time stamps are to be compared. you will see an "object not found" error. If your commit fails. Refreshing the failed objects will load the latest committed objects from the server. you can either rollback or refresh the failed objects and try again. Steps a. b. ObjectA and ObjectB. If you refresh the objects. At commit time. For each dirty object. VERSANT writes the dirty object to the database. VERSANT sets a write lock on its source object in its source database. d. On each dirty object.. then the commit fails. Action Application_1 Application_2 181 . VERSANT does not write the dirty object to the database. who are both working with the same two objects. VERSANT Database Fundamentals Manual object by one. Now. VERSANT sends dirty objects from the object cache to their source databases in batches. d. VERSANT compares the time stamp in the dirty object with the time stamp in the source object. VERSANT will normally scan all objects in your object cache looking for those marked dirty and will flush your object cache at the end of the transaction.

this means using the option O_ROLLBACK_AND_RETAIN with a transaction routine such as o_xact() or xact(). if Application_1 does a complete rollback. In this case." For C and C++. Application_1 will see the following: ObjectA timestamp = 0 value = X_2 ObjectB timestamp = 0 value = Y 182 . Alternately.VERSANT Database Fundamentals Manual Action Application_1 Application_2 Initial conditions ObjectA ObjectA Timestamp = 0 timestamp = 0 Value = X value = X ObjectB ObjectB Timestamp = 0 timestamp = 0 Value = Y value = Y Both modify some objects ObjectA ObjectA Timestamp = 0 timestamp = 0 Value = X_1 value = X_2 ObjectB ObjectB Timestamp = 0 timestamp = 0 Value = Y_1 value = Y Application_2 commits and ObjectA ObjectA reads its results back Timestamp = 0 timestamp = 1 Value = X_1 value = X_2 ObjectB ObjectB Timestamp = 0 timestamp = 0 Value = Y_1 value = Y Application_1 tries to ObjectA ObjectA commit but fails due to Timestamp = 0 timestamp = 1 timestamp of ObjectA Value = X_1 value = X_2 ObjectB ObjectB Timestamp = 0 timestamp = 0 Value = Y_1 value = Y At this point. all objects would be flushed from the object cache. Application_1 could perform a "rollback and retain.

183 . This is intended behavior and will only be experienced by the application whose commit fails because of timestamp failures. note that the timestamps for dirty objects are incremented even though they fail timestamp validation. VERSANT Database Fundamentals Manual If Application_1 refreshes each object. then Application_1 will see the following: ObjectA timestamp = 1 value = X_2 ObjectB timestamp = 1 value = Y_1 In the above.

VERSANT Database Fundamentals Manual Optimistic Locking General Notes Compatibility with strict locking schemes If you start any kind of session other than an optimistic locking or custom locking session. you will really be running with a mixture of optimistic and strict locking. schema evolution. Optimistic locking sessions are compatible with strict locking sessions run by other users. or versioning method in an optimistic locking session. you will use "strict locking. Compatibility with savepoints Savepoints are not compatible with optimistic locking. as long as you stay aware of what is happening. Compatibility with nested transactions Optimistic locking cannot be used with nested transactions. remember that a query first flushes all dirty objects and marks them as clean before 184 . which resets locks. Compatibility with C++/VERSANT links The C++/VERSANT link and link vstr classes automatically obtain locks on database objects when you first touch an object within a transaction. This means that if you use a check out. Intra-ses Intra-session -session compatibility Check out. check in. because setting a savepoint flushes objects to their databases. This may cause confusion when using optimistic locking. and versioning methods implicitly set write locks on VERSANT system objects. Once you have defined a time stamp attribute. regardless of the type of session. This will cause no problems. Query behavior If you use a query. check in. All types of sessions use a two-phase commit protocol to ensure consistency among multiple databases. Delete behavior A delete operation is sent to a database immediately rather than at commit time." Strict locking sessions use standard VERSANT locks to ensure database compatibility in a multi-user environment. schema evolution. it will be updated by commits and group writes performed in any kind of session.

you must mark the object dirty a second time to ensure that the second update is written to the database. and then update the object again. This means that if you update an object. 185 . VERSANT Database Fundamentals Manual selecting objects. perform a query.

// constructor and destructor Employee( const PString& name. const PString& job_description). o_float salary. virtual o_u4b get_number() const.h" #include "departme. public: O_TS_TIMESTAMP. virtual o_float get_salary().h> #include "person. Department* department. virtual ~Employee(). virtual void set_salary(o_float salary). o_u4b number. virtual PString get_job_description() const. 186 . // modifiers virtual void set_department(Department* department). PString job_description. o_float salary. // accessors virtual Department& get_department() const.h" class Employee : public Person { protected: // attributes Link<Department> department. o_u4b number. VDate last_raise. virtual void set_number(o_u4b number).h> #include <stream. // inherits key methods from Person }. C++/VERSANT Example The following C++/VERSANT example assumes that the Employee class has a time stamp attribute: #include <cxxcls/vdate.VERSANT Database Fundamentals Manual Examples Optimistic Locking. virtual void set_job_description( const PString& job_description).

if (argc > 1) strcpy(groupDB. ::dom = new PDOM.. // Initialize DOM Interface and connect with group database // Start an optimistic lock session so that the Versant front-end // will pass to the Versant back-end the time stamp values of the // objects being written or deleted for a time-stamp verification. if (argc > 2) strcpy(concurrentProgram.. cout << "\n\t Starting an Optimistic Lock Session .h> #include <cxxcls/try. exit(1). } main ( int argc. LinkVstrAny lBackVstr.. argv[2]). groupDB. o_dbname groupDB. LinkVstrAny lVstr. char concurrentProgram[20]. o_opts optionArray.h" void usage(char** argv) { cout << "usage is : " << argv[0] <<" <groupDB> <opt_lock[23]> " << endl.". cout << " .h> #include "employee. VERSANT Database Fundamentals Manual Following is an optimistic locking example program named opt_lock.cxx. char **argv ) { o_bool callDestructor. cout << "\n\n\t\tWelcome to the Optimistic Lock Example Program!\n" << endl. "first_session". 187 . ::dom->beginsession( 0. o_bool toPin.h> #include <libc. int i = 0. argv[1]). LinkVstrAny timestampVstr. optionArray[0] = O_OPT_LK.cxx */ #include <iostream. /* * opt_lock.h" #include "departme.done\n" << endl. optionArray ). char cmd[50]. LinkVstrAny deletedVstr.. o_bool rolledBack.

cout << "\n\t Updated an Employee instance. &deletedVstr.\n" << endl.size(). callDestructor ). Employee* james = new Persistent Employee( "James Lee". ::dom->greadobjs( staff. Employee* lisa = new Persistent Employee( "Lisa Dilon". cout << "\n\t Output from " << concurrentProgram << endl.rd. // Commit the Transaction ::dom->commit(). toPin = TRUE. try { ::dom->gdeleteobjs( lVstr."Test Pilot").rd. cout << "\n\t Locks are downgraded.select(groupDB. &timestampVstr. groupDB.\n" << endl. // // Take the first object selected. cout << "\n\t All employees objects are read.100023.PPredicate()). groupDB.00. } callDestructor = FALSE. // Find all employees in group database: LinkVstr<Employee> staff = PClassObj<Employee>. cout << "\n\t Created instances for Department and Employee classes. // Update an Employee object: worker->set_salary(50000. Employee* john = new Persistent Employee( "John Brown". // Employee* worker = staff[0]. cout << "\n\t Selected all Employees instances. Conversion from Employee_link // to Employee* happens. groupDB.rd. &lBackVstr ).00).35000. i < staff. NOLOCK. ::dom->downgradelocks( staff.45000."Engineer"). concurrentProgram. for( i = 1.\n" << endl. cout << "\n\t ********************* " << endl. "%s %s". cout << "\n\t ********************* " << endl. } catch( PError& error ) 188 .61500.VERSANT Database Fundamentals Manual // Create instances // note the placement of the constructor arguments Department* rd = new Persistent Department("RD").00. i++ ) { if (staff[i] != NULL_LINK) lVstr.TRUE. RLOCK. toPin ).00.add(staff[i]). concurrentProgram). system(cmd).\n" << endl. sprintf( cmd. \n" << endl.100024."Supervisor").100022.

" << endl. i++ ) { if (deletedVstr[i]) { cout << "\n\t\tObject " \ << ((Link<Employee>)(deletedVstr[i]))->get_number().release(). SM_E_KEY_NOT_FOUND. cout << " was updated and commited before. SM_LOCK_TIMEDOUT: ". cout << " was deleted already. break. lVstr." << endl. cout << "\n\t\tLock wait timed out. break. cout << "\n\t\tRollback this object. // for cfront only !! // Release vstr memory lBackVstr." << endl. cout << "\n\t\tRefresh this object. 189 .size()." << endl.errnum << ">" << endl.size(). switch( error. OM_TR_INVALID_TS:" << endl." << endl. i++ ) { if (timestampVstr[i]) { cout << "\n\t\tObject " \ << ((Link<Employee>)(timestampVstr[i]))->get_number(). break. VERSANT Database Fundamentals Manual { cout << "\n\t gdeleteobjs() comes across". cout << "\n\t\tSome objects have been updated in the database." << endl. OB_NO_SUCH_OBJECT. } } for( i = 0." << endl. break.release(). i < timestampVstr. break." << endl. i < deletedVstr. case SM_E_KEY_NOT_FOUND: cout << "\n\t\t<Error 1009>. } for( i = 0. } } } end_try. default: cout << "\n\t\t<Error " << error.errnum ) { case OB_NO_SUCH_OBJECT: cout << "\n\t\t<Error 5006>. case SM_LOCK_TIMEDOUT: cout << "\n\t\t<Error 2903>. case OM_TR_INVALID_TS: cout << "\n\t\t<Error 4036>.

} // Release vstr memory lBackVstr. &lBackVstr ). ::dom->xactwithvstr( (O_ROLLBACK_AND_RETAIN | O_RELEASE_VSTR). gdeleteobjs() // should succeed. else cout << " object. \n" << endl.size() > 0) { cout << "\n\t Roll back the changes on objects which have ".release().size() > 1) cout << " objects." << endl.size(). Their current salary are:\n" << endl. cout << "\n\t Refresh the objects which have already been updated. deletedVstr. cout << "\n\t Refreshed " << timestampVstr. &movedVstr ). cout << " Employee instances. cout << "O_RELEASE_VSTR options " << endl. } // Delete the Employee object again: // Since refreshobjs() sets RLOCK on the objects. &timestampVstr. // check the time stamp value try { o_opts options. ::dom->refreshobjs( timestampVstr. i++) { cout << "\n\t " << ((Link<Employee>)(timestampVstr[i]))->get_number().size(). cout << "\t" << ((Link<Employee>)(timestampVstr[i]))->get_salary()." << endl. cout << "\n\t Roll back with the O_ROLLBACK_AND_RETAIN and ". ::dom->gdeleteobjs( timestampVstr.release(). groupDB. 190 . } lBackVstr. 0." << endl. cout << "\n\t Deleted the Employee instances again.VERSANT Database Fundamentals Manual if (deletedVstr. cout << endl." << endl. if (deletedVstr. for (i = 0. &deletedVstr.size(). lVstr. &lBackVstr. RLOCK.release(). deletedVstr. if (timestampVstr.add(staff[0]). cout << "already been deleted. timestampVstr. groupDB.size() > 0) { VstrAny movedVstr. i < timestampVstr. callDestructor ). cout << "\n\t Rolled back " << deletedVstr.release().

} } } end_try. case OM_TR_INVALID_TS: cout << "\n\t\t<Error 4036>. cout << "\n\t\tRefresh this object. ::dom->checktimestamps( options. cout << "\n\t\tObject(s) has(ve) been updated in the database. case SM_LOCK_TIMEDOUT: cout << "\n\t\t<Error 2903>. switch( error. cout << "\n\t\tLock wait timed out. break. case SM_E_KEY_NOT_FOUND: cout << "\n\t\t<Error 1009>. break. break. cout << " was updated and commited before. break." << endl. // for cfront only !! 191 . cout << endl. cout << "\n\t\tRollback this object." << endl.errnum ) { case OB_NO_SUCH_OBJECT: cout << "\n\t\t<Error 5006>. OM_TR_INVALID_TS:" << endl.size(). } catch( PError& error ) { cout << "\n\t checktimestamps() comes across". SM_E_KEY_NOT_FOUND:" << endl. i < timestampVstr. } for( i = 0. i < deletedVstr. default: rethrow." << endl." << endl. OB_NO_SUCH_OBJECT:" << endl. cout << " was deleted already. lVstr. SM_LOCK_TIMEDOUT: ". &timestampVstr." << endl.size(). } } for( i = 0." << endl. i++ ) { if (timestampVstr[i]) { cout << "\n\t\tObject " \ << ((Link<Employee>)(timestampVstr[i]))->get_number(). VERSANT Database Fundamentals Manual options[0] = O_INPUT_VSTR. i++ ) { if (deletedVstr[i]) { cout << "\n\t\tObject " \ << ((Link<Employee>)(deletedVstr[i]))->get_number(). &deletedVstr ).

cout << "already been updated. cout << ((Link<Employee>)(timestampVstr[0]))->get_salary() << endl." << endl. lVstr.size() > 0) { cout << "\n\t Roll back the changes on objects which have ". then do not commit the transaction.release(). &moved ). if (deletedVstr. if (timestampVstr. // Otherwise." << endl." << endl. &timestampVstr.size(). 0. cout << "\n\t Rolled back " << deletedVstr. NULL." << endl. rolledBack = TRUE.size() > 1) cout << " objects. &lBackVstr ). timestampVstr. RLOCK. ::dom->refreshobj( timestampVstr[0].release().size() > 0) { o_bool moved. \n" << endl.release(). moved = FALSE. try { cout << "\n\t O_COMMIT_AND_RETAIN and O_INPUT_VSTR commit.\n" << endl. ::dom->xactwithvstr( (O_ROLLBACK_AND_RETAIN | O_RELEASE_VSTR). &timestampVstr. cout << "O_RELEASE_VSTR options. } 192 . cout << "\n\t Refresh the objects which have ". cout << "\n\t Updated the Employee instance again. } // Release vstr memory lBackVstr.release().00). else cout << " object." << endl. } lBackVstr. if (deletedVstr. deletedVstr. ::dom->xactwithvstr( (O_COMMIT_AND_RETAIN | O_INPUT_VSTR)." << endl. cout << "\n\t Roll back with the O_ROLLBACK_AND_RETAIN and ".VERSANT Database Fundamentals Manual rolledBack = FALSE. if (!rolledBack) { // If the above update has to be rolled back because the object // has already been deleted. deletedVstr. cout << "already been deleted. // Update the Employee object again: worker->set_salary(50000. commit the transaction. &deletedVstr ). cout << "\n\t Its current salary is ". cout << "\n\t Refreshed an Employee instance.

i < timestampVstr. } 193 ." << endl. } case OM_TR_INVALID_TS: { cout << "<Error 4036>. VERSANT Database Fundamentals Manual catch( PError& error ) { cout << "\n\t xactwithvstr() comes across ". i < deletedVstr. break. i++ ) { if (timestampVstr[i]) { cout << "\n\t\tObject " \ << ((Link<Employee>)(timestampVstr[i]))->get_number(). switch( error. cout << " was updated and commited before.\n" << endl.errnum ) { case SM_LOCK_TIMEDOUT: cout << "<Error 2903>. case OB_NO_SUCH_OBJECT: { cout << "<Error 5006>. cout << " was deleted and commited before." << endl.size(). } } } end_try. // for cfront only !! cout << "\n\t Commited the short transaction. } for( i = 0. } default: rethrow." << endl. } } for( i = 0. SM_LOCK_TIMEDOUT: ". cout << "Some objects have been updated in the database. OB_NO_SUCH_OBJECT:" << endl. break. cout << " Object is locked" << endl.size(). i++ ) { if (deletedVstr[i]) { cout << "\n\t\tObject " \ << ((Link<Employee>)(deletedVstr[i]))->get_number(). OM_TR_INVALID_TS:" << endl. break.

lVstr.release().release(). } // end main 194 . cout << "\n\t Ended the session. timestampVstr. cout << "\n\t End of the Example! \n" << endl. staff. \n" << endl. ::dom->exit(0). deletedVstr.release(). ::dom->endsession().VERSANT Database Fundamentals Manual // Release vstr memory lBackVstr.release().release().

................................................................................................................................ 207 Overview .......................................................................................................................................... VERSANT Database Fundamentals Manual Chapter 11: Memory Management This section explains VERSANT memory management in more detail than you will usually want or need................ 196 Object Cache .. 204 VERSANT Server........................................................................................................................................ 205 Network and virtual layers ........................................................................................................ The information in this chapter is provided for situations when you want to control memory usage explicitly............................ 204 VERSANT Manager ....................................................................... 209 Process Usage Notes .................... 197 Pinning objects ........................................................................................................................................................................................................................ 207 One Process Model ................................................ 199 Object cache management ............... 198 Releasing objects............... It also contains caution statements and recommendations for the case of running an application with one process..... 199 Cached object descriptor table............................................................................................ 198 Releasing the object cache.................................. 207 Two Process Model ................................................................................................................................................................................................................... 203 Software Modules............................................................................................................................................................................................................................................................. 205 Multi-Threaded Database Server ................................................................................................................................................................. 211 195 ................................................................................................................ 197 Object cache purpose ........................................................... 202 Server Page Cache ............................................. Overview .............................................................................................................................................................

including the session database. VERSANT uses three kinds of memory. Also. • See also the "Sessions" chapter for an explanation of non-memory elements of a session. and application process. • See also the "Statistics Collection" chapter for information on collecting performance information about the object cache. VERSANT automatically maintains a page cache in server shared memory. See the "Performance Tuning" chapter for information on improving memory usage. Following are explanations of each of these kinds of VERSANT memory usage. Server page cache The database memory area includes a page cache for recently accessed objects and related database cache management tables. 196 . connection databases.VERSANT Database Fundamentals Manual Overview When you start a session. For example. • See also the "Database Profiles" chapter in the VERSANT Database Administration Manual for information on parameters you can use to fine tune database and application performance. Process memory Either one or two processes (depending upon circumstances) are used to manage database and application memory. Object cache The application memory area includes an object cache for objects accessed in the current transaction and related object cache management tables. C++/VERSANT note — C++/VERSANT default memory management is suitable for most situations. page cache. VERSANT automatically caches and pins objects in application virtual memory when you dereference them. and short and long transactions.

Similarly. you should avoid using instances of VERSANT classes outside of a session." It is a hash table keyed on logical object identifiers. VERSANT Database Fundamentals Manual Object Cache To improve access to objects in a short transaction. One of these information tables is the cached object descriptor table. When an application requests an object. sometimes abbreviated as "cod table. you should avoid using in a session any objects that were created outside a session. 197 . However. Usually the object cache is in process virtual memory on the machine running the application. VERSANT creates an object cache. called a "shared session". Since VERSANT uses an object cache. Object cache purpose Object caches are for the sole use of a particular application. Exceptions are the Vstr<type> and PString classes which have an alternative storage mechanism when the object cache does not exist. since most VERSANT classes make use of the object cache. instances created outside a session are no longer valid when a session begins. you cannot use in a session any instances created outside of a session. then the server cache for the database to which the object belongs. the object cache contains objects accessed in the current transaction and is cleared whenever a transaction commits or rolls back. when you start a database session. both transient and persistent VERSANT objects and transient non-VERSANT objects created within a session are no longer valid when the session ends. connected databases. Normally. If you start a special kind of session. Also. Also created are various information tables to track your processes. the object cache will be in shared memory where it can be accessed by multiple processes in an application. and long and short transactions. and then the database itself. For this reason. VERSANT first searches the object cache. even for these exceptions.

as its location in memory is no longer guaranteed. However. and all persistent objects are dropped from object cache memory. the object cache is cleared. it will be invalid when the session begins. it is retrieved from its database.VERSANT Database Fundamentals Manual C++/VERSANT example — For example. you can perform a checkpoint commit. NULL ). When you unpin an object. // example of creating a PString before a session PString s1 = "before session". if you create an instance of PString before a session. and "pinned" in the cache. Whether or not it will actually be removed from memory and returned to its database depends upon available virtual memory and internal VERSANT logic. but the object cache table is maintained. // string s1 is now invalid PString s2 = "inside session". dom -> endsession(). all pointers to them are invalid. you can still use links and pointers to transient objects created or 198 . When the object cache is cleared. persistent objects marked as dirty are written to their database. placed in the object cache. If you create an instance during a session. Because clearing the cache removes all persistent objects from memory. Pins are held when a transaction checkpoint commits. a pointer to the object may become invalid. Unpinning an object does not abandon any changes made to the object. main() { dom = new PDOM. // string s2 is now invalid } } Pinning objects When you access a persistent object by dereferencing a pointer or using the locateobj() method. Releasing the object cache When you commit or rollback a transaction. { // example of creating a PString in a session dom -> beginsession( "mydb". Pins are released when a transaction commits or rolls back. You can explicitly unpin a persistent object with the unpinobj() method. To save changes but hold persistent objects in the object cache. and regardless of its location. it becomes available for movement back to its database. it will be invalid after the session ends. all transaction safeguards of object integrity still apply after an object has been unpinned. "Pinning" means that the object will physically remain in the cache until the pin is released. If you unpin an object. after a commit or rollback.

Releasing objects You can explicitly release an object from the object cache with the releaseobj() method. since it may or may not have been moved back to its database before being released. The term "cached object descriptor" is often abbreviated as "cod". VERSANT Database Fundamentals Manual modified in the current session. Releasing an object does not return it to its database. Cached object descriptor table Associated with object caches are tables that track their contents and information about the objects that they contain. if it is in memory. dereferencing a link uses the pointer entry in the cod. with locateobj(). The memory table associated with an object cache is called the "cached object descriptor table. and the term "logical object identifier" is often abbreviated as "loid". the changes will be saved to its database at the next commit or checkpoint commit. 199 . either in memory or on disk. even if the object was previously pinned or marked as dirty." It is a hash table keyed on logical object identifiers. Releasing an object can be useful if you have no further use for the object in the current transaction. it just releases it from the object cache. If you have previously explicitly written changes to the database with a group write. and the object's unique identifier. it is usually used only with objects accessed with a null lock. If the object is on disk. you should explicitly retrieve it from its database again." which is sometimes abbreviated to "cod table. its logical object identifier. If you need to use a released object later in a transaction. When you use a link. The cached object table contains an entry for each object accessed in the current database session. among other things. Because releasing an object can cause its state to become indeterminate. you are using an indirect reference to a persistent object through the cached object descriptor for the object. These entries are maintained regardless of the location of the object. If the object is in the object cache. its state will be indeterminate if it was previously unpinned. or by selecting and dereferencing it. contains space for a pointer to the object. and survive the ending of individual short and long transactions. The cached object table entry for an object is called the object's "cached object descriptor" and. If you have previously modified the object in the current transaction. dereferencing a link uses the logical object identifier entry in the cod.

non-null non-null Link is to an object on disk and in memory. You can override this behavior with explicit pin and unpin methods. 200 . If the object is not in the cache. VERSANT will look for the object in all connected databases. the cached object descriptor table also maintains the following information about the status of an object in the object cache: Status of lock level When you access an object. Status of pinning When you access an object in C++/VERSANT. update. is to set a read lock. you must use an object link. you must mark it as dirty so that its database will be updated at the next commit. When a process requests an object using a link.VERSANT Database Fundamentals Manual Cached Object Descriptor The pointer and loid entries in a cached object descriptor can be in one of four states: pointer loid state meaning null null Link is null. bring it into memory. it is automatically marked for creation in the default database at the next commit. you implicitly or explicitly set a null. non-null null Link is to a transient instance in memory. VERSANT first checks the cached object descriptor table to determine whether the object has been previously accessed in the session. Status of newWhen you create a new persistent object. null non-null Link is to an object on disk but not in memory. read. you implicitly pin the object in the object cache. and return a cached object descriptor for the object. it is automatically marked for deletion from its database at the next commit. besides a loid and a pointer. The C++/VERSANT default. Status of update When you change an object. Status of deleted When you delete an object. or write lock. For each object. which can be changed. To access an unpinned object. You can access objects with pointers only if they have been pinned.

Since each transaction has its own object cache. When a transaction ends with a commit or rollback. Long session The cod table maintains an entry for each object accessed in a session. Cached object descriptors and their states are transparent to an application. If you do unpin an object. you need to remember that you lose all information about the object. you need to remember that you then cannot access it with a pointer. it is possible to have duplicate copies of the same object residing in different caches of different transactions conducted by different applications. There is one cached object table for each active database session. both objects and cached object descriptors are freed. The size of the cached object table is limited only by available memory. In a continuous session over an extremely long period of time. VERSANT Database Fundamentals Manual Because of the information maintained in the cached object descriptor table. or when you perform a checkpoint commit that saves changes but maintains locks. including its update status. you might want to control pinning explicitly. when you access an object. When a database session ends. only that active transaction can access its cached object table. it is conceivable that you might run out of memory for the cod table. all relevant information about the object is immediately known to the application. The cod table is not cleared until a session ends. Exceptions to this behavior are parent transactions that inherit locks when a descendant terminates. In this case. 201 . when you access an object. If you are accessing an extremely large number of objects in a transaction. cached objects and their short locks are released. but the cached object descriptors remain in the cached object table. you might want to clear the cached object descriptor table. then it is conceivable that you might run out of virtual memory. If you do clear the cached object descriptor table. In this case. The intermediate level of indirection of cached object descriptors also allows VERSANT to manage memory as needed without affecting the application. C++/VERSANT pins it in the object cache until the transaction ends. Since a session has only one short transaction active at any time. and all short locks are released. Clearing the cached object descriptor table is not necessary until after you have accessed several million objects in a session. You do not need to be concerned with the cached object descriptor table except in the following situations: Large transaction By default.

c o_endpinregion() o_gwriteobjs() o_xact() o_xactwithvstr() c++ endpinregion() gwriteobjs() xact() xactwithvstr() 202 . you can use the following. c o_zapcods() c++ zapcods() To clear the cached object descriptor table with a "clean cods" option. you can use the following explicit routines.VERSANT Database Fundamentals Manual Object cache management To clear the cached object descriptor table.

203 . if logging is turned on. like objects in the object cache. log files automatically track all changes so that the timing of page writing does not affect database integrity. when you start a database. can have either a "dirty" or "clean" status. VERSANT Database Fundamentals Manual Server Page Cache To improve access to objects used frequently by multiple applications. Also associated with the database page cache are tables which tracks its contents. In any case. VERSANT creates a page cache for that database. Pages in the database cache. The database cache is in shared virtual memory on the machine containing the database so that server processes associated with multiple applications can access the same pages. either explicitly with the startdb utility or implicitly by requesting a database connection with connectdb() or beginsession(). You can also control whether dirty pages are immediately saved to disk when a commit or direct group write occurs by enabling the server process profile parameter commit_flush. Pages are always written to their database when a session ends or a database is stopped. The database page cache contains disk pages for objects recently requested by an application. and log file buffers. which means that a page either does or does not contain objects that have been updated. track which objects have been locked by which application.

VERSANT Database Fundamentals Manual Software Modules To understand how VERSANT uses processes. VERSANT Manager is structurally divided into two parts: one part is associated with an application and an object cache and another part is associated with a VERSANT Server and a server page cache. The structural organization. like the functional organization. • Converts objects from VERSANT database format to client machine format. long transaction. VERSANT Manager. creates and manipulates class definitions. • Manages database sessions. in turn. The VERSANT Query Processor supports queries for particular objects and iteration over classes of objects. you need to know that VERSANT is structured into several modules. • Provides long transaction support. and distributed transaction support. VERSANT Manager The portion of VERSANT that runs on the same machine as a client application is called VERSANT Manager. links. and checkins to server processes that manage databases. Other modules cache objects and provide session. Application programs communicate with VERSANT Manager through language specific interfaces. but it provides the 204 . The VERSANT Schema Manager. • Manipulates classes. • Establishes connections to databases which may be on the same machine or another machine. updates. VERSANT Manager functionally consists of several subsidiary software modules. • Provides short transaction management via a two-phase commit protocol. communicates with one or more VERSANT Server modules which manage databases. checkouts. versions. • Distributes requests for queries. • Caches objects in virtual memory. The VERSANT Manager portion of VERSANT: • Presents objects to an application. is transparent to developers and users.

it automatically runs both VERSANT Manager and VERSANT Server. VERSANT Database Fundamentals Manual internal basis for shared sessions and flexibility in system configurations. To create an application capable of accessing a VERSANT database. • Evaluates objects on disk or in the server page cache per queries sent by client applications. you link VERSANT Manager into your application. VERSANT Server is the base level of a VERSANT object database management system. • Locks objects. • Manages indexes. • Defines short transactions. Between a VERSANT Server and an operating system is a Virtual System Layer specific to the hardware 205 . Network and virtual layers To provide for heterogeneous hardware. logging. which refers to a machine running VERSANT Server software. manages storage classes. object update. indexes. VERSANT Server: • Interfaces between VERSANT Managers and operating systems. Each VERSANT Server accesses one database. VERSANT implements its client/server architecture with additional software modules called the "Virtual System Layer" and the "Network Layer". It then appears to your application that VERSANT Manager moves objects from the database into and out of your application. This happens automatically. VERSANT Server The portion of VERSANT that runs on the machine where data is stored or retrieved from is called VERSANT Server. At the VERSANT Server level an object is a simple physical data structure consisting of a fixed number of fields. When a client application begins a database session. The term "VERSANT Server" refers to a software module and should not be confused with the term "server". and locking. • Performs disk and storage management tasks such as object retrieval. It interfaces with the operating system to retrieve and store data in database volumes and communicates with VERSANT Managers. • Maintains files that provide for logging and recovery. and your application need not explicitly control object movement as objects will be supplied as your application accesses them. short transactions. page caching.

you must use VERSANT elemental and/or Class Library data types in your programs and recompile your programs as appropriate for each platform.VERSANT Database Fundamentals Manual platform. The Virtual System Layer isolates operating system code and provides portability across hardware boundaries. 206 . To allow portability. The Network Layer translates messages to the appropriate network protocol and moves objects as network packets.

Startup process When you start a database. mounts the database system volume. Cleanup process The cleanup process stays in existence as long as the database is running. When it receives a connection request. and. database connections start threads rather than processes. in general.) The maximum number of concurrent connections to a database is determined by the server process transaction parameter. The server process then stays in existence as long as the database is running. This process creates an initial block of shared memory. it starts the server process. the cleanup process will clean up the uncommitted transaction and any database resources left by the thread. such as dead threads. except those imposed by memory and system resources. The cleanup process also responds to the first request for a database connection. prepares the database for use. At regular intervals. There is no limit on the number of concurrent connections. 207 ." All of the following is invisible to an application. This situation is the "normal case. Server process When the cleanup process receives the first request for a database connection. a startup process is created. VERSANT Database Fundamentals Manual Multi-Threaded Database Server Overview Beginning with Release 5. If a dead thread is found. but the multi-threaded design saves systems resources (because a thread context is smaller than a process context) and improves performance (because thread context switching is faster than process context switching. sets up database control tables. it wakes up and removes unused system resources. either with the startdb utility or by making a connection request. performs database physical and logical recovery. This database server architecture is invisible to applications. Two Process Model When you link your application with the VERSANT two process library and/or you make a connection to a database that is not your session database or is not on your local machine. the server process creates a thread that becomes associated with the application session that requested the connection. The startup process then forks a cleanup process and then dies. the following database server configuration is used.

4. which forks the cleanup process and then terminates. even if that session itself has no application threads in it. 1. The inetd daemon starts the ss daemon associated with VERSANT in its configuration tables. 208 . separate server processes are started for applications linked with libraries previous to Release 5. the server process and cleanup process terminate. the server thread terminates. 3. The ss daemon checks to see whether the database has already been started.VERSANT Database Fundamentals Manual Server thread All database requests by a particular session are handled by the server process thread created for it. The cleanup process then starts the server process and forwards the connection request to it. the ss daemon invokes the startup process. The server thread gets its port number and gives it to the ss daemon. 6. When the database is stopped with the stopdb utility. 7. The application sends a connection request to the TCP/IP inetd daemon on the machine containing the database. When the session ends. Detailed sequence of events Following is a detailed description of what happens when an application requests a database connection. The server process creates a server thread for the connection. The server thread remains in existence as long as the session that created it remains in existence. The ss daemon then sends the port number to the application. If the database is already running. Backwards compatibility For backwards compatibility. If the database has not been started. The application process then sets up a connection between the server thread and the application. 5. the ss daemon forwards the connection request to the server process and then terminates. 2.

the connecting session will get a one process connection to that database. The following are examples of valid situations." The "one-process database" is the database associated with the first connection made by the process that satisfies rules 1-3 above. For a particular process. Any connection to any other database. The owner of the application process is the dba of the database. and a two process connection to Database A. However. The database is the "one-process database.) Each connection to a database other than the one-process database will. This remains true until all of the application's one process connections have been terminated. even if it meets the three conditions. An application and a database will run in a single process if all of the following are true: 1. start a separate server thread on the connection database. 209 . there can be only a single one process database at a time. they will all share the one-process connection associated with the session. each connected in one process mode to DatabaseA and connected in two process mode to DatabaseB. of course. The database is on the same machine as the application. will be made in two process mode. The first time a one process linked application connects to a database that satisfies the above conditions (linking + same machine + dba + single 1P database). a database can have more than one application process with a one process connection. there are no network calls. if all connections to the one-process database are dropped by the application process (in all of its sessions. The application has been linked with the VERSANT single process library. The database by definition is the "one-process database" for that application process (including all of its sessions. In other words. • Application Process 1 has a single one process connection to DatabaseA at the same time that Application Process 2 has a two process connection to DatabaseA.) then a different database can be used as a one-process database. VERSANT Database Fundamentals Manual One Process Model When an application and database are running in a single process. • Application Process 1 has five sessions. which will also get one process connections if they connect to the same database. all one-process connections must be to the same database. Per the above rules. Application Process 2 has a session connected in one process mode to Database A. The application may create more sessions. 4. Application Process 3 has a one process connection to DatabaseB. if there are multiple threads in a session. but an application can have only one one-process database. In a process. 2. 3.

the whole process dies. but it will slow linking and create a potential for database corruption. If the exception was raised because data structures in the session were corrupted. continuing to use the session is likely to result in another exception. and then connects in one process mode to DatabaseB. • Application Process 1 has a session connected in one process mode to DatabaseA and another session connected in one process mode to DatabaseB. This is an operating system issue for all databases running with a single image mode. because if you get an exception. because it violates the rule that any given application process may only have a one process connection to one database at a time. There is no automatic cleanup mechanism for threads using the one process model. The potential for database corruption exists because an abnormal application exit may (or may not) leave the database in an indeterminate state. Running with the one process model will improve performance. If you catch the exception. The following is NOT OK. An example of an abnormal exit is one caused by use of Ctrl-C. Leftover application resources will be freed if you do not catch the exception and the application process terminates. It closes that connection. 210 .VERSANT Database Fundamentals Manual • Application Process 1 has a session connected in one process mode to DatabaseA. you can either explicitly end the session in which the thread was running or you can attempt to continue to use the session. This does NOT work.

VERSANT Database Fundamentals Manual

Process Usage Notes

When you start your database session with beginsession(), if you specify a session database on a different
machine, you will run in two processes regardless of which VERSANT library you choose. Also, each
connection to a group database after the session connection will also start a process on the machine
containing the database.

If you decide to run with one process, we recommend the following.

• Enable signal blocking.

This will block signals, such as Ctrl-C, which can terminate an application abnormally.

Signal blocking is enabled by turning on the signal_block parameter in your application process profile
file. See the VERSANT Database Administration Manual for more information.

• Optionally enable commit flushing.

You may want to enable commit flushing, which will cause the database cache to be flushed to disk after
each commit. However, turning on commit flushing will negate some of the performance gain achieved
by running with one process if you are accessing the same objects in successive transactions (because
the objects will have to be retrieved from disk with each access).

Commit flushing is enabled by turning on the commit_flush parameter in your database server process
profile file. See the VERSANT Database Administration Manual for more information.

• Use only objects that you have checked out, which will enable you to recopy the original objects if your
application terminates abnormally.

If your application does terminate abnormally, we recommend the following:

• Immediately stop the session database with the stopdb utility, which will release its shared memory.

• If you have been using only checked out objects, when you next start a session using that database, roll
back your long transaction and check out needed objects again. This will restore the database to a known
state.

• If you have been using objects not checked out from another database, proceed with caution.

211

VERSANT Database Fundamentals Manual

The primary reason for the above recommendations is that the separate memory areas for application and
database caches are managed with different mechanisms.

• An application owns and controls its object cache, which is normally in process virtual memory. (The
exception is the case of a shared session.)

If any application exits abnormally, the application cache is released, and transaction mechanisms ensure
that no problems related to the object cache occur when the application restarts.

• A database owns and controls its page cache, which is always in shared virtual memory. Page caches are
for the use of any application using the database, and VERSANT swaps objects between page caches and
disks at its own discretion.

There is no way for you to control database page caches from within an application. Database shared
memory is released only when a database is explicitly stopped with the stopdb utility or when it times
out per the db_timeout parameter in the server process profile file. (For more information on stopdb
and db_timeout, see the VERSANT Database Administration Manual.)

If you run with two processes and an application exits, normally or abnormally, the database page cache
is not affected. A separate process associated with the database will remain to run cleanup after the
terminated process.

Process alternatives

Following are diagrams showing application process alternatives.

212

VERSANT Database Fundamentals Manual

One Process Detail

Two Process Detail

In this case, the application is running with two processes. The "client machine" and the "server machine"
could be the same machine with the only difference being that the connection would be internal, rather than
through a network connection.

213

VERSANT Database Fundamentals Manual

One Client Process Connected to Numerous Group Databases

Multiple Users Sharing a Group Database

Multiple users can connect to the same group database. The following example shows two applications using
the same group database as their session database.

214

VERSANT Database Fundamentals Manual

Chapter 12: Multiple Processes in a Single Session
This chapter explains how to use multiple processes in a single session.

For information about sessions in general, see the chapter "Sessions." For information about specific routines,
see your interface reference manual.

The terms "multiple process session" and "shared session" are used to refer to a session in which multiple
processes are allowed. (The term "shared session" refers to the fact that the multiple process share the object
cache, which is in shared memory.)

As this is written, C/VERSANT and C++/VERSANT support multiple process sessions. J/VERSANT Interface
(JVI) does not support multiple process sessions.

Multiple Process Session Concepts ................................................................................................ 216
Multiple Process Session Operations .............................................................................................. 217
Multiple Process Session Usage Notes ............................................................................................ 220

215

VERSANT Database Fundamentals Manual

Multiple Process Session Concepts

Multiple Process Session Overview
When you use multiple application processes in a single session, you must take care to coordinate the
processes so that they do not interfere with each other.

Short transactions in multiple process session
Each process in a multiple process session is in its own short transaction.

Any process in a transaction can end that transaction with a commit or rollback.

Only the process that began the session can end it. Before the session can end, all other processes in the
session must have ended.

If you are using nested transactions, before you can commit or rollback a particular transaction, all descendant
transactions must have terminated. If you try to end a transaction and there are child processes started in the
context of that transaction still running, you will be blocked until they end.

Short locks in multiple process session
Since each process is in its own short transaction, the processes can block each others' locks.

Object cache in multiple process session
In a multiple process session, the object cache is created in shared memory, so that objects acquired by one
process can be accessed and changed by other processes.

In a simple application, you should have each process be responsible for a mutually exclusive set of objects.
In this case, you only have to worry about the timing of your commits and rollbacks (which clear the cache).
One approach to maintaining the cache is to perform checkpoint commits when all objects are ready to be
saved and then explicitly release from the cache those objects you no longer need.

In a more complex application, multiple processes may need to read and update the same objects. Since the
processes operate in different transactions, locks will protect you.

216

VERSANT Database Fundamentals Manual

Multiple Process Session Operations

Start multiple process session
If you start a session with the "share" option, your application can start other application processes which can
then join the session.

You can optionally combine a multiple process session with other session options, such as nestable
transaction and custom locking options.

A performance option is the "single writer, multiple reader option," specified with O_MRSW_SHARE, in which no
latches are held on the object cache when a process reads or writes to a database.

To start a session in which you can use multiple processes, specify the O_SHARE or O_MRSW_SHARE option to
the following routines.
c o_beginsession()
c++ beginsession()
VSession()

End multiple process session
To end a multiple process session, use the normal "end session" routine for your interface.

As with all sessions, ending a multiple process session will commit and terminate the session root transaction;
disconnect the application process from all group databases; commit, rollback, or detach from the current
long transaction depending upon options supplied to "end session;" and end the session.

You cannot end a multiple process session until all child processes in the session have been either terminated
with an "exit" routine or detached from the session with a "detach session" routine. The detach session
mechanism is only relevant to child processes, because the preferred way to end the session root process is to
end the session. (The exit routine will also end the session root process.)

Just as in nestable transaction sessions, you cannot end a multiple process session with an end session routine
until all transactions except for the session root transaction have ended. As with nestable transaction sessions,
if the exit routine is called when the current transaction is not the session root transaction, the exit routine will
still terminate the calling process.

Ending a session also automatically closes all connections made in that session.

If you also used the nestable transaction option when you started the session, you must end the session in the
session root transaction with no child transactions.

217

VERSANT Database Fundamentals Manual

c o_endsession()
c++ endsession()
~VSession()

Exit process
In multiple process sessions, exit routines will terminate the calling process and record the normal or abnormal
ending of the process in the VERSANT session process table.

If you specify the rollback option, the exit routine rolls back the short transaction, continues the long
transaction, and ends the session before terminating the application process.

If you also used the nestable transaction option when you started the session and are in the session root
transaction, no child transactions exist, and you specify the commit option, the exit routine commits the short
transaction, continues the long transaction, and ends the session before terminating the application process.

If you also used the nestable transaction option when you started the session and are in the session root
transaction, no child transactions exist, and you specify the rollback option, the exit routine rolls back the
short transaction, continues the long transaction, and ends the session before terminating the application
process.

If you also used the nestable transaction option when you started the session, in the following cases, the exit
routine will return an error, which is ignored because an exit routine cannot return. The result of these cases is
an abnormal termination, which is similar to a system crash:
• If you are in the session root transaction and child transactions or nested processes exist.
• If you are in the root process but not in the session root transaction.
• If you are in a child process but not in the process root transaction.

If you are in a session and running with multiple processes, you can detach a child process without ending the
session, as long as the session root process remains, by using the detachsession() routine. Once the
process has been detached, you can then terminate it normally or call the joinsession() routine at a later
time.
c o_exit()
c++ exit()

218

VERSANT Database Fundamentals Manual

Start process
To start a process that will join a session, you can use either VERSANT routines or UNIX fork and exec
routines. When you start a new application process, the spawned process is called the "child process," and the
spawning process is called the "parent process."

The following routines will start a child process using VERSANT mechanisms.
c o_forkprocess()
c++ forkprocess()

Join multiple process session
You must use a VERSANT "join session" routine to add a process to a multiple process session.

When a process joins a session, its presence is recorded in a session process table.

Because the object cache in a multiple process is in shared memory, all processes access the same object
cache.

Each time a child process joins a session, a server process associated with that child process is started on all
connected databases. Similarly, once multiple processes are running in a multiple process session, each time a
database connection is made with a connect database routine, a server process on the connection database is
started for each process in the session.

The following routines will join the current process to the session of the parent process and implicitly start a
nested subtransaction under the current transaction of the parent process and make it the current transaction
within the child process.
c o_joinsession()
c++ joinsession()

Detach from multiple process session
The following routines will remove a process from a multiple process session without terminating it and record
the removal in the VERSANT session process table.

No further work involving VERSANT software or databases may be performed by the detached process
unless the join session routine is called again. You must call the detach session routine in the process root
transaction in a child process that is currently part of a session.
c o_detachsession()
c++ detachsession()

219

VERSANT Database Fundamentals Manual

Multiple Process Session Usage Notes

Pointers in multiple process sessions
Persistent objects in a shared object memory cache should not have pointers to transient objects in
non-shared memory. Since VERSANT does not create a transient object in shared memory, if you want a
persistent object to point to a transient object, you must create them in shared memory.

Multiple process session restrictions
• All applications that share the same session must be identically linked executables.
• You cannot use multiple processes in a session in which you are using multiple threads.

Multiple Process Session Examples
A typical sequence of routines

Following is an example of the appropriate sequence of calls when multiple processes are operating in a
multiple process session. The routines are shown as C/VERSANT commands.

In this example, a second process is started with VERSANT "fork process".
P1 at t1 o_beginsession(.. );
P1 at t2 o_connectdb(..);
P1 at t3 T2 = o_begintransaction(..);
P1 at t4 pid = o_forkprocess(..);
P2 at t5 o_joinsession(..);
P2 at t6 T4 = o_begintransaction(..);
P2 at t7 o_endtransaction(..);
P2 at t8 o_exit(..);
P1 at t9 o_endtransaction(..);
P1 at t10 o_endsession(..);

Process 1 at time 1: o_beginsession()

The root process, P1, calls "begin session" with the "nest" and "share" options. This allows the use of
nestable transactions and multiple processes in the session.

When the session begins, a transaction, T1, is started in P1 and becomes the current transaction.

If you have linked the application with the VERSANT two process libraries, the "begin session" call also
starts a server process, S1, on the database, DB1, being used as the session workspace. Regardless of
your choice of linked libraries, a server process is started if your session database is on another machine.

220

P2. S3 The server process for the session database DB1 that is associated with the child process. T2. Process 2 at time 6: o_begintransaction() The child process P2 calls "begin transaction". which in turn starts its own server process. The new transaction becomes the current transaction in P2. P2 The child process. S4 The server process for the first connection database DB2 that is associated with the child process. All transactions and all processes now have access to objects in two databases: the session database and the group database to which a connection was made at time t2. S2. Process 1 at time 4: o_forkprocess() The root process P1 forks a child process. VERSANT Database Fundamentals Manual Process 1 at time 2: o_connectdb() The root process P1 connects to a secondary group database. which becomes the current transaction within P1. S2 The server process for the first connection database DB2 that is associated with the session root process. T4. to handle the connection. there are now the following processes are now running: P1 The session root process. Process 2 at time 5: o_joinsession() The child process P2 calls "join session" to become part of the session and uses the session workspace. 221 . A nestable transaction T3 is implicitly started in process P2. the current transaction within the parent process P1. DB2. S1 The server process for the session database DB1 that is associated with the session root process. Process 1 at time 3: o_begintransaction() The root process P1 starts a nestable transaction. If you are running the application with the two-process model. which starts a new transaction. T3 is a direct descendant of T2.

Process 1 at time 10: o_endsession() The parent process P1 calls "end session". Process 2 at time 7: o_endtransaction() The child process P2 calls "end transaction" which terminates transaction T4 and causes child process P2 to revert to transaction T3. which closes the connections to databases DB1 and DB2. Process 1 at time 9: o_endtransaction() The parent process P1 calls "end transaction" and performs a "commit" on transaction T2. and generic names for routines are used. The following database connections have been established: P1 Connected to session database DB1. T4 The current transaction of child process P2. P2 Connected to group database DB2. T3 The process root transaction of child process P2. you must take care to match "begin session" with "end session" and "join session" with either "exit" or "detach session" in 222 . Process 2 at time 8: o_exit() The child process P2 calls "exit" which terminates the process root transaction T3. terminates transaction T1. This example shows that if you are starting from scratch. and terminates the application and manager process P1. the server processes S3 and S4 associated with P2. P1 Connected to group database DB2. T2 The current transaction of session root process P1. stops server processes S1 and S2. Process P1 is now in session root transaction T1. Example using VERSANT to fork a process In the following example correct and incorrect sequences are shown.VERSANT Database Fundamentals Manual The following transactions are now defined: T1 The session root transaction started with "begin session". Then. The commit proceeds only if child process P2 has terminated normally. and the child process P2. the preferred approach is to start a new process with the VERSANT "fork process" routine and then join it to an existing session with "join session". P2 Connected to session database DB1.

if you started a second session with a child process. then join the first session. CHILD: end session 2 Not Recommended. A session named "1" has already been started. CHILD: begin session 1 Error. and then detach or terminate in a way that got recorded in the session process table for the first session. PARENT: fork process The parent process starts a process outside the session. Using "fork process" creates an entry for the new process in the VERSANT session process table. The transaction in which "fork process" is called becomes the parent of the process root transaction for the child process. VERSANT Database Fundamentals Manual the appropriate processes: PARENT: begin session 1 The parent process starts a session named "1". You can start a new session with a forked process. CHILD: begin session 2 Not Recommended. 223 . Thus. to end the first session the child process would have to end the second session. This means that you cannot end the parent session until VERSANT knows that the child process has been terminated. CHILD: join session 1 This is the recommended procedure. but it could paralyze the parent session because "fork process" records the new process in the VERSANT session process table for the parent.

PROCESS 2: join session 1 The entry of the second process is noted in the VERSANT session process table. The child process must be in its root transaction to detach or terminate normally. call "detach session". PARENT: detach session 1 Error. This situation is similar to the previous example. PARENT: end session 1 or exit A root process can end the session and continue by using "end session" or it can end the session and terminate by using "exit". PROCESS 2: detach session 1 or exit Even though the second process was not started by VERSANT. This example again shows that you must take care to match "begin session" with "end session. PROCESS 1: begin session 1 The first process starts a session named "1". To terminate the child process. A session named "1" has already been started. you can terminate it with "exit". Example of two separate applications joining a session The following approach might be useful if you have two existing programs that you want to adapt to using VERSANT. the session cannot end until the second process ends. The first process waits until the second process terminates. To do either. A root process cannot detach from its own session. Because the second process was noted in the VERSANT process table. call "exit". PROCESS 2: begin session 1 Error. 224 .VERSANT Database Fundamentals Manual CHILD: detach session 1 or exit To detach the child process from the session. the session root process must be in its root transaction. PROCESS 1: end session 1 Blocked." and "join session" with either "exit" or "detach session" in the appropriate processes. Only the process that started a session can end it. PROCESS 2: end session 1 Error.

PROCESS 1: end session 1 or exit A root process can end a session and continue by using "end session" or it can end a session and terminate by using "exit". VERSANT Database Fundamentals Manual PROCESS 1: detach session 1 Error. PROCESS 1: begin session 1 Process 1 starts a session named "1". A root process cannot detach from its own session. 225 . PROCESS 1: UNIX fork The UNIX fork command starts Process 2 in the same program. This example shows that if you use the UNIX "fork" command. Example using UNIX "fork" You may want to use UNIX mechanisms to create additional processes and then join them to a session. the session root process must be in its root transaction. At this point. PROCESS 2: VERSANT routines Not Recommended. PROCESS 2: end session 2 Process 2 ends Session 2 but is still running. PROCESS 2: join session 1 Error. you should immediately follow it with UNIX "exec" and then "join session". PROCESS 2: begin session 2 Process 2 was never recorded in the VERSANT session process table for Session 1. However. so it can safely start its own session which is entirely independent of Session 1. and the results are unpredictable. locks do not provide concurrency control between Process 1 and Process 2. This is dangerous. Process 2 is a part of Session 1 but is not recorded in the VERSANT session process table for Session 1. Process 2 is already a part of Session 1. To do either. PROCESS 2: UNIX exec Detaches Process 2 from the session. since Process 2 has not yet been recorded in the VERSANT session process table. You could use Process 2 to execute VERSANT routines.

VERSANT Database Fundamentals Manual PROCESS 2: join session 1 Process 2 joins Session 1 and is recorded in the VERSANT session process table for Session 1. PROCESS 1: end session 1 or exit Process 1 detaches or terminates. 226 . PROCESS 2: detach session 1 or exit Process 2 detaches or terminates.

....................................................................................... 228 One or more threads in multiple sessions.......... we strongly recommend that new applications be created using VSession for thread management............................................................................................... VERSANT Database Fundamentals Manual Chapter 13: Multiple Threads This chapter explains how to use multiple threads in one or more sessions.......................................................................................... 232 Session Restrictions .................... Thread and Session Alternatives ............................... 241 Thread Safe with Exceptions Methods ........................... 232 Session Mechanisms....... 245 Multiple Threads in Single Session..................................................................................... 244 Thread Example Programs in C++ ........................................................................................................................................................ 242 Thread Safe Methods in C++/VERSANT ........................................................................................................................................ 229 Session Management ................ all of the thread management operations have been added to the VSession class. 251 Special note for C++ The VERSANT thread management strategy for the C++ interface has changed to comply with ODMG standards..... Although the VThread class and methods are still supported by VERSANT for compatibility......................................................................................... 227 ..................... See your C++/VERSANT Reference Manual for details............................................................................................................... C++ Example #1 .......... 245 Multiple Threads in Multiple Sessions... 232 Thread Management ...... 228 Multiple threads in a single session ...... 228 Thread and Session Concepts and Terms ................................................................................................................................................. Instead................................ The class previously used to manage threads (VThread) is no longer required.......................................................................... C++ Example............................................................................. 241 Thread Unsafe Methods in C++/VERSANT................................................................................................... 241 Multiple Threads................................ Single Session .. 238 Multiple Threads in the Same Session...............................................

One or more threads in multiple sessions You start multiple sessions and move threads among them at will: you can attach and detach a thread from a session as many times as you like. This can be useful when you want to create a complex application that responds to numerous events of a similar kind. and Java interfaces support of multiple threads and multiple sessions. Also. A session is a unit of work. C++. multiple reader" approach. Opening multiple sessions allows you to define multiple units of work that are distinct. this approach is useful when you want to monitor and respond to hits on switches or a web site. Accordingly. you must take care to coordinate your work so that one thread does not interfere with the work of other threads. For example. Multiple threads in a single session You can place multiple threads in a single session. you can start multiple sessions even if your operating system doesn't support multiple threads. As this is written. when using "thread unsafe" methods. all threads are in the same short transaction and share the same locks.VERSANT Database Fundamentals Manual Thread and Session Alternatives Following are your alternatives for threads and sessions. such as a commit. because all threads access the same object cache. When you use multiple threads in a single session. usually by developing a "single writer. 228 . the VERSANT C. VERSANT coordinates the work of the threads and uses locks and separate object caches to ensure that the threads do not interfere with one another. if your operating system supports multiple threads. When multiple threads access the same object cache. When you place each thread into a separate session. you must take care to coordinate the threads so that they do not interfere with one another.

When a process starts additional threads. If a process has many threads. and resources. when you start a process. When the process that created a thread ends. data structures. A session can have no or many threads in it. that thread ends also. a set of database connections. you also create a thread. and various session and cache support tables. although a thread can be in only one session at a time. each additional thread has some memory areas and data structures of its own. A thread may associate with a database session and may exit. A thread can use VERSANT routines that access and manage persistent objects and databases only when it is in a session. By definition. Threads can open and close sessions at will. A thread can open a session from within a session. A process can start additional threads with mechanisms specific to its operating system. leaving the session open for a subsequent thread. Associated with a session are an object cache. Session A session is a VERSANT unit of work. but starting an additional thread does not require as many resources as starting another process." Thread A thread is the part of a process that performs work. a set of locks. a long transaction. VERSANT Database Fundamentals Manual Thread and Session Concepts and Terms Process A process consists of memory areas. so a process always has at least one thread. any thread may start a session. 229 . A process always has at least one resource called a "thread.

then the cache is cleared. a session can contain a sequence of one or many short transactions. which means that it is possible for one thread to be reading an object while another is updating it. Long transaction A session occurs within the scope of a long transaction. Accordingly. you should have each thread be responsible for a mutually exclusive set of objects. When multiple threads access the same session. you only have to worry about the timing of your commits and rollbacks (which clear the cache). this is definitely not recommended. Object cache When you create multiple sessions. the results could be unpredictable. In a more complex application that uses multiple threads in the same session. you must avoid conflicts either by your own application programming logic or by using thread exclusion mechanisms set on 230 . they share the same locks. If you are using any of those objects in another of your sessions. In this case. all threads in the session are in the same database transaction. the object cache is accessible by all threads in that session. For example. and the transaction is ended for all threads in that transaction. More than one thread can update the same object at the same time. The purpose of a long transaction is to track objects checked out to personal database from a group database. if you end one of many sessions in the same long transaction with a long transaction commit or rollback (rather than continuing it. Each short transaction in each session maintains its own set of locks. One approach to maintaining the cache is to perform checkpoint commits when all objects are ready to be saved and then explicitly release from the cache those objects you no longer need. A long transaction can span a sequence of sessions and processes. This means that objects acquired by one thread can be accessed and changed by other threads.VERSANT Database Fundamentals Manual Short transaction As a unit of work. a commit or rollback made in a short transaction in one session has no effect on a short transaction in another session. the multiple threads may need to read and update the same objects. In a simple application that uses multiple threads in the same session. each session maintains its own object cache in application memory. because it can lead to unintended results. simultaneous sessions can exist within the same long transaction. Since locks will not protect you.) then all checked out objects associated with that long transaction will be returned to their source databases. If multiple threads are in the same session. You can start and continue multiple long transactions by giving each of them a unique name. Although multiple. within the scope of the standard VERSANT lock model. This means that if one thread commits or rolls back a transaction. Since all threads operate in the same transaction.

Short lock If you are using multiple sessions. if you are using multiple threads in a single session. However. even though the threads belong to the same process. it is as if each session were being run by a different user. you must protect the objects so that one thread changes an attribute only when all other threads are excluded. In other words. This means that an object write locked by one thread in one session cannot be accessed by another thread in another session. 231 . VERSANT Database Fundamentals Manual individual objects or groups of objects or on attributes within an object. lock requests by one thread in one session can be blocked by locks held by another thread in another session. In either case. then locks acquired by one thread are also held by other threads. which means that locked objects can be updated by any thread and are not useful for thread exclusion.

If you do not specify a unique long transaction name for each of multiple concurrent sessions. O_SHARE. • You cannot mix the use of VERSANT C and C++ thread related routines in the same session. you must specify parameters to the routine that starts the session. • Nested transactions cannot be used with the multiple threads option. we strongly recommend that you specify a unique long transaction name for each session that you start. Following is an explanation of these parameters in the context of multiple threads and/or multiple sessions. and the multiple threads option. committing or rolling back the long transaction in one session will commit or rollback the long transaction with the same name in all other sessions. O_THREAD. Session Mechanisms Start session The mechanisms for starting a session are: c o_beginsession() c++ beginsession() VSession() When you start a session. • A threaded process should not fork. • In this release. • A thread can be in only one session at a time. O_THREAD. If long transactions in multiple sessions have the same name. the name of the long transaction that you will start or join is your username.VERSANT Database Fundamentals Manual Session Management Session Restrictions • You cannot start a session with both the shared session option. This will lead to unpredictable results and must be avoided. Long transaction name By default. • Custom locking cannot be used with the multiple threads option. Forking a threaded process will duplicate all threads in the process. O_THREAD. However. which could lead to unpredictable results unless you 232 . problems will arise if you check out or check in objects. you cannot collect statistics on a per thread basis.

Session options Sessions also allow you to specify the kind of session that you want in one or more session options. you must be a registered user of a database in order to use a database as a session database.) However.) High performance share option 233 . In any case. or use a different session database for each session. but you will probably want to supply a session name that will enable you to distinguish among sessions created later. if you start a standard session. the session names must be unique within the scope of a particular application process. you will start a "shared session" in which you can place multiple processes (rather than threads. the name of your first session will be your username. When you specify multiple options.) If you use O_SHARE. VERSANT Database Fundamentals Manual carefully coordinate the work of all sessions. As with all database connections. you will not be able to start additional sessions or place additional threads in the session (only processes. you will be able to start additional sessions (indeed. Following is an explanation of session options in the context of multiple threads and/or multiple sessions. Share option If you specify O_SHARE. you will start a "standard session" using standard VERSANT short transactions and locks. you will not be able to place multiple threads or processes in the session. use the | symbol to concatenate them. Session database name Each session requires a database to be used as a persistent workspace. Option declarations last for the duration of the session. Session name By default. If you start a standard session. You can use the same database as a session database for each of many sessions. the NULL option is the usual case for multiple sessions. when you start additional sessions. Null option If you specify NULL.

If you want to start a session but not join it. you will need to coordinate the work of the threads (see the following section "Multiple Thread Method Safety in C++/VERSANT" for details. you will start a "multiple threads" session that allows use of one or many threads in the same session. every function will be protected by a latch in a multiple threads session. but you will not be able to use the O_SHARE option in order to place multiple processes in the session (you can use only multiple threads) Multi-session Multi-session option By default. For information on shared sessions. you will be able to start additional sessions. In C/VERSANT. You cannot use the nestable transaction option with the multiple thread (O_THREAD) or multiple process option (O_SHARE. For information on optimistic locking. O_MULTI_SESSION." Multiple threads option If you specify O_THREAD. see the chapter "Optimistic Locking." Optimistic lock option If you specify O_OPT_LK. no latches are held on the object cache when a process reads from a database. prevents automatic lock upgrades.VERSANT Database Fundamentals Manual If you specify O_MRSW_SHARE|O_SHARE. 234 . shared session. see the chapter "Nestable Transaction Session. In C++/VERSANT. and provides automatic collision notification.) For information on nested transactions. a thread will join the session it starts. specify the "do not attach" option.) If you use the O_THREAD option. you will start a "nestable transaction session" that allows nesting of transactions. see the chapter "Multiple Processes in a Single Session." Nested transaction option If you specify O_NEST. You can use the optimistic locking option with any other session option. This is also called the "single writer / multiple reader" option. In a high performance. you will start a "high performance shared session" in which you can place multiple processes. you will start an "optimistic locking session" that suppresses object swapping.

It is compatible with all other session options. The O_MULTI_SESSION option cannot be used with the O_SHARE option. Because the case of a single process in a single session is a subset of the general case of multiple threads / multiple sessions. and your thread can leave the session only by ending the session. you can use VSession() to start a single session that will have a single thread (the primary thread associated with the application process. which starts a session and places the starting thread into the session. you will be able to edit data. This access mode is not currently supported. you will be able to start only a single session. Read access option If you specify O_READ_ACCESS. continues to be available for backwards compatibility with previous VERSANT releases.) The beginsession() method. At present. you will be able to view but not change data. Write access option If you specify O_WRITE_ACCESS. if you use beginsession(). C++ Notes If you want to use more than one thread or if you want to start more than one session. This access mode is the default and does not have to be explicitly specified. you will be able to view and edit data. However. you must start your sessions by creating transient instances of class VSession with VSession(). but may be supported in future releases. The write access option can be used with all other session options. VERSANT Database Fundamentals Manual You must specify the O_MULTI_SESSION option if you want to use the same thread to start multiple sessions that will be available for immediate use at a later time. A thread can use VERSANT routines that access and manage persistent objects and databases only when it is in a session. this mode is the same as O_READ_ACCESS|O_WRITE_ACCESS. we recommend that you invoke VERSANT 235 . It is an error to start more than one session in a particular thread without specifying this option. Read and write access option If you specify O_READ_ACCESS|O_WRITE_ACCESS. The read access option can be used with all other session options. If you create a session with VSession().

if you want. End session The mechanisms for ending a multiple session are: c o_endsession() c++ endsession() ~VSession() A thread does not have to be in a session to end it. the dom variable will automatically associate thread15. options[0] = O_THREAD. which called commit(). If you use the dom variable. thread15 in session4 to perform a commit. After the session has started. you can send PDOM methods to the dom global variable. you can continue to use the global variable ::dom of type PDOM* and invoke database methods on the ::dom instance. o_opt options. C++/VERSANT example The following starts a session by creating a transient instance of the VSession class. it will delegate the method to the correct VSession object for you. as VERSANT is able to associate a thread with its current session. as usual. for backwards compatibility. even if you start a session with VSession(). For example.VERSANT Database Fundamentals Manual methods on your session instance. options). but it can be. Although we recommend that you send database methods to an instance of VSession. In this case. VSession* session1 = new VSession( "longtrans1" "db1". say. with session4 and cause a commit only on the current short transaction in session4. you can send PDOM methods to an instance of VSession. For example: session1 ->commit(). an error will be raised. 236 . If one thread tries to end a session while another thread is still in that session. For example: ::dom->commit(). the thread sends the message with normal syntax: ::dom->commit(). "session1". However.

rollback. VERSANT Database Fundamentals Manual As with all sessions. and commit. you must close it with ~VSession(). or continue the current long transaction. C++/VERSANT — If you created the session with VSession(). ending a multiple session or a session with multiple processes or threads will commit and terminate the current short transaction. close all database connections made in that session. Get session parameters Default database Get the default database for a session: c++ get_default_db() User data Get user data for a session: c o_sedataget() c++ get_user_data() Number of threads Get the number of threads currently attached to a session: c++ get_thread_count() Set session parameters Default database Set the default database for a session: c++ set_default_db() Long transaction options Set long transaction options for when a session ends: c++ set_endsession_opts() User data Set user data for a session: c o_sedataset() c++ set_user_data() 237 .

0. 0. Instead. all of the thread management operations have been added to the VSession class. NULL. The class previously used to manage threads (VThread) is no longer required. use a "set session" routine with a NULL session name. &thr1). Attach thread to a session To attach a thread to a session. Start operating system thread To start an operating system thread. c o_setsession() c++ VSession::setsession() 238 . See your C++/VERSANT Reference Manual for details. use normal interface and operating system mechanisms. Although the VThread class and methods are still supported by VERSANT for compatibility. Restriction In a multi-threaded application. in a thread other than main thread of execution user cannot create PError objects before calling a method of VSession or PDOM. we strongly recommend that new applications be created using VSession for thread management. t1_start.VERSANT Database Fundamentals Manual Thread Management Special note for C++ The VERSANT thread management strategy for the C++ interface has changed to comply with ODMG standards. For example: thr_create(NULL. supply a session name to the following methods: c o_setsession() c++ VSession::setsession() Detach thread from a session To detach a thread from a session without having it join a new session.

VERSANT Database Fundamentals Manual Get thread parameters Default lock To get the default lock for a thread: c++ VSession::get_default_lock() Session pointer To get a pointer to the current session object for a thread: c++ VSession::current() Session name To get the name of the current session for a thread: c++ VSession::get_session_name() User data To get user data for a thread: c o_thdataget() c++ VSession::get_thread_user_data() Set thread parameters Default lock To set the default lock for a thread: c++ VSession::set_default_lock() User data To set user data for a thread: c o_thdataset() c++ VSession::set_thread_user_data(const *) 239 .

VERSANT Database Fundamentals Manual Redefine thread exception handling in C++ Error handling The following methods will replace the default error handling methods in C++/VERSANT. c++ vpp_thread_terminate() c++ vpp_thread_unexpected() 240 .

because a commit performed by one thread will clear the object cache even if other threads are currently accessing objects in the cache. C++/VERSANT The C++/VERSANT interface is built on top of the C/VERSANT library. all entry functions into the C/VERSANT kernel library are protected by a mutex latch. Most C++/VERSANT methods call the corresponding C library routine to perform database operations. Following are usage notes related to the use of multiple threads in the same session. the work of each thread will be protected by the session boundaries. Attach a thread to the current session by using VSession::set_session(). a database commit method is thread unsafe. however. This means that one thread cannot update an object while any other C/VERSANT library function is reading or updating it. Your synchronization mechanism must ensure that only one thread (the thread executing the thread-unsafe method) is accessing objects in the cache at the time the unsafe method is invoked. Behavior varies depending upon the interface you are using. a preferred synchronization mechanism is the conditional variable. Typically a mutex and a thread counter is used to synchronize the threads. Thread Unsafe Methods in C++/VERSANT Some C++/VERSANT methods affect the cache globally and therefore require that no other threads be accessing any objects in the cache at the same time. This will initialize the thread local variables used by C++/VERSANT. VERSANT Database Fundamentals Manual Multiple Threads in the Same Session Multiple Threads. you will need to coordinate their activities. However some of the operations. An example is provided at the end of this note. you must coordinate the threads with the thread synchronization mechanism provided by your operating system thread package. If you use a thread-unsafe method. For example. 241 . may not call C/VERSANT if the object is already in cache. If you place multiple threads in the same session. These methods are called "thread unsafe". like dereferencing a link. For operating systems that support conditional variables. Single Session If you use a single thread per session. C/VERSANT For the C/VERSANT interface.

the delete method is considered "safe with exceptions" rather than "unsafe. In a MR/SW mechanism. threads that will execute only thread-safe methods enter the critical region as readers and the thread that will execute the thread-safe-with-exceptions methods will enter the region as a writer. if you delete an object using one thread. the writer can execute thread-restricted methods only when no reader is in the critical 242 . but they still have an impact on other threads that happen to be using the objects in question. when the action option is not O_CHECKPOINT_COMMIT zapcods() Thread unsafe PClass method select()." If you use a "thread safe with exceptions" method. These methods are called "thread safe with exceptions. then that object will no longer be available even if another thread is currently accessing the object. Based on this scheme. you must protect the objects affected by the method by using a "one writer / multiple readers" exclusion mechanism (MR/SW) for each object or groups of objects. when the action option is not O_CHECKPOINT_COMMIT xactwithvstr().VERSANT Database Fundamentals Manual The following C++/VERSANT methods are thread unsafe." For example. when the option O_FLUSH_NONE is not used Thread Safe with Exceptions Methods Some C++/VERSANT methods affect only individual objects or group of objects. Thread unsafe PDOM methods abort() beginsession() begintransaction() commit() connectdb() detachsession() disconnectdb() endpinregion() endsession() endtransaction() exit() forkprocess() joinsession() joinsession() replenishcache() resetoct() rollback() savepoint() set_default_db() set_default_lock() undosavepoint() xact(). Because the delete changes only a single object rather than all objects.

Similar exclusion mechanisms can be implemented on individual attributes of objects. and collection classes change the object and hence are thread-restricted. For example. VERSANT Database Fundamentals Manual region. An iterator over a link vstr would enter as a reader. link vstr. a method that adds to or removes an element from the link vstr would enter as a writer. a vstr or link vstr used as an attribute of an object could be protected rather than the entire enclosing object to increase the concurrency. Thread-safe-with-exceptions global operator operator delete Thread-safe-with-exceptions PDOM methods checkloid() freebeprofile() freefeprofile() gdeleteobjs() gwriteobjs() refreshobj() refreshobjs() releaseobjs() xactwithvstr(). The following C++/VERSANT routines are "safe with exceptions. commit and rollback options Thread-safe-with-exceptions PClass methods dropclass() dropinsts() Thread-safe-with-exceptions PObject methods deleteobj() deletevsn() releaseobj() unpinobj() Thread-safe-with-exceptions Link<type> and LinkAny methods deleteobj() deletevsn() releaseobj() Thread-safe-with-exceptions Vstr<type> and VstrAny methods add() append() remove() unordered_remove() 243 ." The following list is not complete since all modifier methods on vstr.

. These methods are called "thread-safe. If two threads try to dereference the same link at the same time.. For example. if you perform a checkpoint commit with one thread. Thread safe global macro O_NEW_PERSISTENT(." For example.. but they are well behaved in terms of the impact on other threads. the end-impact on the cache is the same regardless of the order of execution. the following methods are thread safe. All methods not noted above as thread-unsafe or thread-restricted are thread-safe.VERSANT Database Fundamentals Manual Thread-safe-with-exceptions LinkVstr<type> and LinkVstrAny methods add() append() remove() unordered_remove() Thread Safe Methods in C++/VERSANT Some methods affect objects.) Thread safe PDOM methods downgradelock() downgradelocks() xact(). if the action option is O_CHECKPOINT_COMMIT Thread safe PObject method dirty() Thread safe Link<type> and LinkAny methods dirty() locateobj() operator->() Thread safe PClass method select(). objects will still be available in cache to other threads and all threads will see the same object states. if the option O_FLUSH_NONE is used 244 . if the action option is O_CHECKPOINT_COMMIT xactwithvstr().

testthrd. }. #include <iostream.cxx The following implements the class TestThread. testthrd. o_4b myid.h" TestThread::TestThread(o_4b _myid) : myid(_myid) { thread_id = thr_self(). #include <cxxcls/pobject. VERSANT Database Fundamentals Manual Thread Example Programs in C++ Multiple Threads in Multiple Sessions. } 245 . public: TestThread( o_4b _myid ).h> #include "testthrd.h> class TestThread : public PObject { o_u4b thread_id. o_u4b session_id. C++ Example The following is an example of using multiple threads in multiple sessions. void print(). void set_myid( o_4b ).h> #include <cxxcls/vsession. session_id = VSession::current() ->get_session()->get_session_index(). dirty().h The following declares the class TestThread which will be used in the example program. } void TestThread::set_myid(o_4b id) { myid = id.

typedef void* (*THREAD_FUNC)(void *). "Session2". int main(int argc. VSession* s1 = new VSession("long1". main. int t2_start(char*). } schema. pdb. exit(1). "Session1". options[0] = O_MULTI_SESSION | O_THREAD. #include <stdlib.h> #include "testthrd. options).VERSANT Database Fundamentals Manual void TestThread::print() { cout << "thread_id = " << thread_id << "\t" << "session_id = " << session_id << "\t" << "myid = " << myid << endl.cxx The following program uses multiple threads in multiple sessions. 246 . #include <cxxcls/pobject. pdb. // create 3 sessions which don't have any thread attached o_opts options.h" O_CAPTURE_SCHEMA(TestThread). VSession* s2 = new VSession("long2".h> #include <cxxcls/pobject.h" int t1_start(). char** argv) { if(argc != 3) { cerr << "Usage: " << argv[0] << " pdb gdb" << endl.h> #include <unistd. char* gdb = argv[2].h> #include <iostream.h> #include "testthrd. options).imp The schema implementation file. } char* pdb = argv[1].

} // end session by delete the VSession object delete s1. delete s3. return 0.. (void*)gdb. cout << "tid " << thr_id << ": join Session1. delete s2. gdb. t2. VSession::set_session("Session1"). 0. i<10. (THREAD_FUNC)t2_start. i++) O_NEW_PERSISTENT(TestThread)(i). NULL. 0. // wait until all threads return int status. for(int i=0. // create 2 threads thread_t t1. thr_create(NULL. a commit 247 . // A commit freshs the object cache // The following commit is safe." << endl. &t2). 0. If there were other threads in Session1. "Session3".. while( thr_join(0. options). they will be in database pdb cout << "tid " << thr_id << ": create 10 TestThread instances" << endl. thr_create(NULL. &t1). because only one thread is // in Session1. // this thread joins to Session1 //VThread mythrd("Session1"). // create some persistent objects // those objects should have a session_id=0 and // thread_id=thr_id.(void**)&status)==0 ) { cout << "thread " << departed << " returned with return value " << status << endl. thread_t departed. (THREAD_FUNC)t1_start. VERSANT Database Fundamentals Manual VSession* s3 = new VSession("long3". } int t1_start() { int thr_id = thr_self(). 0.&departed.

they will be in database gdb cout << "tid " << thr_id << ": create another 10 TestThread instances" << endl. ::dom->commit(). i++) O_NEW_PERSISTENT(TestThread)(i).. ::dom->commit()." << endl. i<size. //mythrd.. VSession::set_session("Session1"). //mythrd. // switch back to Session1 cout << "tid " << thr_id << ": switch back to Session1.release(). // create some persistent objects // those objects should have a session_id=2 and // thread_id=thr_id. l. for(i=0." << endl.size().select( NULL." << endl. // now detach from Session1 and join to Session3 cout << "tid " << thr_id << ": detach from Session1 and join to Session3..set_session("Session1").. // this commit is safe because only one thread attached to // Session3 cout << "tid " << thr_id << ": doing commit. // find some objects // select() flushs object from the cache to the backend // you need to coordinate between the threads.." << endl. for(i=0. 248 .. i++) l[i]->print(). i<10. int size = l.. 0.. It is safe // here because only one thread in the Session1 LinkVstr<TestThread> l = PClassObject<TestThread>::Object(). NULL_PREDICATE).set_session("Session3"). cout << "tid " << thr_id << ": selected " << size << " objects back" << endl. VSession::set_session("Session3").VERSANT Database Fundamentals Manual // might disrupt their work unless you took care to coodinate // threads cout << "tid " << thr_id << ": doing commit.

} int t2_start(char* dbname) { int thr_id = thr_self(). i<10. NULL_PREDICATE). int size = l. 0." << endl. // get session handle //VSession* h_sess = mythrd. return 0. VERSANT Database Fundamentals Manual ::dom->commit(). they will be in database pdb cout << "tid " << thr_id << ": create 10 instances" << endl.set_session("Session2"). //mythrd. // this thread joins Session2 //VThread mythrd.. cout << "******** thread " << thr_id << " done ********" << endl. // this commit is safe because only one thread in Session2 cout << "tid " << thr_id << ": doing commit. i++) O_NEW_PERSISTENT(TestThread)(i). i++) l[i]->print(). VSession::set_session("Session2"). 249 . ::dom->commit().. VSession* h_sess = VSession::current(). // connect Session2 to gdb // alternative. // create some persistent objects // those objects should have session_id=1 and // thread_id=thr_id." << endl..select(NULL. for(i=0. // find some objects LinkVstr<TestThread> l = PClassObject<TestThread>::Object(). cout << "tid " << thr_id << ": selected " << size << " objects back" << endl.get_session(). cout << "tid " << thr_id << ": join Session2.size(). you could say ::dom->connectdb(dbname) cout << "tid " << thr_id << ": connect to " << dbname << endl.. i<size. for(int i=0.

. cout << "tid " << thr_id << ": disconnect from gdb. ::dom->commit(). // create 10 objects in the gdb. i<10. cout << "tid " << thr_id << ": selected " << size << " objects back" << endl. // call cleanup before you call thr_exit() // mythrd. for(i=0.cxx 250 . include .exe all: $(EXEC) a. they will be in database gdb for(i=0.size(). class) // those objects should have session_id=1 and // thread_id=thr_id.o testthrd. Note the use of new macro // O_NEW_PERSISTENT1(db.VERSANT Database Fundamentals Manual h_sess->connectdb(dbname)." << endl. cout << "******** thread " << thr_id << " done ********" << endl. size = l.select(dbname. h_sess->disconnectdb(dbname)." << endl. // to make the compiler happy } makefile Following is a sample makefile. 0. thr_exit(0). return 0..cleanup()..release()..com EXTRA_FLAGS=-mt OBJS= main. cout << "tid " << thr_id << ": doing commit.h schema. i++) l[i]->print(). // find some objects in gdb l = PClassObject<TestThread>::Object()../makecxx. NULL_PREDICATE).o: schema.o schema. i<size.o EXEC= a. l.TestThread)(i).exe: $(OBJS) $(CXXLINK) $(OBJS) $(CXX_LIBRARY) $(OBJS): testthrd. i++) O_NEW_PERSISTENT1(dbname.

C++ Example #1 Following is a simple thread application.exe $(PDB1) $(GDB1) Multiple Threads in Single Session.cxx $(EXEC) $(CXX_TO_NULL) -rm -rf Templates.cxx: schema. A better approach using conditional variable could be used on platforms where it is supported. load them into databases. the main thread starts a number of threads which perform some database operations.sch a. In this application. The application does the following: begins a session on a database spawns a number of threads to create new persistent instances waits for all threads to finish performs a commit ends the session begins a session on a database spawns a number of threads to dereference all instances.sch -stopdb -f $(GDB1) -removedb $(GDB1) -createdb $(GDB1) sch2db -y -D $(GDB1) schema. The main thread performs the thread unsafe methods commit() and exit() only when all the other threads are terminated. VERSANT Database Fundamentals Manual schema. The thread synchronization is achieved by using a mutex and an integer counter.DB run_demo: all -stopdb -f $(PDB1) -removedb $(PDB1) -createdb $(PDB1) sch2db -y -D $(PDB1) schema. and call a virtual function on them waits for all threads to finish performs a commit ends the session begins a session on a database spawns a number of threads to dereference random instances based on a query using random numbers and call a virtual function on them 251 .imp clean: -rm $(TEMP_FILES) $(INSTANCE_FILE) schema.

h> class Test : public PObject { o_4b value.h #ifndef __CLASS_H #define __CLASS_H #ifdef __SVR4 #include <thread.. If an exception thrown. public: static o_4b callCount.h> #define vpp_procSleep(x) sleep(x) #endif #if defined(WIN32) #include <windows. This program is available in the VERSANT directory . 252 .h> #define vpp_procSleep(x) Sleep(1000 * x) #define vpp_mutexInit(x) InitializeCriticalSection(x) #define vpp_mutexLock(x) EnterCriticalSection(x) #define vpp_mutexUnlock(x) LeaveCriticalSection(x) #define vpp_thrExit(x) ExitThread(x) #define vpp_getTid() GetCurrentThreadId() typedef CRITICAL_SECTION vpp_mut. Test(o_4b a = 0) :value(a) {} virtual void foo(). Some of the threads will cause exceptions. the thread is terminated. }..VERSANT Database Fundamentals Manual waits for all threads to finish performs a commit ends the session begins a session on a database spawns a number of threads to load objects into memory. waits for all threads to finish performs a commit ends the session Following is a listing of the sample program. #endif /* WIN32 */ #include <cxxcls/pobject. class. typedef DWORD vpp_thr.demo/cxx/threads or .demo\cxx\threads.

value2(2*a) {} void foo().h> 253 . vpp_mutexUnlock(&foo_mutex). #endif class. #define vpp_thrYield()thr_yield() #endif #if defined(_WIN32) #include <windows.h> typedef thread_tvpp_tid. public: TestTest(o_4b a = 0) : Test(a). VERSANT Database Fundamentals Manual class TestTest : public virtual Test { o_4b value2. }. vpp_mutexUnlock(&foo_mutex).h> #endif /* _WIN32 */ #include "class.h" #ifdef __SVR4 #include <thread.h" vpp_mut foo_mutex.cxx #include "class. Test::callCount++. } void TestTest::foo() { vpp_mutexLock(&foo_mutex). o_4b Test::callCount = 0. void Test::foo() { vpp_mutexLock(&foo_mutex).h> typedef DWORDvpp_tid. } main1.cxx #include <stdlib.h> #if !defined(_WIN32) #include <unistd. Test::callCount++. #define vpp_thrYield()Sleep(0) #endif /* _WIN32 */ #include <cxxcls/vsession.

vpp_mutexUnlock(&sync_mutex). // database name void *(*f)(char *).// To keep track of completed threads for // synchronization char *gdbname. int number_of_threads. count++. } void my_unexpected() { // increate the counter so that the main thread knows this thread is // finished vpp_mutexLock(&count_mutex). void my_terminate() { // increate the counter so that the main thread knows this thread is // finished vpp_mutexLock(&count_mutex). // create a barrier so that all child threads //start together vpp_mut count_mutex. vpp_mutexUnlock(&count_mutex). int count = 0. vpp_mutexUnlock(&count_mutex).// function to be called in the session void session(o_u1b operation). set_terminate(my_terminate). VSession::set_session("session"). set_unexpected(my_unexpected). vpp_mutexLock(&sync_mutex). count++. ::vpp_thread_terminate(). extern vpp_mut foo_mutex.VERSANT Database Fundamentals Manual vpp_mut sync_mutex. ::vpp_thread_unexpected(). 254 . } void *database_create(char *arg) { // this thread creates some objects in the database //VThread mythread("session"). const int objects_per_thread = 50.

VERSANT Database Fundamentals Manual int me = atoi(arg). return 0. i++) 255 . int objval. VSession::set_session("session").size(). // make the compiler happy } void *database_deref(char *arg) { // this thread derefrences all the Test instances in the // database // VThread mythread("session"). O_NEW_PERSISTENT(Test)(objval). //mythread. j < objects_per_thread. vpp_mutexUnlock(&sync_mutex). } vpp_mutexLock(&count_mutex). // select is OK because we have no dirty objects in the cache // and flushing the cache has no impact on all threads // or we could specify the O_FLUSH_NONE option LinkVstr<Test> lv = PClassObject<Test>::Object(). for (int i = 0. "Thread %d: Select got %d objects \n". j++) { objval = me * objects_per_thread + j. vpp_mutexUnlock(&count_mutex). } for (j = 0. fprintf(stderr. for (int j = 0. count++. set_terminate(my_terminate). j < objects_per_thread. j++) { objval = me * objects_per_thread + j. size). set_unexpected(my_unexpected).cleanup(). i < size. int size = lv. vpp_thrExit(0). vpp_getTid(). vpp_mutexLock(&sync_mutex). O_NEW_PERSISTENT(TestTest)(objval). // Yes.select( gdbname. we want sub class instances NULL_PREDICATE). 1.

i < size. 1. vpp_mutexUnlock(&sync_mutex). // Yes. we want sub class instances pred). //mythread. // make the compiler happy } void *database_deref_random(char *arg) { // this thread tests the derefrence of instances based on the // query with random numbers VSession::set_session("session"). vpp_mutexLock(&sync_mutex). return 0. int k = rand(). set_terminate(my_terminate). lv.cleanup(). vpp_mutexLock(&sync_mutex).cleanup(). set_unexpected(my_unexpected). vpp_thrExit(0). LinkVstr<Test> lv = PClassObject<Test>::Object(). vpp_mutexLock(&count_mutex). return 0. for (int i = 0. PPredicate pred = PAttribute("Test::value") == (o_4b) k. i++) lv[i]->foo(). set_unexpected(my_unexpected). vpp_mutexUnlock(&count_mutex). count++.select( gdbname.release(). //mythread. lv.release(). 256 . vpp_thrExit(0). set_terminate(my_terminate). count++.VERSANT Database Fundamentals Manual lv[i]->foo(). int size = lv.size(). vpp_mutexLock(&count_mutex). vpp_mutexUnlock(&count_mutex). // make the compiler happy } void *database_error(char *arg) { // this thread tests the exception handling mechanism VSession::set_session("session").

VERSANT Database Fundamentals Manual vpp_mutexUnlock(&sync_mutex). LinkVstr<Test> lv. try { lv = PClassObject<Test>::Object(). // this will throw an exception else if ((vpp_getTid() % 3) == 2) lv[size]->foo(). } gdbname = dbname. if (!dbname) { fprintf(stderr.size(). } lv. vpp_mutexUnlock(&count_mutex). vpp_mutexLock(&count_mutex). if ((vpp_getTid() % 3) == 0) lv[0]->foo(). //mythread. return 0. int size = lv.release(). else if ((vpp_getTid() % 3) == 1) lv[-1]->foo(). // this throws an exception too } catch (PError e) { e. count++. 257 .cleanup()."You should specify the database name with PDB1\n"). vpp_thrExit(0). } char *dbname = getenv("PDB1").char **argv) { if (argc != 2) { fprintf(stderr. number_of_threads = atoi(argv[1]). // make the compiler happy } main(int argc."Usage: main1 <number-of-threads>\n"). exit(-1).print().select( gdbname. we want sub class instances NULL_PREDICATE). exit(-1). 1. // Yes.

break. break. should be %d\n"..// test error case } // main void session(o_u1b operation) { vpp_tid tid.// create objects session('d'). "Dereferenced %d objects\n". for (register int i = 0. case 'd': f = database_deref. o_opts option.. fprintf(stderr. session('c'). Test::callCount). Test::callCount = 0. "Dereferenced %d objects. break. default: fprintf(stderr. break. gdbname. i++) 258 . switch (operation) { case 'c': f = database_create. case 'r': f = database_deref_random. exit(-1). "Now testing exception handling in threads.\n").// dereference randomly fprintf(stderr. vpp_mutexInit(&foo_mutex). i < number_of_threads.// dereference all objects fprintf(stderr. case 'e': f = database_error. option ). session('r').(number_of_threads * number_of_threads * objects_per_thread * 2)). Test::callCount. option[0] = O_THREAD ."usage error\n"). session('e'). } vpp_mutexLock(&sync_mutex). "session".VERSANT Database Fundamentals Manual vpp_mutexInit(&sync_mutex). VSession *session = new VSession( "longtrans". vpp_mutexInit(&count_mutex).

if (status != 0) { fprintf(stderr. #if defined(__SVR4) && defined(VPP_CXXSUN40) o_u4b status. default */ (LPTHREAD_START_ROUTINE)f.// stack base. } #endif /* defined(__SVR4) && defined(VPP_CXXSUN40) */ #if defined(VPP_MSVC20) HANDLEtHandle. GetLastError()). i)."started a thread with id %d\n".// creation flag. VERSANT Database Fundamentals Manual { char *which = new char[8]. } #endif fprintf(stderr. which. default */ &tid/* thread id returned */ ). tHandle = CreateThread( NULL. status = thr_create( NULL.// arguments 0. 259 ./* creation flags./* arguments */ 0.errno).tid). "%d"./* security attributes */ 0. exit(-1)./* stack size. typedef void* (*THREAD_FUNC)(void *). default &tid// thread id returned )."thr_create() fails with error %d\n". default (THREAD_FUNC)f. if (tHandle == NULL) { printf("CreateThread fails with error %d\n". sprintf(which. exit(-1).// stack size. default 0. which.

o schema. } else { vpp_mutexUnlock(&count_mutex). // wait for all other threads to finish int prevCount = 0. O_CAPTURE_SCHEMA(TestTest)."In main thread.\n".o schema. delete session. count). number_of_threads).out : class. makefile.VERSANT Database Fundamentals Manual } vpp_mutexUnlock(&sync_mutex).. mainThread->set_session(0)..imp #include "class.) { vpp_mutexLock(&count_mutex). if (count != prevCount) { fprintf(stderr.0 -L`oscp -p`/lib -lcxxcls -loscfe -lsocket -lnsl a.4. prevCount = count. count = 0."In main thread. break.o CC $(CCFLAGS) class. } } // now all threads have finished when we come out of // the for loop session->commit(). vpp_thrYield()..h" O_CAPTURE_SCHEMA(Test). for (. waiting for %d child threads.sol CCFLAGS= -mt -I`oscp -p`/h -g LIBS= -L`oscp -p`/lib/sun. continue.\n".o main1.o main1.o $(LIBS) 260 . } schema. fprintf(stderr. } if (count < number_of_threads) { vpp_mutexUnlock(&count_mutex). %d child thread(s) completed.

imp schema.cxx CC $(CCFLAGS) -c main1.cxx clean: rm -rf a.o : schema.cxx schema.cxx : class.imp schcomp -I`oscp -p`/h schema.i0 *.h class.i1 *. VERSANT Database Fundamentals Manual class.sch *.o: class.i2 261 .cxx CC $(CCFLAGS) -c class.o Templates.out *.cxx main1.o: class.DB schema.cxx CC $(CCFLAGS) -c schema.h main1.h schema.cxx schema.

........... 270 Disk Management....................................................................................................................................................................................................................................................... 277 Cluster Objects on a Page................................................................................................................................ 279 Configure Log Volumes...................VERSANT Database Fundamentals Manual Chapter 14: Performance Tuning This chapter suggests some ways to improve application performance................................................................................................................... 269 Memory caches ...................................................... the usual order is C and C++.............................. 266 Memory Management ........... However................ this chapter cannot be viewed as definitive.............................................................................................. 269 Memory management strategies ........................................................... Where functions or methods are listed........................................................... 270 Pinning behavior ................................................................................................................................ this entire chapter depends upon your having access to the reference manual for the interface you are using........................ 278 Create and Use Partitions ................................................ 281 Message Management ...................................................................... 278 Cluster Objects Near a Parent ........................................................................................... 287 262 ............................................................................... Unless otherwise noted.............................. 285 Application Programming........................... 276 Some Basic Suggestions ... 263 Data Modeling ............................................................................. 276 Cluster Classes................................................................... 283 Multiple Applications............................................................. 269 Object locations ............................................ Since application performance depends upon the particular task and machines involved................................... only as a guide to things you might want to try.............................................................................................................................................................................................................. Performance Statistics ................................................... interface routines are referred to with generic names........................................

and index pages." which are a lot less expensive than disk reads. When doing initial performance tuning during development. VERSANT Database Fundamentals Manual Performance Statistics To tune an application. which are covered in the chapter "Statistics Collection. This statistic is a measure of "cache hits. you need to know where it is spending time. make a call to a "write statistics" routine after the point where you want to gather statistics. 3. and index pages. This statistic is a measure of "cache misses. To avoid collecting unwanted statistics about VERSANT routines. Add a statistics collection collection routine to your application. or autoStatsWriteOnDBs:. but not log pages. this routine is o_autostatswrite(). be_net_write_time — Seconds spent sending data from the server process to the application. This statistic is expensive to collect. Tell VERSANT to collect statistics by setting the environment variable VERSANT_STAT_FILE to the name of a file. be_data_located — The number of pages read from the server cache." in which needed information had to be read from disk. Specify statistics to collect by setting the VERSANT_STAT_STATS environment variable. table. Commonly used statistics are: fe_real_time — Seconds elapsed since the fe_real_time statistic was turned on. There are numerous ways to collect statistics. disable the low level collection points built into VERSANT by setting the VERSANT_STAT_FUNCS environment variable to an empty string. Set statistics collection on and send statistics to a file. including data. be_data_reads — The number of pages not found in the server cache. 2." Following is one way to do it. In your program. autostatswrite(). Depending upon your interface. but not log pages. table. including data. 4. writing statistics to file is usually preferable 263 . 1. Specify Specify statistics to collect. Disable low level collection points. See the chapter "Statistics Collection" for some suggestions on statistics to collect.

. - 0. In this case. Run your application and collect statistics. you might also want to immediately check the setting of the database profile parameter max_page_buffs (which sets the maximum number of pages used by the server process page buffer) and increase it.5 Copyright (c) 1989-2002 VERSANT Object Technology 0 = delta fe_real_time 1 = delta be_data_reads db1 2 = delta be_data_located db1 0 1 2 ===== ===== ===== . In this case. column 0 for fe_real_time shows which operations are taking the most time. Writing to file also allows you to preserve statistics so that they can be looked at in different ways. you can now investigate what is special about this particular object and operation. Use a third party profiler. For example. View statistics with the vstats utility. 6.061 1 2 op4 on obj 710912 In the above. because writing to file shows statistics for an application's operations rather than for time slices. consider the following sample output.008 2 0 op2 on obj 130476 1. Another useful tool. is a profiler such as Pure Software's Quantify 264 . View your statistics with the vstats utility by invoking it as: vstats -file filename .where filename is the name of the file specified in VERSANT_STAT_FILE..873 132 2 op1 on obj 20384 0. 7.0. and column 1 shows the time spent reading data. the application is spending most of its time reading data pages during operation #1 on object #20384.VERSANT Database Fundamentals Manual to viewing with a direct connection. VERSANT Utility VSTATS Version 6. With this knowledge. you should see some very useful information about where your application is spending its time. 5. Run your application within the scope of the above environment variables and collect statistics for the activities of your application. When you view your statistics.. particularly for tuning application code.

VERSANT Database Fundamentals Manual or the standard prof and gprof. By running a profiled version of the application. Just seeing what percentage various VERSANT operations contribute to the total cost of a user operation can be worth the effort of using a profiler. you can see how much each function contributes to the total time which it took the application to run. 265 .

and make adjustments based upon the real world of disk reads and network traffic. In general. In C and C++. extensibility. Consider how data is used." To find "real objects. Adjusting a model to reflect data use can have a major impact on performance. Your data model will have minuscule performance implications once all needed objects are in memory (where they can be accessed in microseconds. an employee object could logically either embed a name or contain a link to a separate name object. consider combining them into a single object in order to improve access speed. During the design stage. it would be faster to embed the name. For example. and scaleability of your model. Reading a single large object is cheaper than reading two smaller objects. consider combining the small objects into a larger object. and updated. you are going to pay large performance costs. you can combine objects with embedding. During the development stage. It is almost always a good idea to base your model on data usage rather than data structure. 266 . if you have tiny objects everywhere. you might want to use a "pure" object model to describe your situation. you may need to modify your object model to reflect how data is used rather than how it is structured. if you will need the employee name whenever you need the employee object. The process of structuring data in terms of how it is used is sometimes called "finding your real objects. Although you may look for "real objects" with performance in mind.VERSANT Database Fundamentals Manual Data Modeling If your application is spending a lot of time reading data and/or passing data across a network. because pure object models seldom consider the physical limitations of hardware. found." walk your model with your tasks in mind. Combine objects that are accessed together If you look at your data model and see lots of tiny objects.) but it may have considerable impact on disk reads and network traffic. In this case. For example. if two objects are always accessed together. consider how your data is actually created. consider the following suggestions related to your data model. because it reduces the number of disk find and network message operations required. almost certainly you will make changes that will also improve the reusability.

it will be easier to change the references. Another way to structure this is for each object to contain an identical link to the desired object. VERSANT Database Fundamentals Manual Use links to minimize embedding repetitious data. you would not want to embed the same information about a department in each employee object associated with that department. and you may not need to look at department information each time you look at an employee. once you have a root object. It is much faster to find an object with a link than to find an object with a query. it would be better to relate an employee to a department with a link. It is certainly possible to overdo embedding.) In general. consider creating data structures that have a root object containing direct links to all other objects needed. By definition. it is possible to misuse links. a query traverses a database to find and evaluate a group of starting point objects. For example. Use links to minimize queries. While finding objects with links is fast. If you walk your data model and see the need for queries to assemble needed information about a root object.) In this case. you need to build data relationships into your data model. but you want to be able to change the object to which they point. suppose that several objects need to reference a particular object. You can then read all your objects with two messages to the server: one to find and return the root object and a second to group read all the other objects. For example. To do this. but you will pay a cost each time you need to travel to the target object. you should be able to follow links to all information related to that object. (It would take too much disk space. if each employee has a department. while a link contains all the information needed to go directly to a particular object. If you use a generic object approach. even if they are rarely used. One way to model this is to have each object contain a link to a generic object that then points to the desired target object. There is virtually no penalty for adding links to an object. 267 . This is because a link takes negligible storage space (about 8 bytes per link on disk) and thus does not appreciably slow the retrieval of a root object Use direct links if possible. be costly to change information about the department. then you should stop and reevaluate your data model. regardless of its current location (on disk or in memory. because separate fetches are involved. consider using links. If you look at your data model and see repetitious data in your objects. In general.

you may need to create a graph or tree structure. if at some other time you also need to know which garages have which cars. suppose that a person has garages that can contain cars that have colors. shallow. Use bi-directional bi-directional links with care. or it might involve using a dictionary that allows you to go directly to the object that you want. bring the array into memory. then you could create a direct link from a person to a color. Suppose that you have an object with links to many other objects. This can be as simple as keeping a list of links sorted so you can just pick the first one. However. For example. Wide trees are created with link arrays. it is not always possible to directly link root objects with target objects. Wide trees are practical. 268 . or even embed color literals in the person object. you "cold traverse" a database to get an array of links. "hot traverse" the array in memory to get the next array object. In a multi-user environment. Instead. you have to consult information in each of them. You are only really interested in one of these other objects. In general. consider placing the decision making information in the initial object. avoid implementing inverse relationships with bi-directional links without understanding concurrency issues. If the only question you will ever ask is what colors belong to a person. At each step downwards. because they minimize the number of fetches required to move from a root object to a leaf object.) Place access information in your root objects.VERSANT Database Fundamentals Manual Use shallow link structures if possible. because link arrays take relatively small amounts of memory (about 8 bytes per link on disk. It is better to know where you are going than to have to stop and ask for directions. In this case. As cheap as links are. and then cold traverse again to move to the next level. but in order to determine which one. wide trees are better than deep trees. then you will want to create a tree structure.

An object cache will expand as needed and use both real and virtual memory. get the objects you want into memory as fast as possible. Memory caches Object cache — To improve access to objects used in a transaction. Following are concepts that are necessary to implementing memory management strategies. it will be in application memory. Server page cache — To improve access to objects by all users of a database. the cache will be in shared memory. • Balance your use of client and server resources. VERSANT Database Fundamentals Manual Memory Management Memory management strategies The basic memory management strategies are just common sense: • To improve access times. The page cache will have a fixed size and can use both real and virtual memory. • Let objects no longer needed go out of memory. These tables are created on the machine running the application. Object cache table — To improve access to objects used in a session. Session tables — Various session information tables track your processes. and long and short transactions. connected databases. otherwise. a cached object descriptor table is created on the machine running the application. 269 . and maintain other information about the state of the database. If you are using a shared session. and then keep them there until they are no longer needed. Server page cache tables — Associated with the server page cache are information tables that map objects to their physical locations. an object cache is created on the machine running the application. It contains information about the current location (memory or disk. a server page cache is created in shared memory on the machine containing the database. application machine or database machine) of all objects referenced during a session. contain index information.

At any particular time. warm. If you try to pin more objects than can fit into real and virtual object cache memory.) Hot traversals are very fast.) Pinning behavior If you have pinned an object. then it is in real or virtual memory on the application machine. but that is in server page cache memory. A "cold" traversal finds an object in a database on disk. A cold traversal is slower than a warm or hot traversal.VERSANT Database Fundamentals Manual Object locations You can improve application performance dramatically by understanding the places an object can be and taking steps to control its location. then it can be in any of several places. it will probably remain there. brings the data page containing the object into page cache memory. a cold traversal sends a request across the network to the database. then it will be flushed to the machine containing its source database. If the object cache fills up and the object is clean. C/VERSANT does not automatically pin objects. and then the database server process finds the object. an object can also be in a checkout database on the application machine (if you have checked the object out. because more needs to be done to find the object. • In a server page cache on the database machine. • In an object cache on the application machine. then it will be dropped from memory. and cold traversals A "hot" traversal finds an object already in application cache memory (real or virtual. If you unpin an object after it has been pinned. For example. C++/VERSANT automatically pins objects whenever they are dereferenced. if a database containing an object is remote. A "warm" traversal finds an object that is not in application cache memory. 270 . an object is usually in one of the following places: • On disk on the database machine. and sends the object back across the network to the application. If the object cache fills up and the object is new or dirty. If not in one of the above places. If ample space remains in the object cache. you will get an error. Hot.

which will bypass operating system caching and simulate that fact that the chances of getting a cache hit in a very large database is. and internal data structures. In C and C++. se_objs — Number of objects in the object cache. which can obscure issues that will appear when you deploy to a large database and cannot increase cache sizes proportionally. se_objs_dirty — Number of dirty objects in the object cache. test databases are often small. the object cache is flushed whenever a transaction is committed or rolled back. cached object descriptor table. se_cache_used — Bytes used in the application heap. during development. O_COMMIT_AND_RETAIN — Commit new and dirty objects and keep all objects in the object cache. operating systems will have their own layer of caching which you cannot turn off. Since this is often undesirable. By default. which include the object cache. The heap grows when the number of free bytes runs out. se_swapped — Number of objects swapped out of the object cache. During development. by definition. which include the object cache. consider using a raw device for your database system volumes. se_writes — Number of objects written from the object cache. 271 . According. VERSANT Database Fundamentals Manual Memory management statistics The following object cache statistics are especially useful. and internal data structures. low. Use commit and rollback routines that maintain the object cache. cached object descriptor table. several options are provided for retaining objects between transactions. Create a realistic test environment. For example. fe_vm_maj_faults — Virtual memory major page faults (not supported by some operating systems) se_cache_free — Bytes free in the application heap. you should examine these statistics and make sure things are really working the way you intended. se_reads — Number of objects read into the object cache. When measuring scalability it is important to avoid comparing a hot case with a cold case. these options are used with the o_xact() and xact() routines. Once you have determined your model for object cache usage.

you can easily construct a set of modified objects by using a VERSANT routine that iterates over cached object descriptors marked dirty.) 2. A set is needed if the number of objects is large.) Use resources appropriately. Your rule of thumb should be to pin no more 272 . 4. O_RETAIN_SCHEMA_OBJ — Retain schema objects in the object cache after the transaction ends.) Use commit and rollback routines on objects in an array For even finer grained control over what objects are affected by ending a transaction. or checkpointCommit in SequenceableCollection. Your first step should be to subdivide your operations. (Use o_releaseobjs(). This will commit all of the objects in commitvstr and retain all objects and locks. Your basic strategy should be to keep all objects needed for a particular operation in object cache memory on your application machine. consider using a commit routine that operates on objects in a vstr or collection rather than on the entire object cache. (If you want to commit all dirty objects. releaseobjs().VERSANT Database Fundamentals Manual O_CHECKPOINT_COMMIT — Commit new and dirty objects. Call it. O_ROLLBACK_AND_RETAIN — Rollback all changes and keep all clean objects in the object cache. (This will improve performance the next time you get or select instance objects of the classes involved. say. the routines are o_xactwithvstr() and xactwithvstr(). say. You do this by pinning needed objects and unpinning unneeded objects. xactwithvstr(). Perform a checkpoint commit on the objects in your commitset using o_xactvstr(). Iterate through all of the objects in the cached object descriptor table and check each one. Create a set of objects to retain after the commit. of objects to commit. Create a simple collection. If you are dealing with more objects than can fit into object cache memory. Call it. suppose that you want to commit some set of objects and retain some other set. and retain locks. "commitset". in C or C++. say "releaseset". Make a set. such as a link vstr. Following is one way to do this. Use a "release objects" routine on the objects in your releaseset. For example. 3. 1. or releaseAndSkipDirtyObject(). You should retain all class objects and all those in your retainset. In C and C++. what you should do depends upon your hardware and network resources. 5. "retainset". from all other objects. keep all objects in the object cache.

it is not a big deal to use virtual memory and allow the dictionary to be swapped out. In most cases. A good way to do this is to replace a query on the server with a dictionary lookup held in memory on the application machine. the balancing of the use of client versus server resources needs to be performed empirically. To encourage unneeded objects to remain on the application machine. you can force unneeded objects to be dropped by releasing them. Keeping your cache clean is a very common issue. If recently accessed objects are likely to be accessed again. If you don't keep your cache clean. but in drastic cases. the best solution is to get more memory for your application machine. you will initially get good performance and then start to see bad performance when real memory runs out and you begin to thrash virtual memory. it may make sense to cache them as well. With a four byte key. VERSANT Database Fundamentals Manual objects than those that will fit into real memory.) As a rule of thumb. set the swap_threshold parameter in your application profile to be slightly smaller than the size of your real memory (you may need to experiment to get it right. using server resources will probably outperform using virtual memory. you will see error number 4161. To determine whether page faults are occurring. Caching a link costs almost nothing. (Of course. If you run out of real and virtual memory in the application process heap.690 objects. this only costs you a megabyte for each 43. then virtual memory may work best. If memory constraints prevent you from caching an object. In this case. In this case. If your object cache grows too big. Your next step should be to decide what you want to do with the temporarily unneeded objects. "Out of frontend heap memory".) Generally. To encourage unneeded objects to be dropped or flushed. you should use the object cache for both the current working set of objects and any frequently used objects. If your connection to the server is expensive and objects are accessed in sequential passes. choose a high value for the swap_threshold parameter. it may still be useful to cache a link to it. Keep your object cache clean Keeping objects out of the object memory cache can be at least as important as keeping objects in the cache. You can also monitor se_cache_used and se_objs to determine when real memory is exhausted. monitor the fe_vm_maj_faults statistic. setting swap_threshold is enough. 273 . If your server connection is cheap and/or you are accessing objects in random order. it will trigger virtual memory page faults which can dramatically decrease performance. VERSANT will expand and use virtual memory until resources are no longer available. OM_HEAP_NOMEM.

even if you have a database which is many orders of magnitude larger than your physical memory. To both drop an object and clear its cod table entry. Release unneeded objects — To force VERSANT to drop unneeded objects immediately. you may still get a major improvement in performance by increasing your server cache size if it means that the support tables can remain in real memory. a million or more) of objects in a session. while be_data_located is likely to be high. remember to allow for their needs. you can commit or rollback a transaction with a "zap cods" option that will both clear the entire table and drop all objects from cache memory.VERSANT Database Fundamentals Manual Following are ways to keep your object cache clean. If you need to reclaim space in the application process heap and have not been zapping objects as you go. However. this means that there is not enough physical memory. remember to allow for the server page cache support tables. The statistics which are most relevant to the server page cache are be_data_reads. It is faster for a database server process to retrieve an object from a database than from virtual memory. where each page specified in max_page_buffs equals 16K of memory. release them. be sure that you do not zap a dirty object. the cached object descriptor (cod) table. If you zap objects. If your server cache is working well. If you are also simultaneously running other programs on the database machine. be sure that you do not release a dirty object or a class object. be_data_writes. Zap unneeded objects — If you reference a very large number (say. This will allow VERSANT to drop or flush unneeded objects. This could be because the max_page_buffs is set higher than physical memory or it could mean that another application on that machine is using more memory than you anticipated. be_data_located. may grow to a significant size. If values for be_vm_maj_faults starts increasing. For example. which have a major impact on performance. although it does not guarantee that the objects will be removed from memory. you can zap it with a "zap cods" interface routine. which maintains information about all objects accessed in the session. Set your server page cache size appropriately. This means that you should always set the size of the server page cache to be as large as possible but still smaller than available real memory. because the page cache is a fixed size. an object that is the target of a link in a dirty object. or a class object. Consider running with a single process If your application will access only a single database that is located on the same machine as the 274 . and be_vm_maj_faults. Also. the values for be_data_reads and be_data_writes will be low. Unpin unneeded objects — Unpin objects that are not needed. The size of the server page cache is set by the value of the max_page_buffs parameter in the server process profile for a database. because a server process has access to information about object locations and can be smarter about caching.

) However. consider linking your application with the single process library. if you run in a single process. Running your application in a single process can improve performance dramatically (by 20-50%. 275 . it is possible for a runaway pointer bug in your application code to corrupt data structures and crash the database. VERSANT Database Fundamentals Manual application.

it is generally a good idea to temporarily set the database max_page_buffs profile parameter as low as possible. If two related pieces of information are stored on the same disk page. do not set it so low that the pages necessary for a single operation don't fit in the cache and thrashing ensues. the physical log. Gather statistics about disk usage. without a cache hit you can never hope for better than two reads. Ideally. Some Basic Suggestions Use faster. Multiple disk drives can also increase performance. However. which would distort your statistics. In general. The faster the disk drive on which a database resides.VERSANT Database Fundamentals Manual Disk Management Improving disk input and output can increase performance dramatically. and they are more predictable. consider all available network and storage resources available to you and then place your databases where they can best take advantage of your resources. particularly if multiple access patterns force you to trade off each specific case in order to optimize the average case. In any event. Particularly important can be your storage strategy. You can then look at the be_data_reads statistic and try to get it as low as possible via clustering. the better. Using a small cache while tuning minimizes the possibility of cache hits and allows you to see the true number of reads for each operation." as indexes can significantly improve disk access by queries. See also the chapter "Query Indexes. one for the data page and one for the object location table 276 . which can include clustering and use of partitions. more disk devices. It is better to use raw devices for a database than operating system files. because they do not implement additional buffering outside of VERSANT. the logical log. They are 5% to 10% faster. better. accessing one will bring both into the backend cache in a single operation. While tuning clustering. Storing related objects physically close to each other can greatly improve the speed of accessing them together. Use the following formula to determine a rough goal for the avg delta be_data_reads statistic: (number of objects)(average object size + 20)/16K + (number of objects)/809 + 2 Keep in mind that you may not be able to achieve this goal. and the system volumes should all be on different physical devices.

If instances of one or more class are usually accessed together. With the default strategy. Objects are stored in extents of contiguous pages. specify clustering hints. The clustering routines do not force a clustering. no action will be taken for that class. it will improve performance if you create your objects and then use a group write routine to store them in the same order in which you will access them. Do not use NFS file systems. This will place them in physical proximity on the storage media and thus reduce the time required to find and retrieve instances of the classes if they are being used as a group. and then import instances from the interim database. The default VERSANT strategy places first priority on clustering all instances within a class. it also ensures that the database server process will 277 . This will improve the chances that related objects will be stored on the same or contiguous pages. you can use an interface specific routine to suggest to VERSANT that instances of the desired classes be stored in the same cluster. VERSANT Database Fundamentals Manual page. If a class already has been assigned storage. each class is in a separate "cluster." and instances are stored on a set of data pages within the cluster. you can migrate all objects of the classes to be clustered to an interim database. performance may suffer. but does not group particular sets of classes. Although this reduces concurrency. drop and then recreate the classes in the original database. Thus. To cluster classes after they have been created. If you use an NFS partition to mount and access your databases. When concurrently loading objects. Routines that will cluster classes are: C o_cluster() C++ cluster() in PDOM Create objects in the order in which you will access them. Once you have asked VERSANT to cluster related classes. Once you have tuned clustering to your satisfaction. or else VERSANT will ignore the hint. turn the single_latch server process profile parameter temporarily "on". they suggest to a database that a clustering should be performed. it is important to run a clustering routine before instances are created. Instead. don't forget to restore the max_page_buffs parameter to its original state. Cluster Classes Cluster classes if instances are frequently accessed together. VERSANT does not need NFS to access databases.

278 . This technique of creating objects in a useful order has an important side effect. Cluster Objects on a Page You can cluster objects on a page by using a "group write isolated" routine. However. any given object is more likely to be in the middle of a page than at the beginning. If you have multiple access patterns. then you will probably have to experiment with different orderings and clusterings. the "group write clustered" operation is not considered refill and the page will be used if the parent object is on the page. not just after it. A page will continue to be freed if it has no objects stored on it. VERSANT updates an object location table that associates the object identifier with the object physical location. but the Storage Manager places the given objects near an existing parent object. Routines that will cluster objects on a page are: C o_groupwriteisolated() C++ groupwriteisolated() in PDOM Cluster Objects Near a Parent You can cluster objects near a parent object by using a "group write clustered" routine. Each page in the table holds 809 associations. A "group write clustered operation" works like a normal group write.VERSANT Database Fundamentals Manual not release a latch on the database cache acquired by a group write routine until the routine has completely finished. VERSANT first find the object identifier in the location table. • Second the Storage Manager marks all pages used as "NO REFILL". and look ups will proceed more quickly if all needed object identifiers are found on the same page. this means that they will not be used for normal refill. and then uses that information to find the object physically. rather than trying to use the "current" page for the storage file or trying to refill existing pages. A group write isolated operation works like a normal group write. the Storage Manager always starts with a new page to store the objects. On the average. This has two effects: • First. Each time an object is stored. When you use a link to find an object. it may be useful to put related objects on both sides of it. but it suggests that the storage manager isolate the given objects on their own page. If you have a root object that is always accessed first.

you can partition a class to control how instances of a class will be distributed among available physical devices. Logical partitions A logical partition is a storage segment that consists of one or more disk volumes. If the page does not have enough space. partitions expand and take volume space as needed. Allocating a partition to a volume does not reserve space on the volume. instead. Routines that will cluster objects near a parent object are: C o_groupwriteclustered() C++ groupwriteclustered() in PDOM Create and Use Partitions To take advantage of parallel. A class space consists of logical partitions. Disk volumes A disk volume provides space for one or more partitions. If both these conditions are met. VERSANT treats a partition as a continguous space. even when it spans disk volumes. new pages will be allocated and the objects will be stored there. Storage Architecture Following are concepts related to the VERSANT storage architecture. The object must exist in the database and it must be in the same storage file as the child objects. Class space Class space is the storage space allocated for instance objects of a class. VERSANT Database Fundamentals Manual First. the Storage Manager attempts to store the child objects on the same page as the parent object. 279 . the parent object is looked up to find its physical location. multiple disk device input/output.

There are two allocation algorithms that VERSANT can use: First-available — The first-available algorithm uses the first partition that has enough space for the new pages. In fact. any number of classes can use the same partition. Storage Strategies When a database needs new pages. VERSANT picks a partition to use for the new pages. The following shows the possibilities that you can define. Round-robin — The round-robin algorithm uses the next partition (after the last partition used) that has enough space for the new pages. any number of partitions can use the same volume.VERSANT Database Fundamentals Manual The following shows the class space hierarchy in its simplest form. and a partition can use any number of volumes. 280 . Note that the following diagram is simplified.

When you restart the database. this approach is useful only if there are times when the database is not in use. but they will be more expensive when they do happen. 1. One option is to use huge log files which won't fill up and then. Configure Log Volumes Set the size of your log volumes appropriately. If you want to force a checkpoint at each commit. indexes defined on attributes of a class. You can override the default storage strategy with either the C/VERSANT function o_partition() or the system utility dbtool. checkpoints can take up to several seconds or more. force a checkpoint by stopping the database with the stopdb utility. set the server process parameter commit_flush to ON. all traversals will be cold. The unlucky operation that triggers a checkpoint will take much longer than otherwise identical operations. at low usage times. VERSANT internally triggers a checkpoint when either its physical or logical log volume is filled. VERSANT creates the same number of logical partitions as the number of database volumes that have been defined. and internal system information. since stopping a database clears the server page cache as well as the log files. One partition per volume By default. In other words. because the page cache will initially be empty. such as at the end of a day. First-available allocation By default. Depending on the amount of data in memory. See the "Database Utilities" chapter of your VERSANT Database Administration Manual for information on dbtool. VERSANT Database Fundamentals Manual By default VERSANT uses the following storage strategy for instances of a class. Larger log files will reduce the number of checkpoints. However. A checkpoint is an expensive operation in which all data is flushed to the system volumes and the log files are cleared. Larger log files give you better throughput and average response time. data pages are allocated first to the system volume and then to the storage volumes in the order in which they were created. 2. but increase the worst case response time. 281 . VERSANT defines a logical partition for the system volume and for each storage volume. See your C/VERSANT Reference Manual for information on o_partition(). Small log file sizes lead to more frequent but less expensive checkpoints.

it will temporarily grow if necessary (disk space permitting). so being big enough to hold the largest transaction is not quite as crucial. 282 . If it's on a file system. If the log file is on a raw device. Placing the logical and physical log volumes on raw devices can improve performance if you are triggering a large number of checkpoints.VERSANT Database Fundamentals Manual Put your log volumes on raw devices. it must be big enough to hold information for the biggest transaction that will occur.

If you perform a group write. Use group operations to read and write objects. Although storing objects in the object cache is the most obvious use of this technique. This is because each line of statistics output involves a single RPC to get the value of any server statistics being collected. even when you are accessing a local database. you can specify options that will release objects from memory and/or clear the cached object descriptor table. including the connection to the session database. collect and examine the be_net_rpcs statistic.) Cache frequently used operations. communications between the application process and a server process will occur over a network. you should try to reduce the number of messages that need to be exchanged between application and server processes. and group delete) whenever possible. instead use a "commit with vstr" or "commit with collection" routine. which will lead to potential performance problems if network traffic is heavy or otherwise slow. however. Rather than repeat an operation. links. save its value from the first time and reuse it.) If you are accessing a database on a remote machine. (If you want to save changes and release locks. In addition to the normal benefit of reducing network traffic. and then roll back. group operations contain optimizations which make them inherently more efficient than multiple iterations of their single object counterparts. VERSANT Database Fundamentals Manual Message Management In most cases. there are other additional possibilities. (The only time that VERSANT runs in one process is if you are accessing only a personal database and have linked your application with the single process library. you will get unpredictable results. Gather statistics about network traffic. consider caching non-object information (such as numbers. VERSANT runs in at least two process: an application process and a server process for each database connection. group write. so you should not downgrade their locks. downgrade locks. If it enables you to meaningfully reduce 283 . Use group operations (group read. To assess the number of network messages that are occurring. Keep in mind that the number of network messages (or "RPCs") reported will tend to be one higher than if you were not collecting statistics. As appropriate. that these objects will still be a part of the current transaction and subject to roll back. However. Remember. and query results) in local variables or transient data structures. If you use a group write or group delete.

which reduces network traffic. you should also consider caching information in persistent objects in a session database on your local machine.VERSANT Database Fundamentals Manual your number of network messages. If network traffic is a problem and concurrent access to objects is not. 284 . you can checkout objects to provide local access. Checkout objects.

VERSANT Database Fundamentals Manual Multiple Applications If the database will be serving multiple clients. processor. reduce latch contention by turning the single_latch server process profile parameter to "off. consider distributing objects over multiple databases. be_user_time — Seconds of cpu time not in operating system kernel functions be_system_time — Seconds of cpu time in operating system kernel functions be_lock_wait_time — Seconds clients spent waiting for locks be_latch_wait_time — Seconds waiting for latch. Gather multiple client statistics. adding an additional client will increase throughput on the machine containing the database and decrease response time as experienced by the applications. and shared data structures. When dealing with multiple client applications. Add additional databases if application performance is the primary issue. new issues and opportunities come into play. If your objective is to maximize response time and if the nature of the data allows it. For example. collect and examine the following statistics." If disk. Add additional clients if server performance is the primary issue. or data structure utilization approaches 100%. processor. based on the last digit of the phone number. consider adding additional databases. In general. Even when it is not strictly necessary. concurrent access to a single database may be desirable since it can improve performance on the database machine by reducing context switching and increasing utilization of disk. To gauge contention for shared resources. If you are adding clients to a database. a single database of telephone numbers could be partitioned into ten databases. be_real_time — Seconds elapsed since the be_real_time statistic was turned on. This is inherently more efficient than running multiple clients against a single database since each database can have its own set of resources and be completely independent of 285 . it is important to distinguish between response time and throughput.

you can also replicate objects in several databases. The only downside is that there will be a small lag time between when an update is made to one database and when the change is propagated to the other databases. Asynchronous replication is best implemented with event notification and "move object" features. In addition to partitioning data between multiple databases.VERSANT Database Fundamentals Manual the other databases. 286 . Each client can then use the database to which it is closest. This has the same advantage of eliminating bottlenecks and works particularly well in a widely distributed environment. Use asynchronous replication to improve application performance.

such as a group read. is input or output bound while others. 287 . locking. don't lock any more objects than necessary. and client/server models should be designed in. for example. your transaction model. Depending upon your platform and release. If a group of objects is always locked together. you could use the convention that none of the objects in a container can be modified unless a write lock is obtained on the container object. it is important to develop and implement a transaction. locking. and server strategy.) then consider using optimistic locking. it makes sense to use processes or threads if one operation. For example. such as printing. If only a few applications will access a database and if the chances of them conflicting is low (say. In general. When using a "single lock plus a protocol" technique. In a multi-user environment. try to make sure that all objects needed for a particular operation can be accessed as a group and then released quickly. If it is possible that one application will attempt to modify an object that is being used by another application. you can safely turn locking off. are not. In your data model. you may be able to use multiple processes or threads in a transaction. In brief. VERSANT Database Fundamentals Manual Application Programming Develop a transaction. as retrofitting rarely works well. Turn off locking if only one application will access the database. consider using an application protocol that avoid placing a separate lock on every object in the group. If you need to use strict locking. locking model. If you are going to use optimistic locking. that most applications are just reading data. it is important to keep your transactions as short as possible to minimize lock contention. For example. if multiple applications will be updating objects. Use multiple processes and threads. some form of locking is necessary. If only one application will access a database. and server usage model as early as possible in your development process. Lock as few objects as possible. be careful not to implicitly lock a group of objects which should not always be locked together. The reduced concurrency typically will more than negate the advantage of reducing the number of locks. you must be sure that all applications involved use a consistent application protocol and access objects in ways and times that maximize concurrency.

A single large cache can make much more efficient use of memory by eliminating the redundant storage of objects associated with multiple smaller caches. As its name implies. we recommend using this option. In other words. because original copies of objects remain in their source databases. Since database reads is the most common operation. keep in mind the distinction between per process statistics with an fe_ prefix and per session statistics with an se_ prefix. Logging should be "on" if you want your database to be recoverable. db_obe_locks_waiting — The number of server processes (applications) waiting for locks.VERSANT Database Fundamentals Manual If concurrent access to objects is an issue. In brief. The major disadvantage of shared sessions is that inter-client concurrency will be reduced due to latch contention for shared object cache resources. be_lock_deadlocks — The number of deadlocks that occurred. be_lock_waits — The number of lock waits that occurred. it should be "on" for the vast majority of production applications. be_lock_timeouts — The number of timeouts that occurred due to waiting for locks. In this case. single writer" option. This allows multiple client processes to share a single session with a single frontend cache. When looking at statistics for a shared session. Use the se_latch_wait_time statistic to gauge how much time is lost due to latch contention. If you don't care about any of these things. easy. or if you want to use log rollforward. Consider using a shared session. this option imposes the restriction that only the root process is allowed to write to the database. using links to navigate to objects and phrasing of queries to use indexes properly can significantly 288 . Turning logging off is safe if used in conjunction with checkouts. gather and examine the following statistics. If your application will have multiple clients running on a single machine. turn logging "off" for a quick. and substantial performance increase. It allows you to access the object cache even while concurrent database reads and writes are taking place. See also the "Queries" and "Indexes" chapters for numerous suggestions related to optimizing queries. be_lock_wait_time — The number of seconds that applications spent waiting for locks. Optimize queries. but you may not care. consider using shared sessions. if you want to do rollbacks. Turn logging off if it is not needed. This can result in a better hit ratio and increased performance. a database can be corrupted. This contention can be alleviated greatly by also using the "many readers.

Optimize link dereferencing. Preallocate identifiers if you are going to create a large number of objects. however.236 calls. avoid defining attributes (C++ data members) as public. • You are mainly dereferencing links from a particular database. When you dereference a link. Although not strictly a performance tip. 289 . use a "set loid capacity" routine to reserve a specific number of logical object identifiers. then you will make just one call to the server to reserve object identifiers. suppose that you want to create 34 million new objects. Always use access methods (get methods) and modifier methods (set methods) to manage data. you should recognize that the characteristics of objects will change over time. So that all applications in an system operate in consistent ways. databases are searched for the target object in the following order: 1. the order will change. starting with your session database. VERSANT reserves 1024 logical object identifiers (LOIDs) to reduce amount of requests going to the server every time you create new persistent objects. If you reserve your logical object identifiers ahead of time. By default. Place access methods in your class rather than your applications.) This approach will improve performance only if all of the following are true: • You are using C++. 2. If you know ahead of time that you are going to create a large number of objects. Under some circumstances. (If you connect and disconnect a number of times. This can improve performance by reducing the number of server requests. VERSANT Database Fundamentals Manual improve query performance. The database of the object containing the link. you might consider the order in which you connect to databases. • The connected databases are large. interfaces should persist. • You are connected to a large number of databases. For example. for each application. rather than 33. Other databases in the order in which you connected to them.

................................................................................................................................................................................ 291 Statistics Viewing ................................................................................................................................. 298 Collect Statistics and Store Them in a File ....................................................................... 311 Names of Session Statistics ............................................................................................................................................................................................................................................................................................................... 318 Names of Latch Statistics .......................................................................................................................... 291 Statistics Quick Start............... 299 Collect Statistics in Memory and View in Real Time ......................................................... 302 Collect Derived Statistics ................................................................................ 309 Names of Function Statistics...........................................VERSANT Database Fundamentals Manual Chapter 15: Statistics Collection Statistics Collection Overview......... 293 Get Statistics with Automatic Profiling ................................... 320 290 ..................................... 312 Names of Connection Statistics . 304 Statistics Collection Usage Notes ................................................................................................................. 296 Get Statistics with Interface Routines.................................................................................................................................................................................................................................. 291 Statistics Types .............................................................................................................................................................................................................................................................................................................................................................................. 308 Statistics Names........................................................ 309 Names of Process Statistics ................................... 301 Get Statistics Parameters.................................. 307 Statistics Collection and the Fault Tolerant Server Option............................ 303 Statistics Suggestions ............................................................................................................................... 293 Get Statistics with a Direct Connection ....................................................................................................................................... 307 Statistics General Notes...... 316 Names of Database Statistics........................................................... 307 Statistics Collection Procedures for Applications.................................................

You can also monitor the time spent in VERSANT functions by using predefined function names in statistics tools and routines. such as the number of dirty objects in the object cache. session information and application process information are the same. such as the number of seconds that applications spend waiting for locks. Unless you are in a shared session. you can collect the following kinds of statistics about applications and databases. such as the number of objects read into the object cache. Information about an application process You can monitor application activity." Statistics Types To help you measure and analyze performance. see the chapter "Performance Tuning. Information about databases You can monitor database information. When you collect 291 . Information about sessions You can monitor session information. For information on how to use these statistics. Derived statistics You can derive your own statistics using combinations of other statistics along with numerical operators and statistical functions. Information about latches You can monitor latches per database or per connection. You can monitor the time spent in your own functions by setting enter and exit points that trigger statistics collection. such as the number of active transactions. Information about connections You can monitor connections made to a database. Statistics Viewing You can collect statistics in a file and view them with the command line utility vstats. VERSANT Database Fundamentals Manual Statistics Collection Overview This chapter explains how to collect performance monitoring statistics.

When you collect statistics in memory. you can view them in real time with the vstats utility or bring them into your application with a "get statistics" routine. You can also collect statistics in memory. at your leisure. you can either view them in real time or later. 292 .VERSANT Database Fundamentals Manual statistics to a file.

which you can use if you want a "quick start" way of beginning. we can then view its value with the -stats option to vstats: vstats -database db1 -stats “db_data_reads db1” \ “db_data_located db1” 293 . it is often useful to view a listing of all statistics. Turn statistics on The first step in using a direct connection is identifying the statistics of interest. we might choose the db_data_reads and db_data_located statistics as the ones which we would like to examine. The disadvantages are lack of access to application statistics and lack of information on what operations a database is performing. invoke the following from a command line: vstats -summary Now suppose we are interested in the performance of a database page cache. and with interface routines. Get Statistics with a Direct Connection You can use the vstats utility to connect directly to a database and display database or connection statistics. Since there are so many statistics available. complete list of statistics names. The most direct and convenient way to do this is by invoking vstats as follows: vstats -database db1 -on db_data_reads \ db_data_located View statistics for a database Once a statistic is turned on. The first step in viewing a statistic is to make sure that collection of that statistic is turned on. The advantages of using a direct connection are convenience and low overhead. VERSANT Database Fundamentals Manual Statistics Quick Start Following is a brief overview of statistics collection. Select statistics. with automatic profiling. From the list of all statistics. There are three ways to access VERSANT performance monitoring functionality: with a direct connection. each with a one line explanation. To receive a long.

2052' Server Process = 'gamehendge':20341 Client Process = 'gamehendge':20339 Protocol = TCP/IP Server Port = 192. called be_data_reads and be_data_located.173. To get information about all the current connections to a database.0.0. For example: VERSANT Utility VSTATS Version 6.25:5019 Client Port = 192.70.25:5019 Client Port = 192.9220' Server Process = 'gamehendge':20334 Client Process = 'gamehendge':20332 Protocol = TCP/IP Server Port = 192.173.25:1041 Connection ID = 20341 User Name = 'george' Session Name = 'vstats -connections' Long Transaction = '228. a new line of values is printed every 5 seconds until you type Ctrl-C to break.5 Copyright (c) 1989-2002 VERSANT Object Technology 0 = db_data_reads db1 1 = db_data_located db1 0 1 ===== ===== 31 190 35 200 37 217 By default.0.70. Connection identifiers are specified with the -id option to vstats.173.70. Per connection versions of these statistics.70.0. are also available.173.VERSANT Database Fundamentals Manual This command will result in two columns of values being printed: VERSANT Utility VSTATS Version 6.5 Copyright (c) 1989-2002 VERSANT Object Technology Connection ID to database 'db1': Connection ID = 20334 User Name = 'george' Session Name = 'example session' Long Transaction = '228. View statistics for a database connection In the previous example. use the -connections option to vstats: vstats -database db1 -connections This will cause a list of all connections to the specified database to be printed. we viewed the per-database statistics db_data_reads and db_data_located. To view per connection statistics.25:1043 294 . it is necessary to specify a connection identifier in addition to a database name.

0. For example. First. VERSANT Database Fundamentals Manual From the resulting output. To view the be_data_reads and be_data_located statistics for the example program. For example: VERSANT Utility VSTATS Version 6.5 Copyright (c) 1989-2002 VERSANT Object Technology 0 = be_data_reads db1 1 = be_data_located db1 0 1 ===== ===== 23 123 28 155 32 188 Create statistics expressions It is not necessary to limit yourself to the atomic statistics listed by the vstats -summary command. Connection 20334 is for an example program and connection 20341 is for the vstats command which we used to list the connections. to print the page cache hit ratio for the example program: vstats -database db1 -id 20334 \ -stats “delta be_data_located db1 \ / (delta be_data_located db1 \ + delta be_data_reads db1)” 295 . we have to use the -on command for vstats to turn on these statistics for the example program's connection: vstats -database db1 -id 20334 \ -on be_data_reads be_data_located Once the statistics are on. The -stats command understands standard arithmetic operations and a few built in functions. we must do two things. we can see that there are two connections. the -stats command will periodically print rows of statistic values. we can use the -stats command to view them: vstats -database db1 -id 20334 \ -stats “be_data_reads db1” “be_data_located db1” As before.

and () operators. Get Statistics with Automatic Profiling The second method of accessing statistics also involves the vstats tool.670 NaN 0. /. The advantages of automatic profiling are that it gives access to the application as well as the server statistics and that it provides information on individual database operations. you should be aware that there are other environment variables which can be set to limit the statistics which are written to this file. For example: setenv VERSANT_STAT_FILE /tmp/app.5 Copyright (c) 1989-2002 VERSANT Object Technology 0 = delta be_data_located group / (delta be_data_located group + delta be_data_reads group) 0 ===== - 0. note the NaN ("not a number") value on the third line. thus increasing performance. Finally.VERSANT Database Fundamentals Manual This will result in output similar to the following: VERSANT Utility VSTATS Version 6. Since the delta function requires two lines of output before it can return a value. all application and server statistics are written to the file for all operations. input is taken from a profile file generated by the application.528 Note the use of the standard arithmetic +. However. Create statistics profile file The easiest way to generate a statistics profile file is by setting the VERSANT_STAT_FILE environment variable before running your application. By default.vs This will cause the application to automatically create the specified file and write statistics to it whenever certain database operations take place. instead of taking input directly from the database. This will happen when a divide by zero error occurs due to there being no change in either of the two atomic statistics. This is completely logical. Note also the use of the built in delta function which returns the difference between an expression's current value and it's value on the previous line. 296 .0. the first line of output for this expression is blank. Although it is beyond the scope of this overview. since a read hit ratio is undefined over a time period where no reads occur. The disadvantage is that it can involve substantial performance overhead.

For example: vstats -database db1 -on In the above example.vs -stats \ “delta fe_real_time” “db_data_located db1” \ “be_data_located db2” Note that the database server statistics require database names. Application statistics and per connection server statistics will be turned on automatically. As before. The only difference is that a file name is specified instead of a database name. you could use the following command: vstats -filename /tmp/app. The syntax for examining statistics in a profile file is almost identical to the syntax used in the direct connection model. only the second of these two lines is labeled with the operation. It provides information about what database operation that line of values is associated with. use the vstats -on command. one which shows values before the operation and one which shows values after the operation. all statistics will be turned on for all current connections.db2) In the above output. View statistics from a profile file You can examine the contents of the profile file with the vstats utility. simply run your application.0. 297 . To reduce screen clutter.5 Copyright (c) 1989-2002 VERSANT Object Technology 0 = delta fe_real_time 1 = db_data_located db1 2 = be_data_located db2 0 1 2 ===== ===== ===== . the db_data_located for db1 and the be_data_located for db2. The above command will produce output similar to the following.db2) 0.055 59 3 o_xact(db1. VERSANT Utility VSTATS Version 6. there is an extra column which is not present when using the direct connection model. for example. 59 3 0. Once the environment variables are set and the statistics are turned on. since no statistics or connection identifiers were specified. So. and the profile file will be automatically generated. to show the change in fe_real_time. Note also how a list of database names is provided along with each operation name. For each operation.269 60 4 o_xact(db1. there are two lines of output. This shows for which databases server side statistics were collected and written to the profile file. while the application statistic does not. be sure to turn on any per database server statistics which you are interested in viewing. VERSANT Database Fundamentals Manual Before running your application.216 60 4 0.

To get the current values of statistics which are on. use the "write statistics on entering function" and "write statistics on exiting function" routines. Simply insert the "write statistics automatically" routine function into your application code wherever you would like statistics to be sampled and written to file. If you would like to write statistics samples at the beginning and end of one of your application's operations. To turn statistics on. use the "get activity information" routine. 298 . use the "get statistics" routine. To get a list of connection identifiers which can be passed to these functions. To turn statistics off. Get Statistics with Interface Routines The third and final method for accessing statistics is through low level statistics routines for your interface. use the "turn statistics collection on" routine. It is easy to specify additional points in your application where statistics should be written to the profile file. Primitive flexibility are both the advantage and the disadvantage of this method. use the "turn statistics collection off" routine.VERSANT Database Fundamentals Manual Create user defined collection points It is possible that the statistics collection points built into the beginning and end of various low level database operations will prove to be inadequate.

Statistics will be collected only for the activities of your own application and only for the duration of your session. the vstats utility sends statistics to stdout. VERSANT_STAT_DBS. To filter the statistics collected and set other collection parameters. but it requires you to modify your application code. To collect any statistic for any database to which your application makes a connection. you can pipe the output of stdout. you can set the environment variable VERSANT_STAT_FILE to the name of a file and then run your application within its scope. VERSANT_STAT_TIME. Statistics will be collected only for the activities of your own application and only for the duration of your session. Collecting statistics with environment variables is the same as invoking a "begin automatic collection" routine from within an application each time you make a database connection. By default. You may want to filter the statistics collected to reduce file size and improve application performance. See the chapter "VERSANT Configuration Parameters" in the VERSANT Database Administration Manual for more information. To collect any statistic for any database and any application. Statistics will be collected only for connections in existence at the time vstats is invoked. you can use the VERSANT_STAT_STATS. VERSANT Database Fundamentals Manual Collect Statistics and Store Them in a File Following are the ways you can collect performance and monitoring statistics about a VERSANT application and send them to a file. you can call "begin collection" routines from within the application. Using a routine to begin automatic collection allows greater control. See the VERSANT Database Administration Manual for a complete reference to vstats. and VERSANT_STAT_FLUSH environment variables. To send statistics to a file. you can invoke the vstats utility from the command line. Set statistics collection on and send to file To collect any statistic for any database to which your application has made a connection. c o_autostatsbegin() env VERSANT_STAT_FILE util vstats 299 . VERSANT_STAT_FUNCS.

or you can view statistics at a later time by invoking vstats with the -file parameter. c o_autostatsenter() Collect statistics on function exit If you use a "collect statistics in a file" routine or the VERSANT_STAT_FILE environment variable to collect statistics. If you use one of these routines. If you use a "collect on entering" routine. you can either end your session or use an explicit "end automatic collection routine. you must also use a "collect statistics on exiting" routine. Use "collect and write" any other time that you want to collect statistics. c o_autostatsexit() Collect statistics and write to file A "collect and write" routine will collect the current set of statistics and write them to file along with a specified comment. Use "collect on entering" and "collect on exiting" routines to add collection points at the beginning and end of your functions. c o_autostatswrite() View statistics in file You can view statistics written to a file by using the vstats utility. you can use a "collect statistics on function entry" routine to collect and write statistics when entering a non-VERSANT function. you must also use a "collect on exiting" routine. util vstats 300 ." c o_autostatsend() o_endsession() c++ endsession() Collect statistics on function entry If you use a "collect statistics in a file" routine or the VERSANT_STAT_FILE environment variable to collect statistics.VERSANT Database Fundamentals Manual Set statistics collection off when using file To stop collection started with a "begin automatic collection" routine. The text that you will see will be formatted and filtered per command line parameters (the text is not human readable when viewed with a text editor.) You can view the statistics file in real time by invoking vstats with the -stdin parameter. you can use a "collect statistics on function exit" routine to both collect and write statistics when exiting a non-VERSANT function.

VERSANT Database Fundamentals Manual Collect Statistics in Memory and View in Real Time Following are the ways that you can collect statistics and send them to memory. you can set the stat server process configuration parameter for that database. Until the database stops and restarts. calling these methods will override any setting made in the stat server process configuration parameter that applies to the specified connection. you can invoke a "collect statistics" routine from within an application. c o_getstats() 301 . util vstats Get statistics from memory To view any statistic for a particular database and particular database connection. VERSANT_STAT_FILE. Statistics are printed to stdout. you can ask for statistics by connection or database. c o_collectstats() View statistics in memory To view in real time any statistic being collected for any database and any application. and specified connection statistics will be collected whenever any application connects to the database. you can specify a "direct connection" to one or more databases when you invoke the vstats utility. Set statistics collection on and send to memory To collect any database and/or connection statistic associated with a particular database. Invoking these methods has no effect on statistics collection separately being performed by vstats. Their effect on the specified connection will persist even after the end of the session in which they are called. Statistics are sent to an array from which you can fetch them. Values are sent for all collected statistics at the moment when the routine is invoked. you can invoke a "get statististics" routine from within an application. specified database statistics will be collected whenever the database starts. To collect any statistic for a particular database connection already in existence. After setting stat. or beginAutoCollectionOfStatistics:. When you invoke vstats. c o_collectstats() util vstats cfg stat Set statistics collection off when using memory You can override stat by calling a general or specific "turn off" routine.

Get lock information. Get transaction information The vstats utility and the "turn on collection. locks.VERSANT Database Fundamentals Manual Get Statistics Parameters Get connection information.". and "get statistics" routines allow you to set or get statistics for a specified database connection. 302 . Following are ways that you can get information about current connections. c o_getactivityinfo() o_gettransid() c gettransid() util vstats dbtool Get object information." "turn off collection. Get volume information The dbtool utility can also get information about objects and storage volumes assoicated with a particular database. and transactions so that you can specify the required parameters.

To predefine derived statistics. VERSANT Database Fundamentals Manual Collect Derived Statistics You can derive useful statistics using combinations of other statistics along with numerical operators and statistical functions.vstatsrc win vstats. The name of the configuration file depends upon your operating system. When it starts. vstats will read and use the configuration file to collect and compute the derived statistics.ini 303 . unix . you can create definitions in the statistics configuration file.

To see if there is lock contention: be_lock_waits Lock waits which occurred. To see if the cpu is the bottle neck: fe_cpu_time A derived statistic. be_cpu_time db A derived statistic. db_lock_wait_time Seconds spent waiting for locks. See the following section. Not all operating systems support these statistics. To find out whether an operation is application bound or database bound: fe_run_time A derived statistic. To find out which operations to delve into: fe_real_time Seconds of real time. 304 . be_run_time db A derived statistic. Not all operating systems support these statistics. To see if there is virtual memory thrashing: fe_vm_maj_faults Virtual memory major page faults. db_lock_waits Lock waits which occurred. "Statistics Names." for the formula used by derived statistics. where db is the name of a database. be_lock_wait_time Seconds spent waiting for locks.VERSANT Database Fundamentals Manual Statistics Suggestions Following are some suggestions for which statistics to collect. where db is the name of a database. be_vm_maj_faults Virtual memory major page faults.

fe_reads Objects read into the object cache. To see if there is an opportunity for group operations: be_net_rpsc Database rpc's received from clients. se_reads Objects read into the object cache. VERSANT Database Fundamentals Manual To see if there is latch contention: be_latch_waits Number of waits for any latch. db_obj_received Objects received from the application. be_data_writes Pages written to sysvol + added volumes. 305 . db_data_writes Pages written to sysvol + added volumes. db_latch_waits Number of waits for any latch. be_obj_received Objects received from the application. db_obj_sent Objects sent to the application. db_net_rpsc Database rpc's received from clients. db_latch_wait_time Seconds waiting for any latch. To see if the disk is the bottleneck: be_data_reads Pages read from sysvol + added volumes. db_data_reads Pages read from sysvol + added volumes. db_bf_llog_bytes_written Bytes written to logical log. be_obj_sent Objects sent to the application. db_bf_plog_bytes_written Bytes written to physical log. be_latch_wait_time Seconds waiting for any latch.

To see if cached object descriptors need to be zapped or if objects need to be released: se_cods CODs in object cache. se_objs Objects in object cache. db_bf_llog_bytes_written Bytes written to logical log. db_bf_plog_bytes_written Bytes written to physical log. db_bf_llog_flushes Number of writes to logical log. db_bf_plog_flushes Number of writes to physical log. 306 .VERSANT Database Fundamentals Manual To tune logging: db_checkpoints System checkpoints.

Statistics Collection Procedures for Applications Following are general notes for statistics collection from within an application. After statistics collection has been enabled. 5. 307 . possibly. use the autoStatsEnteringFunction: and autoStatsExitingFunction: methods in VStatistics. To turn on automatics statistics collection. and configuration parameters. use the endAutoCollectionOfStatistics: method in VStatistics. VXactInfo. use the getActivityInfoOn: method in VStatistics. and connections. use the getStatisticsOf: method in VStatistics. To find information about locks. methods. you can limit collection to specific databases and/or connections and change parameters for collection and write intervals. first turn on statistics collection with the turnOnCollectionOfStatistics: method in VStatistics. 1. To retrieve statistics from within an application. Since this could be a significant overhead. and VConnectInfo. 4. a potential file write each time a collection point is encountered. To turn off automatic statistics collection. To collect statistics from within an application. the profiling overhead will be two remote procedure calls and. 3. 2. utilities. transactions. VERSANT Database Fundamentals Manual Statistics Collection Usage Notes Statistics General Notes Who— Who Only the user who created a database can turn statistics collection on or off. You can turn off collection of some or all statistics by using the turnOffCollectionOfStatistics: method. other users can collect statistics Overhead — When statistics collection is turned on. Support classes for the getActivityInfoOn: method are the classes VLockInfo. See also your reference manuals for usage of specific functions. To add collection points for your own methods. use the beginAutoCollectionOfStatistics: method in VStatistics.

308 . To collect statistics for a replica database. statistics collection tools and mechanisms operate only on named databases and not on replica databases. you must apply statistics collection mechanisms specifically to the replica database.VERSANT Database Fundamentals Manual Statistics Collection and the Fault Tolerant Server Option Even when database replication has been turned on.

For example: shown — o_releaseobjs use — CAPI_RELEASEOBJS When used in vstats or an environment variable When statistic names are specified to the vstats Statistics Tool or used in the environment variable VERSANT_STAT_FUNCS: • Enter the name in lowercase (as shown.) 309 .) • Enter the name with the leading "o_" prefix (as shown. specify the C/VERSANT function that performs the same task. • Prefix the name shown with "CAPI_". Names of Function Statistics You can use the following names to specify collection of statistics only for specific functions. • Delete the "o_" prefix. The symbolic names are used as parameters in functions and methods. Following are statistics that you can collect and the names of functions for which you can collect statistics. For C++/VERSANT methods. VERSANT Database Fundamentals Manual Statistics Names Each statistic has a name and stores a numeric value. When used in a function When statistic names are to be used in a function: • Enter the name in uppercase.

VERSANT Database Fundamentals Manual For example: shown — o_releaseobjs use — o_releaseobjs Names of function statistics o_addparentvsn Statistics for o_addparentvsn() o_beginpinregion Statistics for o_beginpinregion() o_checkin Statistics for o_checkin() o_checkinreturnobjs Statistics for o_checkinreturnobjs() o_createvsn Statistics for o_createvsn() o_deleteobj Statistics for o_deleteobj() o_deletevsn Statistics for o_deletevsn() o_endactivity Statistics for o_endactivity() o_endpinregion Statistics for o_endpinregion() o_gcheckout Statistics for o_gcheckout() o_gdeleteobjs Statistics for o_gdeleteobjs() o_getchildvsns Statistics for o_getchildvsns() o_getcod Statistics for o_getcod() o_getdefaultvsn Statistics for o_getdefaultvsn() o_getparentvsns Statistics for o_getparentvsns() o_getvsnno Statistics for o_getvsnno() o_getvsnstatus Statistics for o_getvsnstatus() o_ggcheckout Statistics for o_ggcheckout() o_greadobjs Statistics for o_greadobjs() o_gwriteobjs Statistics for o_gwriteobjs() o_isclassobj Statistics for o_isclassobj() o_locatevsn Statistics for o_locatevsn() o_pathpcheckout Statistics for o_pathpcheckout() o_pathselect Statistics for o_pathselect() o_pcheckout Statistics for o_pcheckout() o_preptochange Statistics for o_preptochange() o_preptoversion Statistics for o_preptoversion() o_refreshobj Statistics for o_refreshobj() o_refreshobjs Statistics for o_refreshobjs() o_releaseobj Statistics for o_releaseobj() o_replenishcache Statistics for o_replenishcache() 310 .

• Prefix the name shown with "STAT_". VERSANT Database Fundamentals Manual o_resetoct Statistics for o_resetoct() o_savepoint Statistics for o_savepoint() o_select Statistics for o_select() o_setdefaultvsn Statistics for o_setdefaultvsn() o_setvsnstatus Statistics for o_setvsnstatus() o_undosavepoint Statistics for o_undosavepoint() o_xact Statistics for o_xact() o_xactwithvstr Statistics for o_xactwithvstr() o_zapcods Statistics for o_zapcods() Names of Process Statistics The following statistics can be collected per application process.) For example: shown — fe_net_bytes_read use — fe_net_bytes_read 311 . When used in a function When statistic names are to be used in a function: • Enter the name in uppercase. For example: shown — fe_net_bytes_read use — STAT_FE_NET_BYTES_READ When used in vstats or an environment variable When statistic names are specified to the vstats Statistics Tool or used in the environment variable VERSANT_STAT_FUNCS: • Enter the name in lowercase (as shown.

fe_net_reads Reads from back end. fe_real_time Seconds of real time. fe_reads Objects read into object cache. Names of Session Statistics When used in a function When statistic names are to be used in a function: • Enter the name in uppercase. fe_writes Objects written from object cache. fe_net_writes Writes to back end. fe_net_bytes_read Bytes read from back end. fe_net_read_time Seconds reading from back end. fe_user_time Seconds not in OS kernel functions. • Prefix the name shown with "STAT_". fe_cpu_time = fe_system_time + fe_user_time Not all operating systems support this statistic. fe_run_time Derived statistic. fe_net_write_time Seconds writing to back end. fe_net_bytes_written Bytes written to back end.fe_latch_wait_time fe_swapped Dirty objects swapped out of object cache. fe_system_time Seconds in OS kernel functions.VERSANT Database Fundamentals Manual Names of application per process statistics fe_cpu_time Derived statistic. fe_run_time = fe_real_time - fe_net_read_time . fe_net_write_time . fe_vm_maj_faults Virtual memory major page faults. 312 . fe_swapped_dirty Objects written as a result of object swapping.

se_heap_small_allocates_2 Allocates in size class 2 (13-16 bytes). se_heap_small_allocates_12 Allocates in size class 12 (129-160 bytes). se_heap_small_allocates_1 Allocates in size class 1 (9-12 bytes). se_heap_small_allocates_9 Allocates in size class 9 (65-80 bytes). se_heap_small_allocates_4 Allocates in size class 4 (21-24 bytes). se_heap_small_allocates_13 Allocates in size class 13 (161-192 bytes). se_heap_small_allocates_8 Allocates in size class 8 (49-64 bytes).) For example: shown — se_cache_free use — se_cache_free Names of application per session statistics se_cache_free Derived statistic. se_heap_small_allocates_6 Allocates in size class 6 (33-40 bytes). se_heap_small_allocates_7 Allocates in size class 7 (41-48 bytes). se_heap_small_allocates_10 Allocates in size class 10 (81-96 bytes). se_heap_allocates Number of "allocate" operations smaller than one page. 313 . se_cache_used = se_heap_used se_cods CODs in object cache. se_heap_small_allocates_11 Allocates in size class 11 (97-128 bytes). se_cache_free = se_heap_free se_cache_used Derived statistic. VERSANT Database Fundamentals Manual For example: shown — se_cache_free use — STAT_SE_CACHE_FREE When used in vstats or an environment variable When statistic names are specified to the vstats Statistics Tool or used in the environment variable VERSANT_STAT_FUNCS: • Enter the name in lowercase (as shown. se_heap_small_allocates_5 Allocates in size class 5 (25-32 bytes). se_heap_small_allocates_3 Allocates in size class 3 (17-20 bytes). se_heap_small_allocates_0 Allocates in size class 0 (1-8 bytes).

se_heap_small_allocates_23 Allocates in size class 23 (1633-2048 bytes). se_heap_small_frees_6 Number of frees in size class 6 (33-40 bytes). se_heap_small_frees_20 Number of frees in size class 20 (817-1024 bytes). se_heap_small_frees_17 Number of frees in size class 17 (409-512 bytes). se_heap_empty_segments Number of empty segments in front-end heap. se_heap_small_frees_3 Number of frees in size class 3 (17-20 bytes). se_heap_small_allocates_26 Allocates in size class 26 (3073-4096 bytes). se_heap_small_frees_19 Number of frees in size class 19 (681-816 bytes). se_heap_frees Number of "free" operations on front-end heap. se_heap_small_allocates_17 Allocates in size class 17 (409-512 bytes). se_heap_small_allocates_15 Allocates in size class 15 (257-336 bytes). se_heap_small_frees_11 Number of frees in size class 11 (97-128 bytes). se_heap_small_frees_15 Number of frees in size class 15 (257-336 bytes). se_heap_small_allocates_29 Allocates in size class 29 (6145-10240 bytes). se_heap_small_frees_9 Number of frees in size class 9 (65-80 bytes). se_heap_small_allocates_22 Allocates in size class 22 (1361-1632 bytes). se_heap_small_allocates_27 Allocates in size class 27 (4097-5120 bytes). se_heap_small_frees_13 Number of frees in size class 13 (161-192 bytes). se_heap_small_frees_0 Number of frees in size class 0 (1-8 bytes). se_heap_small_frees_14 Number of frees in size class 14 (193-256 bytes). se_heap_small_frees_18 Number of frees in size class 18 (513-680 bytes). se_heap_small_allocates_18 Allocates in size class 18 (513-680 bytes). se_heap_small_allocates_16 Allocates in size class 16 (337-408 bytes). se_heap_small_allocates_31 Allocates in size class 31 (12289-20480 bytes). se_heap_small_frees_2 Number of frees in size class 2 (13-16 bytes). se_heap_small_frees_1 Number of frees in size class 1 (9-12 bytes). se_heap_small_allocates_21 Allocates in size class 21 (1025-1360 bytes). se_heap_small_frees_8 Number of frees in size class 8 (49-64 bytes). se_heap_free Bytes free in front-end heap. se_heap_small_frees_10 Number of frees in size class 10 (81-96 bytes). se_heap_small_allocates_19 Allocates in size class 19 (681-816 bytes). se_heap_small_allocates_28 Allocates in size class 28 (5121-6144 bytes). se_heap_small_frees_5 Number of frees in size class 5 (25-32 bytes). se_heap_small_frees_16 Number of frees in size class 16 (337-408 bytes). se_heap_small_allocates_20 Allocates in size class 20 (817-1024 bytes). se_heap_small_frees_4 Number of frees in size class 4 (21-24 bytes). se_heap_small_frees_12 Number of frees in size class 12 (129-160 bytes). se_heap_small_allocates_24 Allocates in size class 24 (2049-2720 bytes).VERSANT Database Fundamentals Manual se_heap_small_allocates_14 Allocates in size class 14 (193-256 bytes). se_heap_small_allocates_30 Allocates in size class 30 (10241-12288 bytes). se_heap_small_allocates_25 Allocates in size class 25 (2721-3072 bytes). 314 . se_heap_small_frees_7 Number of frees in size class 7 (41-48 bytes).

se_heap_total_segments Number of segments in front-end heap. se_heap_used Bytes used in front-end heap. se_heap_small_population_n Derived statistic. se_heap_small_frees Number of "free" operations smaller than 1 page. se_heap_small_population = se_heap_small_allocates - se_heap_small_frees se_heap_small_size Derived statistic. se_heap_optimistic_used = se_heap_used - se_heap_small_free se_heap_population Derived statistic. se_heap_small_frees_26 Number of frees in size class 26 (3073-4096 bytes). se_heap_small_frees_30 Number of frees in size class 30 (10241-12288 bytes). VERSANT Database Fundamentals Manual se_heap_small_frees_21 Number of frees in size class 21 (1025-1360 bytes). 315 . se_heap_small_frees_29 Number of frees in size class 29 (6145-10240 bytes). se_heap_small_frees_25 Number of frees in size class 25 (2721-3072 bytes). See the reference to the heap_size_class application profile parameter for an explanation of class size states. For n. se_heap_small_frees_31 Number of frees in size class 31 (12289-20480 bytes). se_heap_small_frees_24 Number of frees in size class 24 (2049-2720 bytes). se_heap_population = se_heap_allocates - se_heap_frees se_heap_size Derived statistic. se_heap_small_frees_27 Number of frees in size class 27 (4097-5120 bytes). se_heap_size = se_heap_used + se_heap_free se_heap_small_allocates Number of "allocate" operations smaller than 1 page. se_heap_optimistic_free Derived statistic. se_heap_small_frees_23 Number of frees in size class 23 (1633-2048 bytes). se_heap_small_free Bytes free for allocations smaller than 1 page. se_heap_optimistic_free = se_heap_free + se_heap_small_free se_heap_optimistic_used Derived statistic. se_heap_small_frees_28 Number of frees in size class 28 (5121-6144 bytes). se_heap_small_size = se_heap_small_used + se_heap_small_free se_heap_small_used Bytes used for allocations smaller than 1 page. substitute a number from 0 to 31. which refers to a class size state. se_heap_small_frees_22 Number of frees in size class 22 (1361-1632 bytes). se_heap_max_gap Size of largest free area in front-end heap in bytes.

Names of Connection Statistics The following statistics can be collected per server connection. se_net_writes Writes to back end. se_net_reads Reads from back end. se_net_write_time Seconds writing to back end. se_swapped_dirty Objects written as a result of object swapping.) 316 . For example: shown — be_data_located use — STAT_BE_DATA_LOCATED When used in vstats or an environment variable When statistic names are specified to the vstats Statistics Tool or used in the environment variable VERSANT_STAT_FUNCS: • Enter the name in lowercase (as shown. This makes it possible to connect to a database and view database process statistics for connections other than your own. • Prefix the name shown with "STAT_". se_objs_dirty Dirty objects in cache. se_net_bytes_written Bytes written to back end. se_reads Objects read into object cache. se_writes Objects written from object cache. se_swapped Objects swapped out of object cache. se_objs Objects in object cache. se_net_read_time Seconds reading from back end. When used in a function When statistic names are to be used in a function: • Enter the name in uppercase.VERSANT Database Fundamentals Manual se_net_bytes_read Bytes read from back end.

VERSANT Database Fundamentals Manual For example: shown — be_data_located use — be_data_located Names of server connection statistics be_cache_hit_ratio db Derived statistic. be_locks_granted Locks requested and granted. be_cache_hit_ratio db = be_data_located db / (be_data_located db + be_data_reads db) be_cpu_time db Derived statistic. be_net_bytes_read Bytes read from front end. be_lock_wait_time Seconds clients spent waiting for locks. be_data_writes Pages written to sysvol + added volumes. where db is the name of a database. be_ev_user_delivered User events delivered. be_ev_defined Events defined. be_data_reads Pages read from sysvol + added volumes. be_ev_sys_delivered System events delivered. 317 . be_net_read_time Seconds reading from front end. be_lock_timeouts Timeouts waiting for locks. where db is the name of a database. be_data_located Pages found in database page cache. be_inst_cache_hit_ratio db Derived statistic. where db is the name of a database. be_ev_sys_raised System events raised. be_net_bytes_written Bytes written to front end. be_ev_user_raised User events raised. be_lock_waits Lock waits which occurred. be_cpu_time db = be_system_time db + be_user_time db Not all operating systems support this statistic. be_inst_cache_hit_ratio db = delta be_data_located db / (delta be_data_located db + delta be_data_reads db) be_lock_deadlocks Deadlocks occurred.

be_qry_btree_objs Objects read during B-tree query. be_xact_active Active transactions. be_vm_maj_faults Virtual memory major page faults. be_net_write_time Seconds writing to front end. be_run_time db Derived statistic.be_latch_wait_time db be_system_time Seconds in OS kernel functions. be_obj_received Objects received from front end.VERSANT Database Fundamentals Manual be_net_reads Reads from front end. be_run_time db = be_real_time db - be_net_read_time db . be_user_time Seconds not in OS kernel functions. be_net_writes Writes to front end. be_xact_rolled_back Transactions rolled back. 318 . be_real_time Seconds elapsed. be_xact_committed Transactions committed. be_net_rpcs Database RPCs received from clients.be_net_write_time db . be_qry_hash_objs Objects read during hash query. be_obj_sent Objects sent to front end. be_qry_scan_time Seconds spent in sequential scan query. • Prefix the name shown with "STAT_". where db is the name of a database. be_qry_btree_time Seconds spent in B-tree query. 0 otherwise. Names of Database Statistics The following statistics can be collected per database. be_xact_started Transactions started. be_qry_scan_objs Objects read during sequential scan query. be_obe_locks_waiting 1 if waiting for lock. be_qry_hash_time Seconds spent in hash query. When used in a function When statistic names are to be used in a function: • Enter the name in uppercase.

319 .) For example: shown — db_bf_llog_flushes use — db_bf_llog_flushes Names of database statistics db_bf_llog_bytes_written Bytes written to logical log. db_cache_hit_ratio db Derived statistic. db_ev_defined Events defined. db_cache_hit_ratio db = db_data_located db / (db_data_located db + db_data_reads db) db_checkpoints System checkpoints. db_bf_plog_bytes_written Bytes written to physical log db_bf_plog_flushes Number of writes to physical log. db_bf_llog_flushes Number of writes to logical log. db_ev_sys_raised System events raised. db_ev_sys_delivered System events delivered. db_disk_free Bytes of storage available. db_disk_reserved Bytes of storage reserved by classes. db_data_reads Pages read from sysvol + added volumes. db_ev_user_raised User events raised. db_data_writes Pages written to sysvol + added volumes. db_data_located Pages found in database page cache. db_ev_user_delivered User events delivered. VERSANT Database Fundamentals Manual For example: shown — db_bf_llog_flushes use — STAT_DB_BF_LLOG_FLUSHES When used in vstats or an environment variable When statistic names are specified to the vstats Statistics Tool or used in the environment variable VERSANT_STAT_FUNCS: • Enter the name in lowercase (as shown.

db_locks_granted Locks requested and granted. db_net_bytes_written Bytes written to front end. db_xact_committed Transactions committed. db_net_rpcs Database RPCs received from clients. db_obj_sent Objects sent to front end. db_lock_wait_time Seconds clients spent waiting for locks. db_qry_hash_time Seconds spent in hash query. db_net_writes Writes to front end. Names of Latch Statistics There are four basic types of latch statistics: latch_released latch_granted latch_waits latch_wait_time For each of these. db_lock_timeouts Timeouts waiting for locks. db_inst_cache_hit_ratio db = delta db_data_located db / (delta db_data_located db + delta db_data_reads db) db_lock_deadlocks Deadlocks occurred. db_xact_started Transactions started. db_qry_btree_time Seconds spent in B-tree query. db_obj_received Objects received from front end. db_qry_scan_objs Objects read during sequential scan query. db_xact_active Active transactions. db_net_write_time Seconds writing to front end. 320 . db_net_bytes_read Bytes read from front end. db_obe_locks_waiting Connections waiting for locks. there are both per database (db_*) and per connection (be_*) versions of each statistic. db_net_reads Reads from front end. db_qry_hash_objs Objects read during hash query.VERSANT Database Fundamentals Manual db_inst_cache_hit_ratio db Derived statistic. db_lock_waits Lock waits which occurred. db_qry_scan_time Seconds spent in sequential scan query. db_xact_rolled_back Transactions rolled back. db_net_read_time Seconds reading from front end. db_qry_btree_objs Objects read during B-tree query.

Also. be_latch_granted_bf_bkt Number of BF_BKT latches granted. positive if more. and negative if less. When used in a function When statistic names are to be used in a function: • Enter the name in uppercase. *_heap. VERSANT Database Fundamentals Manual In addition. The value will be 0 if the same number of latches. etc. there are two derived statistics: be_latch_holds and db_latch_holds.) For example: shown — be_latch_granted use — be_latch_granted Names of latch statistics be_latch_granted Number of latches granted of any type. These are defined to be the number of latches granted minus the number released (latch_granted . *_sda. *_voldev.). The exception to this is the latch_released statistic which is not available for the individual latch types. each statistic is available for all latches or for an individual type of latch (e. 321 . The values of these statistics are not absolute.g. be_latch_granted_bf Number of BF latches granted. but are relative to the number of latches held when the statistic is turned on. For example: shown — be_latch_granted use — STAT_BE_LATCH_GRANTED When used in vstats or an environment variable When statistic names are specified to the vstats Statistics Tool or used in the environment variable VERSANT_STAT_FUNCS: • Enter the name in lowercase (as shown.latch_released) and give an indication of how many latches are currently being held. be_latch_granted_bf_dirty Number of BF_DIRTY latches granted. • Prefix the name shown with "STAT_".

be_latch_wait_time_cp_wait Seconds waiting for CP_WAIT latch. be_latch_granted_llog Number of LLOG latches granted. be_latch_granted_tre Number of TRE (transaction entry) latches granted. be_latch_granted_cp Number of CP latches granted. be_latch_holds db = be_latch_granted db - be_latch_released db be_latch_released Number of latches released of any type. be_latch_wait_time_bf_dirty Seconds waiting for BF_DIRTY latch. be_latch_granted_cp_wait Number of CP_WAIT latches granted. be_latch_granted_l2file Number of L2FILE latches granted. be_latch_granted_sce Number of SCE latches granted. 322 . be_latch_granted_sdhs_bkt Number of SDHS_BKT latches granted. be_latch_granted_sda Number of SDA latches granted. be_latch_granted_log_unit Number of LOG_UNIT latches granted. be_latch_granted_ss Number of SS latches granted. be_latch_granted_voldev Number of VOLDEV latches granted. be_latch_holds db Derived statistic. be_latch_granted_sc Number of SC latches granted. be_latch_wait_time Seconds waiting for any latch. be_latch_wait_time_ev Seconds waiting for EV latch. be_latch_granted_ev Number of EV latches granted. be_latch_wait_time_heap Seconds waiting for HEAP latch. be_latch_granted_sch Number of SCH latches granted. be_latch_granted_ps Number of PS latches granted. be_latch_granted_sd Number of SD latches granted. be_latch_granted_phy Number of PHY latches granted. be_latch_granted_l2file_da Number of L2FILE_DA latches granted. be_latch_granted_plog Number of PLOG latches granted. be_latch_wait_time_bf_bkt Seconds waiting for BF_BKT latch. be_latch_wait_time_bf Seconds waiting for BF latch. be_latch_granted_lock Number of LOCK latches granted. be_latch_wait_time_bf_free Seconds waiting for BF_FREE latch. be_latch_granted_sdhs Number of SDHS latches granted. be_latch_wait_time_cp Seconds waiting for CP latch. be_latch_granted_tr Number of TR latches granted.VERSANT Database Fundamentals Manual be_latch_granted_bf_free Number of BF_FREE latches granted. be_latch_granted_heap Number of HEAP latches granted.

be_latch_waits_cp Number of waits for CP latch. be_latch_waits_bf_bkt Number of waits for BF_BKT latch. be_latch_waits_bf_dirty Number of waits for BF_DIRTY latch. 323 . be_latch_wait_time_voldev Seconds waiting for VOLDEV latch. be_latch_wait_time_ss Seconds waiting for SS latch. be_latch_waits_plog Number of waits for PLOG latch. be_latch_wait_time_sdhs_bkt Seconds waiting for SDHS_BKT latch. be_latch_waits_sc Number of waits for SC latch. be_latch_wait_time_plog Seconds waiting for PLOG latch. be_latch_waits_lock Number of waits for LOCK latch. be_latch_waits_llog Number of waits for LLOG latch. be_latch_wait_time_tr Seconds waiting for TR latch. be_latch_wait_time_llog Seconds waiting for LLOG latch. be_latch_wait_time_sdhs Seconds waiting for SDHS latch. be_latch_wait_time_log_unit Seconds waiting for LOG_UNIT latch. be_latch_waits_phy Number of waits for PHY latch. be_latch_wait_time_phy Seconds waiting for PHY latch. VERSANT Database Fundamentals Manual be_latch_wait_time_l2file Seconds waiting for L2FILE latch. be_latch_waits_log_unit Number of waits for LOG_UNIT latch. be_latch_wait_time_l2file_da Seconds waiting for L2FILE_DA. be_latch_wait_time_ps Seconds waiting for PS latch. be_latch_wait_time_sch Seconds waiting for SCH latch. be_latch_wait_time_sce Seconds waiting for SCE latch. be_latch_waits_bf_free Number of waits for BF_FREE latch. be_latch_wait_time_sd Seconds waiting for SD latch. be_latch_waits_ps Number of waits for PS latch. be_latch_wait_time_sda Seconds waiting for SDA latch. be_latch_waits_l2file Number of waits for L2FILE latch. be_latch_waits_cp_wait Number of waits for CP_WAIT latch. be_latch_waits Number of waits for any latch. be_latch_waits_l2file_da Number of waits for L2FILE_DA latch. be_latch_waits_heap Number of waits for HEAP latch. be_latch_wait_time_lock Seconds waiting for LOCK. be_latch_waits_bf Number of waits for BF latch. be_latch_wait_time_sc Seconds waiting for SC latch. be_latch_waits_ev Number of waits for EV latch. be_latch_wait_time_tre Seconds waiting for TRE (transaction entry).

db_latch_granted_sdhs_bkt Number of SDHS_BKT latches granted. db_latch_granted_log_unit Number of LOG_UNIT latches granted. db_latch_granted_l2file Number of L2FILE latches granted. be_latch_waits_tre Number of waits for TRE (transaction entry) latch. db_latch_granted_heap Number of HEAP latches granted. db_latch_granted_bf Number of BF latches granted. be_latch_waits_voldev Number of waits for VOLDEV latch. db_latch_granted_bf_bkt Number of BF_BKT latches granted. db_latch_granted_ev Number of EV latches granted. db_latch_granted_ss Number of SS latches granted. db_latch_granted Number of requests for any latch. db_latch_granted_cp_wait Number of CP_WAIT latches granted.VERSANT Database Fundamentals Manual be_latch_waits_sce Number of waits for SCE latch. db_latch_granted_phy Number of PHY latches granted. db_latch_granted_sch Number of SCH latches granted. db_latch_granted_sc Number of SC latches granted. db_latch_granted_cp Number of CP latches granted. db_latch_granted_tr Number of TR latches granted. be_latch_waits_sdhs_bkt Number of waits for SDHS_BKT latch. db_latch_granted_bf_dirty Number of BF_DIRTY latches granted. be_latch_waits_ss Number of waits for SS latch. 324 . db_latch_granted_sda Number of SDA latches granted. db_latch_granted_sd Number of SD latches granted. be_latch_waits_sch Number of waits for SCH latch. be_latch_waits_sd Number of waits for SD latch. db_latch_granted_sce Number of SCE latches granted. db_latch_granted_bf_free Number of BF_FREE latches granted. db_latch_granted_lock Number of LOCK latches granted. db_latch_granted_ps Number of PS latches granted. db_latch_granted_l2file_da Number of L2FILE_DA latches granted. db_latch_granted_llog Number of LLOG latches granted. be_latch_waits_tr Number of waits for TR latch. be_latch_waits_sdhs Number of waits for SDHS latch. db_latch_granted_plog Number of PLOG latches granted. db_latch_granted_sdhs Number of SDHS latches granted. be_latch_waits_sda Number of waits for SDA latch.

db_latch_wait_time_sdhs_bkt Seconds waiting for SDHS_BKT latch. db_latch_granted_voldev Number of VOLDEV latches granted. db_latch_wait_time_bf_bkt Seconds waiting for BF_BKT latch. 325 . db_latch_wait_time_plog Seconds waiting for PLOG latch. db_latch_waits Number of waits for any latch. db_latch_wait_time_heap Seconds waiting for HEAP latch. db_latch_wait_time_l2file_da Seconds waiting for L2FILE_DA. db_latch_wait_time_sd Seconds waiting for SD latch. db_latch_wait_time_llog Seconds waiting for LLOG latch. db_latch_wait_time_cp_wait Seconds waiting for CP_WAIT latch. db_latch_wait_time_sda Seconds waiting for SDA latch. db_latch_holds db = db_latch_granted db - db_latch_released db db_latch_released Number of latches released of any type. db_latch_wait_time_lock Seconds waiting for LOCK. db_latch_wait_time_cp Seconds waiting for CP latch. db_latch_wait_time_sce Seconds waiting for SCE latch. db_latch_wait_time_bf_free Seconds waiting for BF_FREE latch. db_latch_wait_time_ps Seconds waiting for PS latch. db_latch_wait_time_ss Seconds waiting for SS latch. db_latch_wait_time_bf Seconds waiting for BF latch. db_latch_wait_time_voldev Seconds waiting for VOLDEV latch. db_latch_wait_time_sch Seconds waiting for SCH latch. db_latch_wait_time_ev Seconds waiting for EV latch. db_latch_wait_time_tre Seconds waiting for TRE (transaction entry). db_latch_wait_time_l2file Seconds waiting for L2FILE latch. db_latch_waits_bf Number of waits for BF latch. db_latch_wait_time_tr Seconds waiting for TR latch. db_latch_holds db Derived statistic. db_latch_wait_time_phy Seconds waiting for PHY latch. db_latch_wait_time Seconds waiting for any latch. db_latch_wait_time_sdhs Seconds waiting for SDHS latch. db_latch_wait_time_sc Seconds waiting for SC latch. db_latch_wait_time_log_unit Seconds waiting for LOG_UNIT latch. db_latch_waits_bf_bkt Number of waits for BF_BKT latch. VERSANT Database Fundamentals Manual db_latch_granted_tre Number of TRE (transaction entry) latches granted. db_latch_wait_time_bf_dirty Seconds waiting for BF_DIRTY latch.

db_latch_waits_phy Number of waits for PHY latch. db_latch_waits_sdhs_bkt Number of waits for SDHS_BKT latch. se_latch_wait_time Seconds waiting for latch. db_latch_waits_tre Number of waits for TRE (transaction entry) latch. db_latch_waits_sce Number of waits for SCE latch. db_latch_waits_lock Number of waits for LOCK latch. db_latch_waits_ss Number of waits for SS latch. fe_latch_wait_time Seconds waiting for latch. db_latch_waits_ev Number of waits for EV latch. db_latch_waits_l2file Number of waits for L2FILE latch. db_latch_waits_sd Number of waits for SD latch.VERSANT Database Fundamentals Manual db_latch_waits_bf_dirty Number of waits for BF_DIRTY latch. db_latch_waits_sdhs Number of waits for SDHS latch. db_latch_waits_sc Number of waits for SC latch. db_latch_waits_l2file_da Number of waits for L2FILE_DA latch. db_latch_waits_llog Number of waits for LLOG latch. db_latch_waits_voldev Number of waits for VOLDEV latch. db_latch_waits_sda Number of waits for SDA latch. db_latch_waits_sch Number of waits for SCH latch. db_latch_waits_log_unit Number of waits for LOG_UNIT latch. db_latch_waits_bf_free Number of waits for BF_FREE latch. db_latch_waits_ps Number of waits for PS latch. db_latch_waits_tr Number of waits for TR latch. 326 . db_latch_waits_cp_wait Number of waits for CP_WAIT latch. db_latch_waits_heap Number of waits for HEAP latch. db_latch_waits_cp Number of waits for CP latch. db_latch_waits_plog Number of waits for PLOG latch.

.............................................................................. 330 327 ................................................................................................................. VERSANT Database Fundamentals Manual Chapter 16: Garbage Collection Concepts ....................................................... 328 Garbage Collection Policy Suggestions ................................................................ 329 Garbage Collection Safety.......................

char. If a generic instance is reachable.VERSANT Database Fundamentals Manual Concepts Following are key garbage collection terms. tombstone_sysclass 328 . If a versioned object is reachable. db_dir. all objects to which it has links are reachable. loid_db. attribute. Garbage objects Garbage objects are objects which are not system objects and are not reachable. If an object is reachable. pl_class. System objects are defined to be instances of any class whose name begins with o_ and also instances of these classes: class. lo_class. Database root classes Database root classes are those classes named on the command line. All database roots objects are reachable. dba_uid. all of its versions are reachable. Database root objects Database root objects are objects named by loid on the command line and all instances of database root classes. method. its generic instance and all of its versions are reachable.

VERSANT Database Fundamentals Manual

Garbage Collection Policy Suggestions

The best way to use the garbage collector is to define one or more classes to be database root classes. Make
sure that all of your objects that you want to keep are installed in some instance of one of the database roots
classes.

If several different sets of objects are stored in the same database, and each set of objects has different
database roots classes and objects, you must use the union of all these database roots classes and objects on
the command line. Objects created by different language interfaces may be used and garbage collected
together in the same database as long as this union policy is used.

All C++ objects derive from PObject, and thus will be considered roots, and therefore not deleted.

Limitations
• Only a single database is garbage collected. If objects in the database are reachable but only via
objects in another database, they will be thought to be garbage.
• The garbage collector runs in the default long transaction and does not know about any objects
not visible to and available to the default long transaction.
• The garbage collector must be the only program accessing the database.

Caution

The requirement that the garbage collection be the only program accessing the database is not enforced.
However, it is thought to be safe if other programs that only read non-garbage objects are connected to
the database.
• If a database is very large and the object relationships in the database are very complex, then
garbage collection may fail with an "out of heap" error message. This means that you have run
out of system swap space. Before using garbage collection, you should maximize available swap
space.

329

VERSANT Database Fundamentals Manual

Garbage Collection Safety

The garbage collector is inherently dangerous, as are commands such as dropinst, dropclass, and
removedb.

In particular, if you name no roots on the command line, the garbage collector will remove all objects in the
database except system objects.

330

VERSANT Database Fundamentals Manual

Chapter 17: Event Notification
Overview .................................................................................................................................... 332
Event Notification for C and C++ .................................................................................................... 335
Event Notification Overview for C and C++ .................................................................................. 335
Event Notification Procedures for C and C++ ............................................................................... 335
Event Notification Actions for C and C++ ..................................................................................... 337
Usage Notes for C and C++ ....................................................................................................... 339
Event Notification Example in C++ .............................................................................................. 347
Event Notification Performance Statistics......................................................................................... 360
Asynchronous Database Replication............................................................................................... 361
Asynchronous Database Replication Concepts ............................................................................. 361
Asynchronous Database Replication Actions................................................................................ 361
Asynchronous Database Replication Procedures .......................................................................... 361
Asynchronous Database Replication, C++/VERSANT Example....................................................... 362

331

VERSANT Database Fundamentals Manual

Overview

Event notification mechanisms allow you to monitor objects and classes and receive a message when a
specified object is modified or deleted or when an instance of a specified class is created, modified, or
deleted. You can also define your own events and receive a message if the event occurs on a specified object
or an instance of a specified class.

Following are key concepts.

Event

An "event" is something that happens.

System event

A "system event" is an event pre-defined by VERSANT. For example, system events occur when a class or
instance object is created, modified, or deleted.

User event

A "user event" is an event defined in an application.

Event message

An "event message" is a message sent by VERSANT when an event occurs.

Event registration

To receive an event message when a particular event occurs, you must "register" interest in the event
with the database involved.

Event notification

When a registered event occurs, VERSANT sends an event message to a database queue on the
database where the event occurred. These messages stay in the queue until you explicitly ask for them.

Transient Mode

In transient mode, VERSANT keeps a list of event registrations and a list of generated events in memory.
When the database stops, the lists are lost. This is the default mode.

332

VERSANT Database Fundamentals Manual

Persistent Mode

In persistent mode, VERSANT stores the list of event registrations and the list of generated events in the
database. When the database stops, the lists remain.

To specify persistence, use the following parameters in your application server profile file profile.be.
event_msg_mode Specify persistent event messages.
event_registration_mode Specify persistent event registrations.
You should set these parameters to Transient Mode for compatibility with existing/legacy applications.
New applications can use either mode, in any combination. For instance, you can set your new
application to use persistent event registration with transient event messages. You should avoid using
old_transient with new applications, though, as it will be phased out in later releases.

For more information on setting mode, see the chapter "Database Profiles" in your VERSANT Database
Administration Manual.

Number of event notifications

Event registrations are dynamically allocated and kept in the server database. Theoretically, there is no
limit to the number of events that you can register, but practically, the number is limited by available
shared memory.

Also, as the number of registrations is increased against a specific object on an event, the time to search
for those interested registrations will also increase. And, when an event is raised, it will trigger an event
for each interested registration, which could potentially generate a large number of events. If an
extremely large number of events are raised, potentially some of them may not be able to be delivered
due to limitations on the message queue.

Because event notification is tightly bound to interface languages, following are separate event
notification sections, for C and C++ .

Current event notification status

You can use the dbtool utility to display current event notification status information. You can see the
following information:

• Event notification status, "active" or "not active".

• Event notification configuration information.

• Event message queue information, such as the number of events left in the event queue.

• A list of all event registration entries and their status, "active" or "not active".

333

VERSANT Database Fundamentals Manual

For more information, see the dbtool reference in the "Database Utilities" chapter of your VERSANT
Database Administration Manual.

334

VERSANT Database Fundamentals Manual

Event Notification for C and C++

Event Notification Overview for C and C++
A database produces event messages and puts them on an event message queue, where they are stored.
Applications access messages, using an event delivery daemon. The flow of messages is:
db --server process--> msg queue --delivery daemon--> application

There is one event message queue and one event delivery daemon per database. Both the event message
queue and the event delivery daemon must be running for you to use event notification functions.

Event Notification Procedures for C and C++
To use event notification, complete the following steps.

1. Create event notification entry in the database profile file.

For each database on which you want to use event notification, open the database profile file
profile.be and create an event delivery daemon entry.

The event delivery daemon entry can have either of the following two formats:
event_daemon code_path

or
event_daemon MANUAL

In the first form, code_path is the full path name of object code that will start an event delivery daemon.
You must separately write this code, which is operating system specific. This code must be on the same
machine as the database.

In the second form, you must manually start an event delivery daemon after the database starts. If there is
no event_daemon entry, "event_daemon MANUAL" is the default.

335

VERSANT Database Fundamentals Manual

2. Start event notification daemon.

You must start the event daemon before doing anything else. Otherwise, event defining requests from an
application will remain pending until the daemon is started.

When a database starts, it will configure itself per the parameters in the file profile.be.

If there is an event_daemon entry in profile.be, the server process will create an event message
queue, if one does not already exist.

Automatic startup

If the database process sees the entry event_daemon code_path, the server process will invoke the
code located at code_path, which will start an event delivery daemon.

Manual startup

If the database process see the entry event_daemon MANUAL, no event delivery daemon will be started
and you must manually start an event delivery daemon before proceeding.

Null startup

If the database process sees no event_daemon entry in profile.be, manual startup behavior occurs.

3. Enable event notification for a database.

Follow normal procedures to start a session and then connect to the database on which you want to
enable event notification.

Next, enable event notification by running the o_initen() function or initen() method with the
O_EV_DAEMON option. This will identify you to the database server process as the owner of the event
delivery daemon and enable event notification.

After event notification has been enabled, the database will create a database event message queue, if it
does not already exist. Then the event daemon will issue a request to open the database message queue
to get a handle, and start to read requests. The database will immediately begin monitoring itself for
registered events and, as appropriate, produce messages and put them on the event message queue. At
this point, all event notification functions are available both for you and for all other users. This means
that you and others can now register events, read events, raise events, and so on.

Note that it is the responsibility of an application to activate event notification. You must take care that
your application waits for notification from the event daemon that it has received a handle to the database
message queue before proceeding to register, read, and raise events. Otherwise, the application may
attempt to perform actions before event notification has been activated. Alternately, you can build in

336

VERSANT Database Fundamentals Manual

logic that causes the application to retry its action until event notification has been activated.

4. Register event.

Register the events that you wish to monitor with o_defineevent() or defineevent().

5. Get events.

Read events from the event message queue with o_readevent() or readevent().

6. Release event notification system.

When you are finished with event notification, your application should disable its event notifications with
o_disableevent() or disableevent() and optionally disable event notification for the database with
o_initen() or initen() and kill the event notification daemon.

Event Notification Actions for C and C++
• Disable event notification for a database

• Enable event notification for a database

• Initialize event notification for a database

• Remove event message queue for a database

c o_initen()
c++ initen()

Depending on options, the o_initen() and initen() routines can:

• Enable event notification for a database.
• Disable event notification for a database.
• Reactivate event notification after it has been disabled.
• Remove the event message queue.
Disable event notification for a registered event
Temporarily disable monitoring on previously registered events.
c o_disableevent()
c++ disableevent()

337

VERSANT Database Fundamentals Manual

Drop event notification registration for a registered event
Drop monitoring on previously registered events.
c o_dropevent()
c++ dropevent()

Enable event registration for a registered event
Reactivate monitoring on events previously registered then disabled.
c o_enableevent()
c++ enableevent()

Get event notification message
Retrieve an event from the event message queue.
c o_readevent()
c++ readevent()

Get event notification status
Get event notification status.
c o_getevstatus()
c++ getevstatus()

Raise event to daemon
Send a message to the event delivery daemon.

This function allows you to send an event message to the event delivery daemon:

• Without registering,
• Without specifying a target object, and
• Without waiting for a commit for your message to be processed.
c o_sendeventtodaemon()
c++ sendeventtodaemon()

338

to read your messages with o_readevent() or readevent(). You can then use the handle. c o_raiseevent() c++ raiseevent() Register event Register for an application the objects and events to be monitored by a database. then o_initen() or initen() must be invoked within a database session by the dba user who created the database. you must use this method to receive a handle to your event message queue. c o_defineevent() c++ defineevent() Set event options Set event notification options. 339 . VERSANT Database Fundamentals Manual Raise event on an object Explicitly raise an event on an object. you will receive an event message whenever a specified event occurs to a specified object.a. If you have linked your application with the single process library libosc. returned to eq_handle. Afterwards. Before you can access your event messages. c o_eventsetoptions() c++ eventsetoptions() Clear event notification options. c o_eventclearoptions() c++ eventclearoptions() Start work on event message queue Start an event message daemon and get a handle to the database event message queue. the o_initen() function or initen() method initializes and enables event notification and identifies you as the owner of the event delivery daemon. c o_openeventqueue() c++ openeventqueue() Usage Notes for C and C++ Event notification initialization When invoked with the O_EV_DAEMON option.

Only after all applications monitoring an object drop their interests or terminate does a database stop 340 . when the database starts a new daemon. at the time when event is raised or when the originating transaction of the event commits. However. You can more precisely specify objects to be monitored by specifying a predicate. After the event delivery daemon has been disabled.VERSANT Database Fundamentals Manual When invoked. must have called o_initen() or initen(). rather than waiting until the next commit. which will narrow the group of instances to which a raised event can apply. the event notification daemon must be running and some application. When the database is next started and a new daemon is created. When the database restarts. they will act at the next transaction commit. The events of interest defines a subset of all events that can happen to the target objects. Otherwise. The o_defineevent() function and defineevent() method register objects and events to be monitored. If you want to suspend the operation of the event message daemon. the database cleanup process will attempt to bring up another copy of the daemon. an application must register with a database its desire to monitor particular objects and events. If a machine crashes because of an event such as a power failure. Before you can make a registration. it will not restart event monitoring until you again invoke o_initen() or initen() with the O_EV_DAEMON option. The objects to be monitored can be either class objects or instance objects. the event message queue and all messages in it will be lost. a new event message queue will automatically be created. If you have used VERSANT mechanisms to start an event delivery daemon and it terminates while a database is still running. but the event message queue will remain. you can call o_initen() or initen() with the O_EV_DISABLE option. If a database is shut down. the daemon will immediately pick up any messages left in the message queue when the database stopped. so that you can see changes before making a commit. Only a raised event falling into this subset will send an event message. Event notification registration To receive event messages. all event notification functions (except o_initen() and initen() using the O_EV_ENABLE option and o_dropevent() and dropevent()) will receive an error. o_initen() and initen() act immediately if the application is using the one process model. the event delivery daemon will be terminated. but to reactivate event notification you must perform the normal startup procedures as noted above. The server process for the specified database will begin event monitoring as soon as an application makes a registration. not necessarily your application. A registration can optionally specify when to evaluate this predicate. after you perform the normal startup procedure. You make registrations at any time during a session.

In this case. which means that it is available to all applications connected to that database. you can suspend event monitoring with o_disableevent() or disableevent(). 99. [98. At any time during a session. with the first part of each pair representing the lower range and the second part representing the upper range of the event numbers for the events to be monitored. 20]. Shutting the database down cancels all event registrations. The "define event" routines take effect immediately without waiting till the end of the transaction. as only logical object identifiers (their loids) are sent to a database. there is an expectation that the frequency of occurrences of events 10 thru 20 will be higher than that of event 4. The registration will be saved in shared memory on the machine containing the database and will be accessible by all server processes on that machine. or terminate monitoring with o_dropevent() or dropevent(). monitoring for the application or database will be terminated.4]. Information about event registrations is kept in shared memory managed by the database.99]} covers event numbers 4. VERSANT Database Fundamentals Manual monitoring the object. The order in which the pairs of event number are specified in the events parameter determines the order in which events are evaluated. Event notification parameters The contents of the events parameter in o_defineevent() or defineevent() determines the events monitored. The objects you want to monitor need not be in your application object memory cache. [4. which is defined by the operating system on which the database resides. deactivating. will be notified of an event on a registered object if the event falls into the event ranges of interest and the predicate is evaluated to TRUE. If the queue is full when an event message is generated. The events parameter must be a vstr containing pairs of event numbers. but this practice is 341 . which means that it can be used in an optimistic locking environment. defined in definer_info. You can invoke the "define event" routines more than once with identical parameters. If your application or the database terminates abnormally. The event notification recipients. For example. or re-activating has no impact on locks. Use of event notification does not require that locking be turned on. Event registering. and 10 thru 20. which in turn is expected to occur more often than events 98 and 99. 98. reactivate monitoring with o_enableevent() or enableevent(). releasing. it will be lost. This means that performance will be better if events with a higher frequency of occurrence are kept in front of the list. Database event message queues have a maximum size. a vstr of {[10. If you are interested in just one event. use the same number for both parts of the pair.

modification of an instance of a class object 0xE0000004 O_EV_CLS_INST_CREATED. 0x80000002 O_EV_END_EVENT. disable. 342 .VERSANT Database Fundamentals Manual not recommended. an event is added immediately if it is raised with an explicit use of the "send event to daemon routine. However. In an events parameter. The time a system event is raised is determined by the system. or deletion to any instances under a class object. 0xC0000000 O_EV_OBJ_DELETED. but to drop. the start of an event. If you double register. on each qualified event you will receive only one event message. deletion of an object 0xC0000001 O_EV_OBJ_MODIFIED. System events include status changes to a database such as modification and deletion of instances. you can specify the following numbers recognized by VERSANT." either o_sendeventtodaemon() or sendeventtodaemon(). Another category of system events are tags that indicate the start and end of events raised from a database within a transaction. System events A system event is an event pre-defined by VERSANT. Otherwise. Events are added to the database event message queue when the transaction raising the event is committed. creation. modification of an object 0xE0000002 O_EV_CLS_INST_DELETED. or a schema evolution of a class object. deletion of an instance of a class object 0xE0000003 O_EV_CLS_INST_MODIFIED. creation of an instance of a class object 0x80000001 O_EV_BEGIN_EVENT. all events related to the transaction will be discarded. modification. or enable the registration you will need to invoke the appropriate function twice. the end of an event.

you will receive a message for each deleted instance. O_EV_BEGIN_EVENT Send a message when an event starts. This event will be applied to both instance and class objects contained in the objects parameter. O_EV_OBJ_DELETED Send a message when an object is deleted. O_EV_CLS_INST_DELETED Send a message when an instance of a class is deleted. If you delete all instances of a class. the server for the originating transaction trying to drop all instances could conceivably run short of memory trying to store all deferred events for each deleted instance. a message is sent when it is deleted. Also. a message is sent when it is modified. This event will be applied to both instance and class objects contained in the objects parameter. This event will be applied to both instance and class objects contained in the objects parameter. For a class object. which could be overwhelming if the class contained many instances. For an instance object. For a class object. such as when an attribute is added or dropped or when a subclass is dropped. This event is similar to an object modified event. a message is sent when schema evolution occurs. a message is sent when the class is dropped. This event will be applied only to class objects contained in the objects parameter. This event will be applied only to class objects contained in the objects parameter. except that a message is sent only on deletion. This event will be applied to both instance and class objects contained in the objects parameter. 343 . This event will be applied only to class objects contained in the objects parameter. O_EV_CLS_INST_CREATED Send a message when an instance of a class is created. For an instance object. O_EV_CLS_INST_MODIFIED Send a message when an instance of a class is modified. as with o_dropclass() or o_dropinsts(). O_EV_END_EVENT Send a message when an event ends. VERSANT Database Fundamentals Manual The following explains these system events. O_EV_OBJ_MODIFIED Send a message when an object is updated.

multiple operations may be applied to the same object and cause multiple events to occur. object modified class instance created Both messages. What happens depends on whether the object is an instance object or a class object. class instance created object deleted One object deleted message. the following shows the net effect of two system events on the same object. and in the following the word "object" refers to a class object. class instance created class instance modified Both messages. class instance created class instance deleted None. object modified object deleted One object deleted message. class instance modified object deleted One object deleted message. First event Second event Message sent object modified object modified One obj modified message. For instance objects. Only relevant sequences are shown. Only relevant sequences are shown. class instance modified object modified Both messages. class instance deleted object modified Both messages. object modified class instance deleted Both messages. object modified object deleted One obj deleted message. object modified class instance modified Both messages.VERSANT Database Fundamentals Manual Multiple operations In a transaction. class instance modified class instance modified One class instance modified message class instance modified class instance deleted One class instance deleted message. First event Second event Message(s) sent object modified object modified One object modified message. the following shows the net effect of two system events on the same object. class instance deleted object deleted One object deleted message. For class objects. class instance created object modified Both messages. 344 .

one per database. by default the following will happen. when registered to different objects. the database server will write the event message to the file LOGFILE in the database directory. the server first evaluates each registration for the object and determines whether to evaluate the predicate immediately or upon commit. Defined events are known only to the application. the server process will monitor registered objects. and the evaluation of the predicate. you can define an event to occur when a routine affecting an object completes. Messages for an application remain in the queue until the application requests its messages with a "get event message" routine. (There is no "rollback" of message delivery once a message in a string of messages has been delivered. an event may have different meanings when applied to one object or another. You can register the same event to more than one object. For defined events. You can specify your own event number pairs using any non-negative number. is satisfactory. VERSANT Database Fundamentals Manual Defined Events A "defined event" is an event defined in an application. the event daemon will retry sending it three times. event has occurred on a registed object is of interest. After three tries. For example. When an event occurs. 0 through 2147483647. If the message queue runs out of space and a message is sent to it. o_readevent() or readevent(). Event Notification Timing For system events. It is bound to an object when you register it with o_defineevent() or defineevent(). For example. A defined event may or may not involve changes to an object. This queue is automatically created by VERSANT when the database is started. However. Regardless of when evaluation is performed. an event on class C1 could mean a temperature increase. the application process will monitor registered objects and notify the server when a defined event on an object occurs. 345 . if any. and VERSANT does not attempt to interpret defined events. A defined event is identified by a number. while an event on class C2 could mean a temperature drop. Event Notification Message Queue Notifications are stored in an operating system message queue. a registration qualifies a raised event only if the registration is active. Each time an undeliverable message is encountered. All event messages generated in the transaction that have already been delivered are not affected.) 2. 1.

The error EV_EVENT_LOST is returned. systemwide. 2. it does not change database format or affect object compatibility. you must configure a new UNIX kernel.h. it is unnecessary to rollback the transaction upon receiving this error. the following will happen when the message queue runs out of space: 1. If the event message queue clears during the time the event message queue is delivering a string of messages. the following parameters are used to configure a message queue: MSGTQL The maximum number of messages. systemwide. but the database server will try to deliver the message only once. To improve performance when the event message queue runs out of space. To restore default behavior. MSGMAX The size of the largest message that can be stored. 4. All other undeliverable event messages generated by the transaction are discarded. Because this event notification scheme operates at run time. All deliverable event messages generated by the transaction are delivered. all subsequent messages will be delivered as usual. If you use O_EV_NO_RETRY. you can invoke o_initen() or initen() again with the option O_EV_RETRY_SEND. The first event undeliverable message generated by the transaction is written to the file LOGFILE in the database directory. 3. On UNIX platforms.VERSANT Database Fundamentals Manual 3. Values for these UNIX parameters are defined in the file sys/msg. 346 . you can override the default behavior by invoking o_initen() or initen() with the O_EV_NO_RETRY option. As events are delivered only when a transaction is committed. MSGMNB The maximum size in bytes of a particular queue for a particular database. Long transaction event notification The event notification scheme for long transactions that was used in previous releases (and which used e-mail for notification) can still be used alongside this scheme for short transactions. MSGMNI The maximum number of message queues. To change a value.

cxx /* * Daemon.h> #include "Alarm. // // Misc // friend ostream &operator<<(ostream &o. VERSANT Database Fundamentals Manual Event Notification Example in C++ Following is an example of using event notification with C++/VERSANT. Alarm &e).h> #include <iostream.h" #define AUX_LEN 100 // 347 . Alarm. }. // // Accessors // int getLevel() {return level.h> class Alarm: public PObject { private: int level. ~Alarm() {}.h /* * Alarm.cxx * * A sample event dispatching daemon process. #endif Daemon. */ #include <stdlib.h> #include <unistd.h * * Alarm class declaration.h> #include <strstream.h> #include <signal. */ #ifndef ALARM_H #define ALARM_H #include <cxxcls/pobject.}. public: // // Constructors & destructors // Alarm(int j=0):level(j) {}.

// // Signal only not for me // while(TRUE) { dom->readevent(eventQueue. dom = new PDOM.VERSANT Database Fundamentals Manual // This is a sample of event delivery daemon for Event Notification // int main() { char *DBNAME = getenv("DBNAME"). lengthEvent. */ #include "Element. receivedEvent = (o_event_msg *) malloc(lengthEvent). int definerPid. int myPid = getpid().SIGUSR2). if (DBNAME == NULL) { cout << "DBNAME environment variable not set" << endl. // // Allocate buffers for received events // lengthEvent = sizeof(struct o_event_msg) + AUX_LEN. 0. o_event_msg *receivedEvent = 0. NULL). exit(1). 0). definerPid = atoi((char *)O_EV_DEFINER_INFO(receivedEvent)). receivedEvent.h" LinkVstr<Element> Element::getBad(int aLevel) { PAttribute alarmAttr = PAttribute("Element::history\tAlarm::level"). O_EV_DAEMON | O_EV_ENABLE. dom->openeventqueue(DBNAME. dom->beginsession(DBNAME. 0). } } Element. } o_ptr eventQueue. int lengthEvent = 0.cxx /* * Element. 348 . if (definerPid != myPid) kill(definerPid. // // Specify that I am an event delivery daemon // dom->initen(DBNAME.cxx * * Implementation of Element class. &eventQueue).

select( NULL.address. VERSANT Database Fundamentals Manual LinkVstr<Element> matchingObj = PClassObject<Element>::Object(). return matchingObj.select( NULL. PPredTerm predicate = (alarmAttr < (o_4b)aLevel). } ostream &operator<<(ostream &o.h> class Alarm. FALSE.h * * Element class declaration. // predicate.set_flags(O_ALL_PATHS|O_EMPTY_TRUE). class Element: public PObject 349 . } void Element::addHistory(Alarm *a) { dirty().h /* * Element. return matchingObj. FALSE. Element &e) { return o << e. history. } Element.h> #include <iomanip.h> #include <cxxcls/pobject. */ #ifndef ELEMENT_H #define ELEMENT_H #include <iostream. predicate ). alarmAttr >= (o_4b)aLevel ).h> #include <cxxcls/pstring.name << '@' << e.add(a). LinkVstr<Element> matchingObj = PClassObject<Element>::Object(). // // None of them have received an alarm of level2 // or no alarm at all. } LinkVstr<Element> Element::getGood(int aLevel) { PAttribute alarmAttr = PAttribute("Element::history\tAlarm::level").

// // Mutators // void addHistory(Alarm *a) .h" #include "Element. dom->beginsession(DBNAME. if (DBNAME == NULL) { cout << "DBNAME environment variable not set" << endl. static LinkVstr<Element> getBad(int aLevel). public: // // Constructors & destructors // Element(char *aName.h" int main() { char *DBNAME = getenv("DBNAME").h> #include <iomanip. exit(1). }. Element &e).h> #include "Alarm. */ #include <iostream. NULL). 350 . #endif MakeAlarm.int anAddr): name(aName). // // Queries // static LinkVstr<Element> getGood(int aLevel). // // Misc // friend ostream &operator<<(ostream &o.address(anAddr) {} ~Element() {}.cxx * * Modify Element class instances to raise event. LinkVstr<Alarm> history.VERSANT Database Fundamentals Manual { private: PString name. } // // Start a session on DBNAME // dom = new PDOM. int address.cxx /* * MakeAlarm.

&anAddr).size() == 0) { cout << "Bad input" << endl << flush. scanf("%s". } # link for interpretation with ObjectCenter # Notice: you must either run "getocinit" and "source init" # or you must add steps here to load Versant libraries. printf("Continue:"). } while (goOn == 1) . // // Get the equipment // LinkVstr<Element> elements = PClassObject<Element>::Object(). dom->commit(). do { printf("Alarm level:"). } // // Create the Alarm and commit // elements[0]->addHistory(new( PClassObject<Alarm>::Pointer()) Alarm(aLevel)). printf("Element name:"). (PAttribute("Element::name") == anEl) && (PAttribute("Element::address") == (o_4b)anAddr) ). &aLevel). printf("Element address:"). # Otherwise you will get a long list of undefined symbols. if (elements. &goOn).anAddr. int goOn = 0. 351 . return -1. scanf("%i". char anEl[255]. FALSE.select( NULL. scanf("%i". return 0. // // Commit and end session // dom->endsession(). scanf("%i". VERSANT Database Fundamentals Manual // // Parameters for the alarm // int aLevel. anEl).

h> #include <stdlib. // // Define the event // 352 .h> #include <signal. loid regID. theEnd = FALSE. // // Start a session on DBNAME // dom = new PDOM. } int main() { signal(SIGUSR2.h> #include "Alarm. o_4b badObjIndex = -1.cxx * * Register and wait for events.cxx /* * Monitor. if (DBNAME == NULL) { cout << "DBNAME environment variable not set" << endl. dom->beginsession(DBNAME. char processID[PID_LEN]. "%i".h" #define PID_LEN 20 o_bool theEnd. int myPid = getpid(). // // Notification through signals. } Vstr<o_u4b> events. NULL).h> #include <iostream. int pidLen. exit(1).h> #include <unistd. theEnd = TRUE. LinkVstrAny classes. pidLen = strlen(processID) + 1. // static void sig_handler() { printf("BIP BIP BIP BIP BIP\n").(SIG_PF)sig_handler). char *DBNAME = getenv("DBNAME"). sprintf(processID. */ #include <stdio.VERSANT Database Fundamentals Manual # compile Monitor. myPid).

Element *e3 = new(pe) Element("WACSEM". // // Only reached after the signal // dom->endsession(). // // Wait for the SIGUSR2 // printf("I am doing something very important\n").cxx /* * Populate. VERSANT Database Fundamentals Manual classes. EV_EVAL_AT_COMMIT.h" int main() { char *DBNAME = getenv("DBNAME").h> #include <iomanip. 300). Element *e2 = new(pe) Element("FETEX-150".add(O_EV_CLS_INST_MODIFIED). (o_u1b *)processID. 353 . exit(1). pidLen. } // // Start a session on DBNAME // dom=new PDOM. &regID. DBNAME)). classes.add(dom->locateclass("Element". dom->defineevent(DBNAME. 200). PClass *pe = PClassObject<Element>::Pointer(). } Populate. if (DBNAME == NULL) { cout << "DBNAME environment variable not set" << endl. pred. events. events. NOLOCK. */ #include <iostream.h> #include "Alarm.add(O_EV_CLS_INST_MODIFIED). // // Create 3 elements // Element *e1 = new(pe) Element("FETEX-150". dom->beginsession(DBNAME. PPredicate pred= (PAttribute("Element::history\tAlarm::level") == (o_4b)2) && (PAttribute("Element::name") == "WACSEM").h" #include "Element. 100). NULL). events. PClass *pa = PClassObject<Alarm>::Pointer(). &badObjIndex).cxx * * Create instances of Element class. while(!theEnd) .

VERSANT Database Fundamentals Manual // // Commit and end session // dom->endsession().h" int main(int argc. char *argv[]) { char *DBNAME = getenv("DBNAME").size().h" #include "Element. if (DBNAME == NULL) { cout << "DBNAME environment variable not set" << endl.h> #include "Alarm. exit(2). exit(1).h> #include <iomanip. 354 . i++) cout << *bads[i] << endl << flush.release(). // // Get the bad equipments // LinkVstr<Element> bads = Element::getBad(aLevel).size(). } if (argc < 2) { cout << "Usage: Statistics <level>" << endl. } Statistics. NULL).cxx * * Gather simple statistics about Element objects. for (i = 0. i++) cout << *goods[i] << endl << flush.cxx /* * Statistics. dom->beginsession(DBNAME. // // Get the good equipments // LinkVstr<Element> goods = Element::getGood(aLevel). int aLevel = atoi(argv[1]). cout << "Good equipments" << endl << flush. i < goods. i < bads. for (int i = 0. return 0. */ #include <iostream. } // // Start a session on DBNAME // dom = new PDOM. bads. cout << "Bad equipments" << endl << flush.

For user events. However. but this practice is not recommended. or a schema evolution of a class object. This means that performance will be better if events with a higher frequency of occurrence are kept in front of the list. 20]. For example. or enable the registration you will need to invoke the appropriate function twice. 98. there is an expectation that the frequency of occurrences of events 10 thru 20 will be higher than that of event 4. return 0. defined in another parameter. } Event notification parameters The parameters supplied to a registerInterestsAbout: method determine the events monitored. // // Commit and end session // dom->endsession(). Events are added to the database event message queue when the transaction raising the event is committed.4]. an array of {[10. In this case. You can invoke registerInterestsAbout: more than once with identical parameters. If you double register. The order in which the pairs of event number are specified in the events parameter determines the order in which events are evaluated. VERSANT Database Fundamentals Manual goods. and 10 thru 20. System events include status changes to a database such as modification and deletion of instances. disable. If you are interested in just one event. use the same number for both parts of the pair. with the first part of each pair representing the lower range and the second part representing the upper range of the event numbers for the events to be monitored. The registerInterestsAbout: method takes effect immediately without waiting till the end of the transaction. The time a system event is raised is determined by the system. 99. Another category of system events are tags that indicate the start and end of events raised from a database within a transaction. modification.99]} covers event numbers 4. The registration will be saved in shared memory on the machine containing the database and will be accessible by all server processes on that machine. on each qualified event you will receive only one event message. the events parameter must be an array containing pairs of event numbers.release(). Otherwise. will be notified of an event on a registered object if the event falls into the event ranges of interest and the predicate is evaluated to true. all events related to the transaction will be discarded. creation. [98. an event is added immediately if it 355 . which in turn is expected to occur more often than events 98 and 99. The event notification recipients. [4. System events A system event is an event pre-defined by VERSANT. or deletion to any instances under a class object. but to drop.

VERSANT Database Fundamentals Manual is raised with an explicit use of the "send event to daemon routine. This event will be applied only to class objects contained in the objects parameter. This event is similar to an object modified event. #O_EV_OBJ_DELETED Send a message when an object is deleted. a message is sent when it is deleted. #O_EV_CLS_INST_MODIFIED Send a message when an instance of a class is modified. a message is sent when schema evolution occurs. For a class object. This event will be applied to both instance and class objects contained in the objects parameter. For an instance object. This event will be applied only to class objects contained in the objects parameter. such as when an attribute is added or dropped or when a subclass is dropped. For a class object. #O_EV_CLS_INST_DELETED Send a message when an instance of a class is deleted. If you delete all instances of a class. as with o_dropclass() or o_dropinsts(). #O_EV_OBJ_MODIFIED Send a message when an object is updated. For an instance object. a message is sent when it is modified. This event will be applied only to class objects contained in the objects parameter. except that a message is sent only on deletion. This event will be applied to both instance and class objects contained in the objects parameter. the server for the originating transaction trying to drop all instances could conceivably run short of memory trying to store all deferred events for each deleted instance. you will receive a message for each deleted instance. #O_EV_CLS_INST_CREATED Send a message when an instance of a class is created. Also. which could be overwhelming if the class contained many instances." In the events parameter. you can specify the following symbols for system events recognized by VERSANT. 356 . a message is sent when the class is dropped.

object modified object deleted One object deleted message. the following shows the net effect of two system events on the same object. object modified class instance created Both messages. VERSANT Database Fundamentals Manual #O_EV_BEGIN_EVENT Send a message when an event starts. object modified class instance deleted Both messages. object modified class instance modified Both messages. Only relevant sequences are shown. class instance created class instance deleted None. First event Second event Message(s) sent object modified object modified One object modified message. This event will be applied to both instance and class objects contained in the objects parameter. and in the following the word "object" refers to a class object. class instance modified object modified Both messages. multiple operations may be applied to the same object and cause multiple events to occur. For class objects. class instance modified object deleted One object deleted message. the following shows the net effect of two system events on the same object. First event Second event Message sent object modified object modified One object modified message. Multiple operations In a transaction. For instance objects. What happens depends on whether the object is an instance object or a class object. class instance created object modified Both messages. This event will be applied to both instance and class objects contained in the objects parameter. object modified object deleted One object deleted message. class instance created class instance modified Both messages. #O_EV_END_EVENT Send a message when an event ends. class instance modified class instance modified One class instance 357 . Only relevant sequences are shown. class instance created object deleted One object deleted message.

User events are specified a SmallInteger. when registered to different objects. SmallInteger values 0-9 are reserved for configuring the event notification system: 0 — for requesting a connection to the event daemon 1 — for releasing ipc server in the event daemon Image 2 — for terminating the event daemon 3-9 — reserved You can specify your own event number pairs using any non-negative number. When an event occurs. an event on class C1 could mean a temperature increase. an event may have different meanings when applied to one object or another. 358 . the server first evaluates each registration for the object and determines whether to evaluate the predicate immediately or upon commit.VERSANT Database Fundamentals Manual First event Second event Message(s) sent modified message. class instance deleted object modified Both messages. For example.1 = 536870911. A defined event may or may not involve changes to an object. 10 through 2^29 . you can define an event to occur when a method affecting an object completes. You can register the same event to more than one object. For example. However. while an event on class C2 could mean a temperature drop. the server process will monitor registered objects. Defined Events A "defined event" or "user event" is an event defined in an application. and VERSANT does not attempt to interpret defined events. Defined events are known only to the application. the application process will monitor registered objects and notify the server when a defined event on an object occurs. For defined events. class instance deleted object deleted One object deleted message. class instance modified class instance deleted One class instance deleted message. It is bound to an object when you register it with registerInterestsAbout:. Event Notification Timing For system events.

and the evaluation of the predicate. an application must request its messages with the readAndSendEvents method in VEventDaemon. MSGMNB The maximum size in bytes of a particular queue for a particular database. To read a message. To change a value.h. This queue is automatically created by VERSANT when the database is started. 359 . notifications are stored in an operating system message queue. Because this event notification scheme operates at run time. MSGMNI The maximum number of message queues. one per database. Values for these UNIX parameters are defined in the file sys/msg. messages are lost until space is again available. MSGMAX The size of the largest message that can be stored. a registration qualifies a raised event only if the registration is active. systemwide. it does not change database format or affect object compatibility. the following parameters are used to configure a message queue: MSGTQL The maximum number of messages. If a message queue overflows available space. systemwide. if any. On UNIX platforms. you must configure a new UNIX kernel. For each application. is satisfactory. VERSANT Database Fundamentals Manual Regardless of when evaluation is performed. event has occurred on a registered object is of interest. Long transaction event notification The event notification scheme for long transactions that was used in previous releases (and which used e-mail for notification) can still be used alongside this scheme for short transactions.

STAT_DB_EV_SYS_RAISED The number of system events raised (but not necessarily delivered). 360 .VERSANT Database Fundamentals Manual Event Notification Performance Statistics The following statistics related to event notification can be collected per database connection. STAT_DB_EV_SYS_DELIVERED The number of system events delivered. not including the system events O_EV_BEGIN_EVENT and O_EV_END_EVENT. STAT_DB_EV_USER_RAISED The number of user defined events raised (but not necessarily delivered). STAT_BE_EV_SYS_RAISED The number of system events raised (but not necessarily delivered). not including the system events O_EV_BEGIN_EVENT and O_EV_END_EVENT. STAT_BE_EV_DEFINED The number of invocations of registerInterestsAbout:. STAT_BE_EV_SYS_DELIVERED The number of system events delivered. STAT_BE_EV_USER_DELIVERED The number of user defined events delivered. STAT_DB_EV_USER_DELIVERED The number of user defined events delivered. STAT_BE_EV_USER_RAISED The number of user defined events raised (but not necessarily delivered). The following statistics can be collected per database: STAT_DB_DISK_FREE Bytes of storage space available for any use (space in free extents) STAT_DB_DISK_RESERVED Bytes of storage space reserved by classes (space in allocated extents and free bytes in data pages) STAT_DB_EV_DEFINED The number of invocations of registerInterestsAbout:. See the "Statistics Collection" chapter for information on statistics collection.

While synchronous database replication is useful for achieving fault tolerance and data safety. Create replica utility Create a replica database that is a copy of a source database using a command line utility. asynchronous replication is useful for achieving performance in a distributed environment. you may want to create your own scheme for asynchronous database replication using event notification mechanisms. suppose that you have numerous regional offices accessing a common database. UNIX createreplica Win creatrep Copy objects Copy objects to a target database without changing their logical object identifiers. VERSANT Database Fundamentals Manual Asynchronous Database Replication Asynchronous Database Replication Concepts VERSANT provides synchronous database replication and roll forward archiving utilities and interface methods. If you used asynchronous replication to maintain ten replicated local databases. Asynchronous Database Replication Actions When you create an asynchronous database application. The replica database name and database identifier must not exist on the replicated system. Alternately. the following VERSANT mechanisms are useful. In some situations. For example. this approach would dramatically improve performance. users in each regional office would be making local database connections and the number of users per database would be reduced. c o_moveobjs() c++ migrateobjs() Set database for vstr read operations c o_setobjsdb() c++ setobjsdb() Asynchronous Database Replication Procedures A typical approach to asynchronous database replication is to first create a replica database and then maintain 361 .

and provide for cases when the replica database is down. it is also possible to write a program which propagates a batch of changes all at once. If you are dealing with such a situation. C++/VERSANT Example Following is one way to perform asynchronous database replication using event notification and object migration routines. 2. Instead of using event notification to propagate changes as they happen. but for others it will. but also as an object replication server. maintenance will be done by setting up a process for each database which uses event notification to watch for any changes. Following are typical steps involved in performing asynchronous database replication. rather than as the only way asynchronous database replication can be done. say. One disadvantage of asynchronous replication is that there is a lag time between when a change is made in one database and when it becomes visible in the other databases. The central element in the following approach is the event notification daemon process. if you have. the disadvantages of asynchronous replication will not matter. you might want to refer to the chapter on "Optimistic Locking" which explains how you can create and use timestamps to coordinate updates to unlocked objects. It is provided as an example. register events. Utility names are for UNIX. For example. The code for the following example is for C++/VERSANT. Asynchronous Database Replication. and run a program which copies new objects back to the master database. See also the chapter "Create a Database" and the references to the setdbid and createdb utilities in the VERSANT Database Administration Manual. Because of the great flexibility available. so the same osc-dbid database system identifier file should be used for all databases involved. When a change is made. plug into the network. a thousand salesmen carrying around copies of a master database on notebook computers. there is a window where the databases are inconsistent.VERSANT Database Fundamentals Manual it with a combination of event notification and object copying methods and procedures. For some applications. at the end of the day they could return to their offices. it propagates it to the other databases using routines such as o_moveobjs() or copyAllFromDB:. It acts not only as an event dispatcher. 1. 362 . This can lead to a situation where different users at different times make conflicting updates to an object without knowing that it has been changed by another user. Create a replica database with the createdb utility. Follow normal event notification procedures to initialize the environment. As a result. The database name and the database identifier must be unique to the network system. it is often possible to come up with workarounds for dealing with the inherent problems. Typically.

You can use these routines to implement periodic synchronization using either a push or a pull model. Retrieve the logical object identifier for the changed object from the o_event_msg struct of the received event. 4. O_MV_SYNC). rather than one at a time.. dummy.add(object).. objvstr. Fetch an event with readevent(). VERSANT Database Fundamentals Manual 3. So the check is // recommended. // fetch an event loid objId = event->obj_event_raised. // get loid LinkAny object. or copy objects only if they met some condition. // source db DBNAME2. try { ::dom->migrateobjs( objvstr. the system will generate 'begin-event' and // 'end-event' events whose obj_event_raised fields // will be filled with all 0's. either the event notification daemon or any other application can copy objects to the replication database. 5. For example: o_event_msg event. ::dom->commit().). ::dom->readevent(. In a real application. if ((object = ::dom->getcod(objId)) != NULL) { // Remember. // replication db &dummy. } catch (PError &err) { // migratation failed } end_try. LinkVstrAny objvstr. // migratation succeeded Depending upon your needs. 363 . Migrate the changed object to the replication database. DBNAME1. you might also want to copy objects in groups.

while(TRUE) { try { dom->readevent(... 0. if there is heavy event traffic.. the event queue may overflow while the daemon is sleeping. return 1. you might also want to notify client applications. // Return 1 if server is alive. . } catch (PError &err) { // Ping server here. O_EV_IPC_NOWAIT). It is possible to put the daemon to sleep for a while before pinging the server. ping_server(). int ping_server() { try { dom-> sendeventtodaemon(DB. } catch (PError &err) { return 0. } You might want the daemon to utilize a busy-waiting event handling loop since the option O_EV_IPC_NOWAIT is specified.. // Process/dispatch event here. } end_try. } end_try. NULL). When the server comes back. PING_EVENT. 0. Following is code that pings the database server: #define PING_EVENT 9999 #define DB "mydb" // Ping if the database server still alive. If the server goes down.VERSANT Database Fundamentals Manual Following is code that uses a loop to read events.. However. NULL. continue. 364 . the daemon will need to re-initialize the event notification environment and possibly notify client applications. } The daemon should ignore these ping events in its event loop.

...................................................................................................... 366 Roll Forward Management ............................................... VERSANT Database Fundamentals Manual Chapter 18: Roll Forward Archiving Roll Forward Concepts ........................................... 369 Roll Forward Procedures ....................... 370 365 ................ 367 Roll Forward Usage Rules....................................................................................................................................................................................................................

you can always restore to a previous. When the crashed database comes back. but you will lose the last committed transaction unless you are using roll forwarding or some form of database replication. VERSANT will continue to use the remaining database. For more information about synchronous database replication. then you also probably want to use roll forward archiving to a local tape or disk drive.VERSANT Database Fundamentals Manual Roll Forward Concepts If a hard disk crashes. If performance is an issue. Synchronous database replication If continuous operation is your first priority. because this avoids network traffic without compromising the ability to recover from a destroyed machine." Roll forward archiving If you want to keep a history of database states." With synchronous database replication. Following are the ways you can avoid losing the last committed transaction. In this case. historical state. VERSANT will automatically resynchronize it with the database that did not crash. the two databases kept in synchronization are called a "replica pair. then you probably want to use synchronous database replication in which VERSANT ensures that changes made to one database are also made to another database. Together. 366 . if a crash occurs to one database. you can restore to your last database backup. then you probably want to use a combination of database backups plus roll forward archiving. see the chapter "Fault Tolerant Server.

Or. VERSANT Database Fundamentals Manual Roll Forward Management To use roll forward. 4. roll forward may be interrupted by a tape device problem or network crash. as long as roll forwarding remains on. roll forward is not enabled. You can simultaneously backup multiple database logs to a single tape. Once a backup has been completed and roll forward has been enabled. After roll forward has been enabled. This is done using the command line vbackup utility. if desired. For example. so that there is a consistent state from which to roll forward. 367 . 1. There are many reasons why you may need to suspend roll forward. you can use the command line vbackup utility. you are always guaranteed that no log records will be discarded until they have been archived. turn on roll forward archiving. make an online backup. you can safely stop and start archiving temporarily. When a database is created. Temporarily stop roll forward archiving. using the command line vbackup utility. VERSANT will never throw away any log records which have not been archived. Once you have begun the online backup process. you may need to change a tape or use the roll forward tape drive to make an online backup. you do the following for each database on which you want to use roll forwarding. To backup a database and turn on roll forward. 2. or use multiple tape drives up to one per database. After roll forward archiving is turned on. Create a backup. 3. Turn on roll forward for the database. VERSANT will start archiving log records created since the last backup. Start roll forward archiving. An on-line backup must first be performed before roll forward can be enabled. by default. As long as roll forwarding is on. Once roll forward has been enabled.

VERSANT Database Fundamentals Manual Following are possible database states. 368 . The vbackup command options that will move you from one state to another are indicated in italics.

• If you turn off roll forward with the -off option to vbackup. and they will be discarded after a transaction ends. VERSANT will stop saving log records for archiving. • You do not have to suspend roll forward archiving to perform an online backup if you use a device for the backup that is different from the roll forward device. 369 . and then it is restarted. roll forward archiving. and restores on a database. • If a database goes down. you will have to restart roll forward archiving for that database. the sequence number will be checked to ensure that they are applied in the proper order. • Roll forward archiving has no effect on the normal writing of log files to a database. When you use the files to restore a database. you must be the dba user who created the database. If multiple databases are being archived to the same output media. and the database will shut down. • If you need to spread roll forward archiving over several tapes or devices. and there will be no reason to do a fresh incremental backup. nothing will be lost. but roll forward archiving for other databases will continue unless they are writing to the same output media. when it returns. either explicitly or by a process termination. the tape or device files will be marked with a sequence number. • If a database must be restored from backup and log archives. • If roll forward archiving is stopped. If the database runs out of space in its log files while roll forward archiving is suspended. you will get an error message. you should restart the roll forward archiving process as soon as possible. VERSANT Database Fundamentals Manual Roll Forward Usage Rules Following are usage rules related to roll forward archiving. • To perform backups. if roll forward archiving is stopped. • If a database goes down. only log archives created after the latest incremental backup are utilitized. However. roll forward archiving for that database will be stopped. a failure to any of the databases will cause log archiving to be stopped for all of the databases.

VERSANT Database Fundamentals Manual Roll Forward Procedures If you need to roll forward. the command prompt will not return and roll forward archiving will continue until you end the archiving process by closing the window or pressing <Enter> to exit vbackup. For example: vbackup -level 0 -device tape1 -rollforward -backup db1 db2 After the backup. For example: vbackup -level 1 -device tape1 -backup db1 db2 5. Resume roll forward archiving. Temporarily stop roll forward archiving to make an incremental backup. You will not have to invoke vbackup repeatedly: all restore steps are performed in a single invocation. the command prompt will return. During this time. 1. 2. you will be given the opportunity first to restore from your incremental backups and then from your roll forward archives. 4. use the vbackup command line utility to restore first from your last complete backup. Begin roll forward archiving. Temporarily stop roll forward archiving (by pressing <Enter>) to change a tape. just whatever is appropriate. For example: vbackup -device tape1 -log db1 db2 After this command. Typical Sequences of Events Archiving with one device — If you have only one tape drive or external drive. The backup does not have to be a full backup. After you have restored from your last complete backup. For example: vbackup -device tape1 -log db1 db2 370 . all log records will be saved until you start archiving again. Perform a level 0 backup and enable roll forwarding. a typical sequence of events is the following. 3.

the command prompt will return. 1. VERSANT Database Fundamentals Manual Archiving with multiple devices — Suppose that you have three tape drives and two databases. Open another window and begin roll forward archiving on database db2 using tape2: vbackup -device tape2 -log db2 4. 2. a typical sequence of events for databases db1 and db2 is the following. In this case. do the following. you will be asked for incremental backup and roll forward tapes as each step is completed. just whatever is appropriate. For example: vbackup -level 0 -device tape3 -rollforward -backup db1 db2 After the backup. If the databases were completely demolished. The backup does not have to be a full backup. Also. to restore after a crash. 1. Begin roll forward archiving on database db1 using tape1: vbackup -device tape1 -log db1 3. Insert the full backup tape and restore: vbackup -device tape3 -restore db1 db2 If additional tapes are needed for the full backup. In this case: makedb -g db1 makedb -g db2 2. Make an online incremental backup using tape3: vbackup -level 1 -device tape3 -backup db1 db2 Restoring after a crash — For the above examples. Perform a level 0 backup and enable roll forwarding. The user who recreates the databases must be the same user who created the original databases. first recreate the database directories and support files. 371 . you will be prompted for them.

.................................................................................................. 378 Failure Scenarios ....... 381 Mechanisms ..................................................................................................................................................................... 382 372 ................................................................................................................. 373 Procedures .......................................................................................................... 378 Restrictions...................... 374 Usage............................................................................................................................................................................................................................................................................................... 380 Database Backup and Restore in a Replicated Database Environment.. 380 Cautions........................................................................................................... 379 Network Partitioning Behavior................................................................................VERSANT Database Fundamentals Manual Chapter 19: Fault Tolerant Server Concepts ........................................................

VERSANT will automatically resynchronize the database with the database that did not crash and return to fully replicated operation." If a crash occurs to one database. see the chapter "Event Notification. Following are the steps required to perform synchronous database replication. The resynchronization will occur while the database that did not crash continues to be updated. you can also protect yourself against system failure with roll forward archiving and/or asynchronous database replication. the two databases kept in synchronization are called a "replica pair. Synchronous database replication mirrors the contents of one database in another in a predictable and orderly manner. For information about roll forward archiving." When you use synchronous database replication. 373 . see the chapter "Roll Forward Archiving." a software module that supplements standard VERSANT functionality by performing synchronous database replication. which protects against the unavailability of a database in the case of a system failure. VERSANT Database Fundamentals Manual Concepts This section describes the functionality of "VERSANT Fault Tolerant Server. VERSANT will continue to use the remaining database. This provides either local or geographically remote redundancy. Besides synchronous database replication." For information about asynchronous database replication. When the crashed database comes back.

2. You may want to create a new database directory for the database to be used for synchronous replication. Create a replica file. For each pair of primary and synchronous replication databases. you will probably want to locate the synchronous replication database on a machine different than the primary database. For each VERSANT installation that will use the primary database.VERSANT Database Fundamentals Manual Procedures 1. after the profile files have been created. VERSANT will automatically mirror the contents of the named databases each time a transaction commits. If you decide to use a new database directory for the synchronous replication database. use makedb normally to create the database directory and the database profile files. Optionally create a database directory. to use makedb to create database directories and profile files for a group database named replicadb: makedb -g replicadb See "Database Profiles" chapter in VERSANT Database Administration Manual for information on makedb and server process profiles. where node is the name of the machine containing the database: primarydb@node replicadb@node 374 . To maximize protection against system failure. Once a replica file and a replica database have been created. • The synchronous replication database must be a group database. Per normal practice. The replica file should be named replica and be placed in the VERSANT software root directory for that installation. you can edit the server process profile file to specify non-default values for such parameters as system and log volume sizes. create or edit a file that names the primary and synchronous replication databases. • The database that you will use for replication cannot exist before you run the createreplica utility. Use the following syntax for the primary and synchronous replication database. You must create a replica file before creating a synchronous replication database. the replica file should contain a line that names the databases. For example.

reads are done from the primary database. See the "Utilities" chapter in the VERSANT Database Administration Manual for a reference to the createreplica utility. 3. any line starting with a # sign is considered to be a comment. you must use the createreplica utility to create the synchronous replication database and load it with the contents of a primary database. Access either database in a normal manner. When you perform an action on an object in either database of a replica pair. they will be asserted in both databases. Once you have created a replica file and synchronous replication database. VERSANT will look for the database name in the replica file and. the action will be performed first on the object in the first database named in the replica pair in the replica file and then performed on the object in the second database. Create the synchronous replication database. automatically make a connection with the other database of the pair. 375 . you can access either database using normal syntax and procedures. if the VERSANT software root directory is /usr/local/versant. Each time you connect with either database of a replica pair with a begin session or connect database routine. Changes to the primary database will be written before changes are written to the synchronous replication database. if the name is found. By default. The database from which reads are made can be changed by calling o_setpreferreddb() or setpreferreddb(). if you lock an object in the second database. the file /usr/local/versant/replica will contain the following entry for a database named db1 located on a machine named alpha and its synchronous replication database replicadb1 on a machine named beta: db1@alpha replicadb1@beta A connection made to either database in a replica pair will automatically cause a connection to be made to the other database in the pair. You must use database@node syntax in the replica file to indicate the machines containing the databases to be mirrored. The ordering of the names of the databases determines the order in which changes will be written. VERSANT Database Fundamentals Manual For example. the lock will first be set in the database first named in the replica pair and then set in the second database. 4. If locks are asserted. In the replica file. Before beginning replication. The replica file can contain separate lines for any number of pairs of databases and synchronous replication databases. For example.

When synchronous replication begins. If the synchronous replication database runs out of space. then you can enable replica error reporting at the transaction level by doing the following. 376 . For example. Enable error reporting for a specific transaction by adding the option O_REPORT_ERROR to the commit option supplied to o_xact() or xact(). enable reporting with the following function: o_err o_setreplicareporting( o_dbname db ). the connection to the other database will succeed and access will be subject to standard operation during failure mode. If you want to receive an error message if either of the replicated databases fail. For example: o_xact( O_COMMIT | O_REPORT_ERROR. the default behavior of no reporting will be restored until o_setreplicareporting() or setreplicareporting() is called again.VERSANT Database Fundamentals Manual 5. A. NULL). At the next database session. Optionally set replica reporting. also grant privileges on the synchronous replication database. B. If a replica database being monitored is down. Administer b both oth databases in a normal manner. This means that you must manage both primary and synchronous replication databases as independent entities. Replica databases are normal databases. enable reporting with the following method in PDOM: o_err setreplicareporting( o_dbname_const db ). Enable reporting for each database you want to monitor in the current database session. 6. by default a transaction will not report an error if a synchronous replication database is down. if you try to make a connection to one of the databases in the replica pair and the connection fails because that database is down. In C/VERSANT. In C++/VERSANT. use the addvol utility to add space as you would with any other database. when you grant access privileges on a primary database. a commit will return error 4035: OM_TR_DBDOWN. If you run out of space in a primary database and add volumes to it. For example. VERSANT will not check to see if the synchronous replication database needs space and will not automatically add space to it.

the polling process will detect the return and resynchronize it. See the "Utilities" chapter in the VERSANT Database Administration Manual for a reference to comparedb. You can stop replication and remove a synchronous replication database with the removereplica utility. Optionally compare the primary and synchronous replication databases. the other starts a polling process. 9. Optionally remove a synchronous replication replication database. VERSANT Database Fundamentals Manual 7. 377 . When the database that failed returns. If you want to do manual synchronization. Optionally turn automatic synchronization off. By default. If you want to turn automatic synchronization off. See the "Utilities" chapter in the VERSANT Database Administration Manual for a reference to removereplica. You can use the offline comparedb utility to compare the contents of a primary and synchronous replication database. 8. you can use the polling utility: polling dbname See the "Utilities" chapter in the VERSANT Database Administration Manual for a reference to ftstool and polling. when either database in a replication pair goes down. you can use the ftstool utility.

One of the replica databases must be a group database.VERSANT Database Fundamentals Manual Usage Restrictions Following are restrictions on the use of synchronous database replication. Only one replica can be created. Nested transactions You cannot use nested transactions if synchronous database replication is in use. Cursor queries and event notification Both cursor queries and event notification operate on a single database and. routines that manage serial numbers or user lists. This means that checkins and checkouts cannot be replicated. Savepoints You cannot set or undo a savepoint if synchronous database replication is in use. that get information about a database. One of the replica pair must be a group database. You can only create one replica of a database. For example. or that run a utility on a database can be used only on one database at a time. are not fault tolerant. Schema evolution requires that both databases be running You cannot change schema when a database in a pair of replica databases is down. Some routines can be used only on a single database Some routines do not make sense for a pair of databases. 378 . thus. Join session You cannot use multiple processes in a session if synchronous database replication is in use.

Use the vbackup utility to restore the database previously backed up to a backup tape or file. You cannot perform checkpoint commits or use the dropinst utility if synchronous database replication is in use.) Then create a new replica database with the same name as the database that is not repairable: createreplica UPdb DOWNdb If both databases are down and are not repairable 1. (You do not have to backup both databases. If the down database is the secondary database. Failure Scenarios Following are recovery procedures in the case that one or both databases are not repairable. vbackup -restore db1 3. then switch the order of the database names in the replica file (so that the secondary database is seen as the primary database. Remove both databases: removedb -f db1 removedb -f db2 2. If the down database is the primary database. Stop the database that is running: stopdb UPdatabase 2. then create a new replica database with the same name as the database that is not repairable: createreplica UPdb DOWNdb 3b. Create the other database with createreplica: createreplica db1 db2 379 . If one database is down and is not repairable 1. just one or the other). VERSANT Database Fundamentals Manual Checkpoint commits and dropinst. Remove the database that is not repairable: removedb -f DOWNdatabase 3a.

A more moderate approach is to only archive one database. then a failure of the database being archived followed by a failure of the other database in the replicated pair will only allow a database restore to the latest log archive on the database where archiving was occurring.VERSANT Database Fundamentals Manual Network Partitioning Behavior VERSANT replication utilizes your network to manage distributed transactions across replicated databases. However. and if the database being archived fails. then parallel object updates will not occur. You should never attempt a database restore or log rollforward using vbackup to one of the databases in an actively replicated pair. you don’t need to use replica error reporting. This allows you to know in an application that a replica failure has occurred and then restrict updates to only one server. If applications doing updates run on both servers. you would only use the backup and log archives in a case where a failure to both databases occurs. If you choose to on-line backup and log archive only one database in the replicated pair. In this case. In this case. then the network failure will probably cause all databases to be inaccessible and neither database will be updated. and recreate it later using the createreplica command. You may wish also to perform on-line backups and log archiving for a replicated database. If one database in a replicated pair fails. after which it is better to remove the failed database with the removereplica command. 3. then VERSANT will refuse to re-synch the databases. If your network fails. it is typically restored automatically using automatic re-synchronization mechanisms. The most conservative approach is to perform on-line backups and log archiving on both databases all of the time. applications running local to a replicated database will conclude that the remote database is down and begin saving updates for later re-synchronization after the failure is corrected. You can avoid the network partitioning problem through application design or by using the optional replication error reporting. If applications doing updates run on only one server. 380 . 2. In this case. then a potential for parallel updates exists and error reporting must be used to prevent the applications on one server from updating during a replication failure. you don’t need to use replica error reporting. Database Backup and Restore in a Replicated Database Environment The VERSANT Fault Tolerant Server option protects a database from single failures. If all applications execute on clients remote to replicated servers. This leads to a situation called network partitioning where objects may have conflicting updates in each database. immediately perform an on-line backup and begin log archiving on the remaining up database. If VERSANT detects that both databases in a replicated database pair have done ANY updates during the failure. Three different update scenarios need to be considered: 1. it is possible that a failure may continue for an extended period of time.

but you will have problems later. • If you forget to include a pair of primary and synchronous replication database names in the replica file. • Synchronous replication databases are normal databases. • You must use database@node syntax in the replica file to indicate the machines containing the databases to be mirrored. if either a primary or synchronous replication database runs out of space. For example. All replication files in a network must be the same. If you run out of space in a primary database and add volumes to it. you will not get an error message. but another installation does not. When you manage objects. then changes made by some applications will be replicated but changes made by other applications will not be replicated. 381 . you will get an error message. VERSANT will not check to see if the synchronous replication database needs space and will not automatically add space to it. use the addvol utility to add space as you would with any other database. • If you make a consistency error in a replica file. a deadlock can occur if both applications try to update the same object. actions are applied in the order in which a pair of databases are named in the replica file. if one replica file on one installation of VERSANT specifies a particular primary and synchronous replication database pair. • If you make a syntax error in the replica file. if you ask for a write lock on an object. it is first set on the object in the first database named in the primary/replica pair and then set on the object in the second database named in the primary/replica pair. no replication will occur and error E7220 will be generated by the createreplica utility. This means that you must manage both primary and synchronous replication databases as independent entities. or else several types of problems can occur. VERSANT Database Fundamentals Manual Cautions • You must create a replica file and enter the primary and synchronous replication database names before initializing a synchronous replication database. For example. For example. If two applications use different replica files in which a particular database is designated as primary in one and as replica in the other.

it will resynchronize db2 with db1. VERSANT will automatically attempt to restart the database stopped with stopdb -f. This will result in the following sequence: 1. VERSANT immediately starts trying to restart and reconnect to db2 (it will continue trying as long as db1 is running). Mechanisms Create replica database UNIX createreplica (utility) Windows creatrep (utility) Delete replica database UNIX removereplica (utility) Windows removrep (utility) Set replica reporting on for current session c o_setreplicareporting() c++ setreplicareporting() Set synchronization on and off UNIX ftstool (utility) Windows ftstool (utility) Set preferred database for read operations with synchronous database replication c o_setpreferreddb() c++ setpreferreddb() 382 . and you stop db2. As soon as VERSANT can restart and reconnect to db2. 3. For example. Because replication is occurring. The restarted db2 becomes available again and resumes its role as part of the replica pair. You stop db2 with stopdb -f db2 2. suppose that db1 and db2 are a replica pair. 4.VERSANT Database Fundamentals Manual • Using stopdb -f is the same as a crash. if automatic synchronization is on. both are running.

VERSANT Database Fundamentals Manual Restore defaults for read operations with synchronous database replication c o_unsetpreferreddb() c++ unsetpreferreddb() 383 .

.................................................................... 385 Database User Management utility (dbuser) ............................................................................................................................................................................................... 392 User Authentication Sample Programs.............................................. 390 User Authentication Program Structure.......... 388 Database User Authentication............................................ It includes: • Database Users • User Authentication • User Privileges Database Users........................ 408 384 ............................................................................... 395 User Authentication Sample Programs............................................................................... 389 Customized User Authentication .....................VERSANT Database Fundamentals Manual Chapter 20: Controlling Access to Database This chapter explains the means of controlling access to a Versant database....................... 402 User Privileges........................................ Windows NT............................................................................................................................................ 386 User Authentication ......................................................... 388 Backward Compatibility........................................................... 408 Utility Access Privileges.................... 385 Users ................................................................................................................. UNIX ...................................... 388 Database Administrator Authentication ....................................................................................................................................................................................................................................................................................................................... 390 User Authentication Process.............................................

The dbsa • Owns the osc-dbid file for a database system. h. administers or accesses Versant databases.flg or personal. this can be done by editing the entry in the groups. and lib subdirectories and all files under those directories. There can be only one dba for a database at any point of time. After a database has been created. On Windows platforms.flg file in the database directory. The dba must have a valid Operating System User Account. Each user is identified by a user name that is stored in the database. The dba owns the database and related files and directories. Versant relies on Operating System mechanisms to verify the dba's identity and it does not do password- based user authentication for the dba. for all installations in a network. • Owns all database root directories for all installations in a network. Database Administrator (dba) The dba is the user who created the database. its dba can be changed by changing the ownership of its database directory. Versant has three kinds of users: Database System Administrator (dbsa) The dbsa is the user who installs Versant on each machine in a network. VERSANT Database Fundamentals Manual Database Users Users A user is a role adopted by a person who creates. The primary functions of the dba's are: 385 . including bin. The primary function of dbsa is to install the Versant Database System. • Owns all system information files for all installations in a network. A user name can be of 32 characters in length. this ownership extends to all versions of VERSANT installed on a system of databases. • Owns all VERSANT software root directories.

Database User Management utility (dbuser) The user management utility (dbuser) is used to add. -add Add a user to the database access list. You must also supply a -n or -P option.Read-Only. The default. You must also supply a -n or -P option. delete. used when changing the user's password 386 . The database user list for a particular database can be created and maintained by the dba of that database.Read/Write. -delete Delete a user from the database access list. You must also supply -n option. dbuser <command> [options] <dbname> The following are the supported commands: -list List users on the database access list. and change password of a database user. The database user may or may not have a valid operating system user account. A database user can change their password using the database user management utility (dbuser). or list users of a database. the default) -passwd password of a user -opasswd old password. The following are the supported options: -n <username> user name -P change public access -m <accessmode> access mode (r . The database users access the database using applications and utilities.VERSANT Database Fundamentals Manual * Creation of Versant databases * Granting and Administering user access to Versant databases * Backup Versant Databases Database Users (dbuser) The database users are the list of VERSANT maintained logical users who have access to a particular database. rw . -chpasswd Change the password of a user.

For example. For example. • To add a user Fred in the database EmployeeDB by running dbuser as shown below: dbuser -add -n Fred -m rw EmployeeDB Enter Fred's password: Confirm Fred's password: • To make the database publicDB available for public access dbuser -add -P publicDB • To delete a user Allen from the database EmployeeDB dbuser -delete -n Allen EmployeeDB • To list all the user information in the user list of the database EmployeeDB dbuser -list EmployeeDB • A database user can change the password associated with the user information. Fred's password can be changed by running the following: dbuser -chpasswd -n Fred EmployeeDB Enter Old Password : Enter New Password : Re-Type New Password : 387 . VERSANT Database Fundamentals Manual -noprint suppress display message dbname database name Only the Database Administrator (dba) of a database has the privilege of adding/deleting users to/from the users list.

Versant provides user identification via different methods for the database users: * Database Administrator Authentication * Database User Authentication * Customized User Authentication Database Administrator Authentication As Database Administrators (DBAs) have valid Operating System account. The server verifies the client's password with the information stored in the database to authenticate the client. Versant relies on Operating System mechanisms to verify the DBA's identity. To protect password confidentiality. The client is authenticated at the server during the initial connect (o_beginsession or o_connectdb). The client has a secret password. To prevent unauthorized use of a database. password based authentication is followed at the server-side. The client sends this password to the server to prove its identity. Versant encrypts the password before sending it across the network. Once the connection has been established. known only to the client and the server.VERSANT Database Fundamentals Manual User Authentication Authentication is the means of identifying uniquely the database users. For users with a password. The requirement is that the user be a valid OS user. User identification is the basis of Versant's authorization mechanism and the users are allowed access to the system when identified as 'authorized' users by the system. no passwords are checked. Database User Authentication Versant authenticates the users attempting to connect to a database by using the information stored in that database. no further authentication is done during the life of that connection. The Dba can choose to add a user with no password. The user 388 . Versant implements password-based authentication for users with a valid password and Operating System based authentication for users with no password. in which case the authentication mechanism at the server-side for that user is Operating System based. The following api is used by the client to set the user information required for user authentication. During Operating System based authentication. The password cannot exceed 256 characters.

it is required that the user exists as a valid Operating System user. For the case where. o_err o_setuserlogin(o_userInfo userinfo /* user information */). the users in the database have no passwords. Failing to provide the correct password would result in an authentication failure. the user entry in the database has a valid password. When performing Operating System level authentication. the user name from the operating system will be picked up as the default. db2tty -d <dbname> -u user1 -p user1-password (Will succeed from any machine and as any OS user) Backward Compatibility After conversion of a database to this release. The authentication mechanism for such users is again same as described above. }. dbuser -ch passwd -n user1 -passwd user1-password (The user invoking this command must be user1. this command will be authenticated based on Operating System) 4. VERSANT Database Fundamentals Manual information is specific for the caller thread of this api. only password-based authentication is performed. 389 . dbuser -add -n user2 -passwd user2-password <dbname> (A user with a password) 3. db2tty -d <dbname> (If the user invoking the db2tty process is same as the user1. for it to succeed) 6.0 database provided the user entry in the database has no passwords. The examples below describe the authentication procedure.0 clients can connect to a 6. 1. this command will fail as it performs password based authentication) 5. Once the password changes to a valid password the pre 6. struct o_userInfo { char username[O_NAME_SIZE]. Failing to satisfy both the conditions would result in an authentication failure. In case the user entry in the database has no password. The user information is sent to the server during a connect (o_beginsession() or o_connectdb()). db2tty -d <dbname> (If the user invoking the db2tty process is same as the user2. the server assumes Operating System authentication and performs the corresponding check for thatuser during the initial connect. dbuser -add -n user1 -passwd "" <dbname> (A user with no password) 2.0 client cannot access the database. If the user information is not set using this api before connecting to a database. char password[O_PASSWD_SIZE]. both on the client and the server side. All pre 6.

Run your application in two processes by linking with the VERSANT two process system library for your platform: liboscfe. Tell VERSANT about the authentication programs. The general format for the entry is: authentication_program program_path 3. the authentication programs on the application and database machines can communicate with each other through a connection established by VERSANT.so. liboscfe.a. 1.VERSANT Database Fundamentals Manual Customized User Authentication To customize user authentication. These programs can perform any actions that you want in order to come to a decision as to whether a particular user is valid. User Authentication Program Structure While they are running. 2. either with an interface routine or with a database utility. The general format for the environment variable is: VERSANT_AUTH=program_path On the database machine. Use two process model. Sample programs are provided in a following section of this chapter. On the application machine. or liboscfe. and a database authentication program that will run on the machine containing the database. After these steps.lib. Create two authentication programs: an application authentication program that will run on the machine containing the application. in the database profile file. These programs will communicate with each other through channels established by VERSANT. The authentication programs 390 . do the following. add a line containing the keyword authentication_program followed by the path to the database authentication program. set the environment variable VERSANT_AUTH to point to the application authentication program. Create authentication programs. VERSANT will run the authentication programs everytime a database connection request is made.

an authentication program on an application machine should do the following to prepare an authentication program on the database machine." O_AUTH_WRITE "Write my data packet to your database connection. /* packet data */ ) o_auth_packet. The authentication processes reads a packet from file 0 and writes a packet to file 1. 391 . /* length of data in byte */ o_ptr data. 5. O_AUTH_READ "Send to me one data packet you receive from your database connection." The default timeout is 600 seconds. In the simplest case. 2. /* operation type */ o_u4b len. Send O_AUTH_READ packet. 4. Send O_AUTH_WRITE packet." O_AUTH_DENIED "This user is not ok. Read packet from the communication pipe. the opcode and len fields of the packet are first retrieved from the connection and then data of the packet up to len bytes is read. 3." O_AUTH_GRANTED "This user is ok. Send O_AUTH_GRANT or O_AUTH_DENIED packet. the communication pipe appears to be open file descriptor 0 and 1. While reading a packet. Process the incoming packet. VERSANT Database Fundamentals Manual can send any of the following operation codes to the VERSANT process to which they are connected. The structure of a packet that can be sent with these operation codes is: typedef struct o_auth_packet { o_u2b opcode. 1. To an authentication process." O_AUTH_SET_TIMEOUT "Set the timeout period to a specified number of seconds.

3. 1. TCP/IP inetd daemon starts. The check is made on the machine containing the VERSANT_ROOT location parameter in use by the application. looks up the specified authentication program. but VERSANT will only extend to that user the privileges established by the database administrator. A user requests a VERSANT session. 4. send O_AUTH_GRANTED. Process the authentication. To grant authorization. To use VERSANT. To deny authorization. Send O_AUTH_READ. a machine must have TCP/IP software installed. When it receives a "begin session" or "connect database" request.) 3. Read a packet from the communication pipe. If the VERSANT_AUTH environment variable has been set. When a machine with TCP/IP starts. 5a. A user logs into the operating system. a TCP/IP inetd daemon process is started that will listen for service requests. 392 . VERSANT checks to see if the VERSANT_AUTH environment variable has been set on its machine. starts a VERSANT application. 2.VERSANT Database Fundamentals Manual The authentication program on the database machine should do the following. The VERSANT application may be using VERSANT files on a local or remote machine. Send O_AUTH_SET_TIMEOUT. starts the authentication program. The authentication programs are responsible for validating that a user is valid. User Authentication Process Following is a description of how VERSANT user authentication works. and redirects stdin and stdout so that they serve as a channel of communication between the application process and the authentication program. and makes a request to start a session (which requires a database connection. 1. VERSANT reads VERSANT_AUTH. An authentication program is started on the application machine. send O_AUTH_DENIED. The database administrator for a database must still add and delete users with the VERSANT dbuser utility. 2. 5b. forks a process.

) 5. and then fork a database server process.d process will start the database. 7. it forks a process. the application authentication program sends an O_AUTH_READ packet to the application process. The request for a database connection and a password are sent to the inetd daemon process on the machine containing the database.) The inetd daemon process will read its TCP/IP configuration files and respond to the connection request by starting a VERSANT ss. If it sees a line beginning with the keyword authentication_program.d process. and the only action that the application process can perform is to pass messages to and from the authentication program. When it starts. achine." (The username is sent by the VERSANT connection request. "please forward this password to the authentication program on the machine containing the database. the lines of communication are: 393 . the application authentication program sends an O_AUTH_WRITE packet containing a password to the application process. and redirects stdin and stdout so that they serve as a channel of communication between the server process and the server authentication program. The application machine authentication program sends "O_AUTH_WRITE". After sending a username.d (system services) process and then connect the application with the ss. if it is not already running." 6. (The same procedure is followed whether the database machine is remote or local. Once the connection request has been sent. An authentication program is started on the database m machine. The application machine authentication program then sends "O_AUTH_READ". control of the application process passes to the application authentication program. forward it to me. The ss. starts the program specified. At this point. This message means. "when you get a message from the VERSANT server process. The database server process will check its server process profile file. This message means. VERSANT Database Fundamentals Manual 4. The application sends a connection request and username to the database machine.

O_AUTH_GRANTED. (This discussion assumes the default timeout." At this point. If the application process has received an O_AUTH_READ packet. When it receives O_AUTH_GRANTED. For example. on stdout. an O_AUTH_WRITE packet to the VERSANT server process. control of the database server process has passed to the database authentication program. each program can send a packet with O_AUTH_WRITE and then stand by to receive a packet with O_AUTH_READ. The VERSANT server process then forwards the packet to the VERSANT application process. the database authentication program sends. O_AUTH_SET_TIMEOUT. The authentication programs can send any of the following operation codes to the VERSANT process to which they are connected: O_AUTH_READ. If authorization is granted. to send a message to the application authentication program. you would send O_AUTH_SET_TIMEOUT. the database authentication program sends the packet operation code O_AUTH_READ to the database server process. O_AUTH_WRITE. and the only action that the server process can perform is to pass messages to and from the authentication program.. "when you get a message from the VERSANT application process.. This message means. forward it to me.VERSANT Database Fundamentals Manual The authentication programs on the application and database machines are now active and can communicate with each other through the connection established by VERSANT. 9. communicating with each other through VERSANT. The authentication programs now conduct any kind of dialogue that you desire. In this dialogue. If the server authentication program decides that the user is okay. To change it. 10. and O_AUTH_DENIED. When it starts. the VERSANT server process forwards the message to the 394 .) 8. The database machine authentication program sends "O_AUTH_READ". it sends the message O_AUTH_GRANTED to the VERSANT server process and then terminates. it will give the packet to the application authentication program. The authentication programs evaluate the username.

.. Authentication program for application machine Following is a sample user authentication program to run on the machine running an application. The program simply used standard i/o routines to read and write from the pipe. When it receives O_AUTH_GRANTED. returns. then it stays alive in order to service database requests from the application. If the server authentication program decides that the user is not okay. If authorization is denied. the application authentication program terminates. UNIX Following are sample programs for customized user authentication suitable for Unix. the VERSANT application process forwards the message to the application authentication program and returns. and either handles the error or terminates with an error. it sends an error to the application. the application communicates with the authentication program through a Unix pipe which is duplicated onto the standard input and standard output handles of the authentication program. the application authentication program terminates. If the user is not on its list. it sends the message O_AUTH_DENIED to the VERSANT server process and then terminates. When it receives O_AUTH_GRANTED. the VERSANT server process forwards an error message to the VERSANT application process and terminates. Its first action is to check whether the user is on its own list of authorized users. When it receives O_AUTH_DENIED. VERSANT Database Fundamentals Manual VERSANT application process and returns. and terminates. 395 . User Authentication Sample Programs. On Unix. When it receives O_AUTH_DENIED. The communication mechanism between the authentication program and the application differs on NT. closes the connection. If the user is on the list. the VERSANT application process forwards the error message to the authentication program. When it receives O_AUTH_DENIED.

write(OUT.opcode = O_AUTH_READ. packet.opcode) { case O_AUTH_GRANTED: /* forward the packet to kernel */ SYSLOG("Access granted"). sizeof(o_auth_packet)).len = 0. } /* done */ SYSLOG("Done"). SYSLOG("Start").opcode = O_AUTH_WRITE. break. &packet.h> #include <omapi. 396 . sizeof(o_auth_packet)).h> #include <syslog. write(OUT. default: SYSLOG("Wrong reply packet"). case O_AUTH_DENIED: /* forward the packet to kernel */ SYSLOG("Access denied"). * File descriptor 1 is opened for writing to Versant kernel. sizeof(o_auth_packet)). write(OUT. &packet. write(OUT. char *argv[] ) { o_auth_packet packet. break. &packet. exit(2). read(IN.VERSANT Database Fundamentals Manual It is a stripped down example that simply passes a plain-text password to an authentication program running on the machine containing a database.len = strlen(PASSWORD). sizeof(o_auth_packet)).len). &packet. &packet.h> #include <stdlib. sizeof(o_auth_packet)). write(OUT. /* verify the reply packet */ switch (packet. (msg)) int main( int argc. packet. PASSWORD. /* write an O_AUTH_READ packet to server and wait for an reply */ packet.h> /* * File descriptor 0 is opened for reading from Versant kernel. /* write an O_AUTH_WRITE packet that contains the password */ packet. #include <stdio. packet. "(FE): %s". */ #define IN 0 #define OUT 1 #define PASSWORD "simple-but-unsafe" #define SYSLOG(msg) syslog(LOG_ERR.

len). VERSANT Database Fundamentals Manual return 0.h> #include <stdlib. */ #define IN 0 #define OUT 1 #define PASSWORD "simple-but-unsafe" #define SYSLOG(msg) syslog(LOG_ERR. buff. char buff[30]. } Authentication program for database machine Following is a sample user authentication program to run on the machine containing a database. packet.h> #include <omapi. It is a stripped down example that simply reads a plain-text password and then verifies it. "(BE): %s". * File descriptor 1 is opened for writing to Versant kernel. } else { SYSLOG("Access denied"). &packet. } /* write the authentication result to kernel */ packet. 397 . char *argv[] ) { o_auth_packet packet. #include <stdio. /* verify the reply packet */ if (packet.opcode = O_AUTH_GRANTED. packet.len = 0. (msg)) int main( int argc. read(IN. write(OUT. sizeof(o_auth_packet)). SYSLOG("Start"). PASSWORD.h> /* * File descriptor 0 is opened for reading from Versant kernel. /* read in the password */ read(IN. sizeof(o_auth_packet)).h> #include <syslog.len == strlen(PASSWORD) && !strncmp(buff. /* write an O_AUTH_READ packet to kernel and wait for an reply */ packet.opcode = O_AUTH_READ.opcode = O_AUTH_DENIED. packet. &packet. packet.len = 0. strlen(PASSWORD))) { SYSLOG("Access granted").

VERSANT Database Fundamentals Manual write(OUT. /* done */ SYSLOG("Done").h> #include "auth_krb5.h> #include <signal. &auth_context)) { 398 . argv) int argc. krb5_error_code retval. /* initialize Kerberos context */ krb5_init_context(& context). krb5_init_ets(context). { o_auth_packet packet.h> #include <netdb. krb5_principal principal. It performs the by parsing a KRB_AP_REQ packet sent from authentication program running on the application machine.h> #include <sys/socket.h> #include <sys/types. &packet. } Kerberos authentication program for database machine Following is a sample user authentication program to run on the machine containing a database. krb5_ccache ccdef.h" #include "com_err. "(BE): %s".h" #include <stdio. char* msgp.h> #include <netinet/in. krb5_data recv_data.h> #include <omapi. It uses Kerberos V5 as the principal authentication mechanism. Many of the resource deallocation codes are ignored on purpose in order to make the sample program simpler. krb5_keytab keytab. krb5_auth_context* auth_context = NULL. krb5_context context. char *argv[]. SYSLOG("Start"). return 0.h> #include <ctype. sizeof(o_auth_packet)). /* initialize authentication context */ if (retval = krb5_auth_con_init(context.h" #define SYSLOG(msg) syslog(LOG_ERR. (msg)) #define KEYTAB "/tmp/v5srvtab" void main(argc. #include "krb5.h> #include <syslog.

recv_data. exit(2). msgp. } /* identify our credentials cache */ if (retval = krb5_cc_default(context. exit(5).opcode = O_AUTH_READ. } /* write an O_AUTH_READ packet to kernel and wait for an reply */ packet. &ccdef)) { SYSLOG(error_message(retval)).len = 0. sizeof(recv_data)). keytab. &packet. packet. &packet. packet. exit(1). principal. read(IN.len)) == NULL) { SYSLOG("Out of memory"). VERSANT Database Fundamentals Manual SYSLOG(error_message(retval)). sizeof(o_auth_packet)). &recv_data. &auth_context. if (retval = krb5_kt_resolve(context. sizeof(o_auth_packet)). &principal)) { SYSLOG(error_message(retval)). KEYTAB. &keytab)) { SYSLOG(error_message(retval)). } /* read in the KRB_AP_REQ message */ read(IN. NULL. } else { SYSLOG("Authentication succeeded").data = msgp + sizeof(recv_data). msgp. if ((msgp = (char *) malloc(packet. } if (retval = krb5_rd_req(context. packet. } 399 . exit(3). } /* parse the KRB_AP_REQ message */ if (retval = krb5_sname_to_principal( context. write(OUT. OBE_SERVICE.opcode = O_AUTH_DENIED. exit(4). NULL)) { SYSLOG(error_message(retval)). /* reconstruct the KRB_AP_REQ message */ memcpy(&recv_data. KRB5_NT_SRV_HST. SYSLOG("Authentication failed"). packet.opcode = O_AUTH_GRANTED. OBE_HOST.len).

{ o_auth_packet packet. /* initialize Kerberos context */ krb5_init_context(& context). krb5_ccache ccdef. (msg)) void main(argc. krb5_init_ets(context). argv) int argc. krb5_data recv_data.h" #define SYSLOG(msg) syslog(LOG_ERR.h" #include "com_err. /* initialize authentication context */ if (retval = krb5_auth_con_init(context.h> #include "auth_krb5. "(FE): %s". exit(1). } Kerberos authentication program for application machine Following is a sample user authentication program to run on the machine containing an application. exit(0). char *argv[].h> #include <ctype. sizeof(o_auth_packet)). krb5_error_code retval. This program utilizes Kerberos V5 as the principal authentication mechanism.h> #include <omapi. SYSLOG("Start").VERSANT Database Fundamentals Manual /* write the authentication result to kernel */ packet. #include "krb5.h> #include <signal. /* done */ SYSLOG("Done"). krb5_context context.h> #include <sys/socket.len = 0. krb5_auth_context* auth_context = NULL.h> #include <netinet/in. Many of the resource deallocation codes are ignored in order to make the sample program simpler. &auth_context)) { SYSLOG(error_message(retval)). &packet.h> #include <sys/types.h" #include <stdio. 400 .h> #include <netdb. It achieves authentication by sending a KRB_AP_REQ packet to authentication program on a machine containing a database.h> #include <syslog. write(OUT.

exit(4). &packet. sizeof(recv_data)). &packet. packet. } /* send the KRB_AP_REQ message to kernel via an O_AUTH_WRITE packet */ packet.length. if ((packet. packet. OBE_HOST.data. write(OUT. break. recv_data.opcode = O_AUTH_READ.opcode = O_AUTH_WRITE.data. recv_data. /* write an O_AUTH_READ packet to kernel and wait for an reply */ packet. write(OUT. memcpy(((char *)packet.data. sizeof(o_auth_packet)). 401 . sizeof(o_auth_packet)). &recv_data)) { SYSLOG(error_message(retval)). &recv_data. &packet.opcode) { case O_AUTH_GRANTED: /* forward the packet to kernel */ SYSLOG("Authentication succeeded"). packet. write(OUT. &packet. exit(2).data = (o_ptr) malloc(packet. VERSANT Database Fundamentals Manual } /* identify our credentials cache */ if (retval = krb5_cc_default(context. sizeof(o_auth_packet)).data)+sizeof(recv_data). &auth_context. sizeof(o_auth_packet)). write(OUT. } /* format a KRB_AP_REQ message */ if (retval = krb5_mk_req(context. AP_OPTS_USE_SESSION_KEY. &ccdef)) { SYSLOG(error_message(retval)). break.len = 0.len = sizeof(recv_data) + recv_data.len). ccdef. packet.length). /* wait */ read(IN. } memcpy(packet.len)) == NULL) { SYSLOG("Out of memory"). OBE_SERVICE. sizeof(o_auth_packet)). &packet. exit(3). write(OUT. NULL. default: SYSLOG("Wrong reply packet received"). /* verify the reply packet */ switch (packet. case O_AUTH_DENIED: /* forward the packet to kernel */ SYSLOG("Authentication failed").

h> #include <stdlib. On NT we use an NT anonymous pipe to communicate between the authentication program and the application. char **argv) 402 . \ fprintf(outputFile. "a"). exit(0). \ } #define PASSWORD "simple-but-unsafe" /* * This is a bare-bone front-end authentication program whose sole * purpose is to demonstrate the usage of Versant user authentication * facility. The authentication program is expected to use WIN32 ReadFile() and WriteFile() calls to read from and write to these handles in order to communicate with the spawning program. It simply passes a plain-text password to the server * authentication program. The server authentication program follows the same protocol to communicate with VERSANT's server process. and need to be converted to handle numbers using atoi(). Sample client and server authentication programs for NT are presented below. \ fclose(outputFile). #define SYSLOG(msg) { \ outputFile = fopen("authfe. */ int main (int argc. /* * A sample client user authentication program. The read handle and the write handle of the pipe are passed in to the authentication program as command-line arguments. It takes input and output handle numbers as command-line arguments. The program simply used standard i/o routines to read and write from the pipe. On Unix. (msg)).out". } /* done */ SYSLOG("Done"). the application communicates with the authentication program through a Unix pipe which is duplicated onto the standard input and standard output handles of the authentication program.VERSANT Database Fundamentals Manual exit(2). Windows NT Following are sample programs for customized user authentication suitable for Windows NT. } User Authentication Sample Programs.h> #include <windows. and uses ReadFile() and WriteFile() for i/o on these handles. These arguments are integers in decimal notation. */ #include <stdio. "(FE): %s\n".h> FILE *outputFile = NULL.h> #include <omapi.

packet. return (1).len = 0. SYSLOG (message).opcode = O_AUTH_READ. &packet. hOut. sizeof(o_auth_packet). packet. } if (WriteFile (hOut. BytesWritten. &BytesWritten. BytesWritten. "WriteFile failed : %d". sprintf (message. DWORD BytesWritten. FILE *pfile. "WriteFile failed : %d".len). if (WriteFile ( hOut.len) { sprintf (message. BytesRead. /* write an O_AUTH_WRITE packet that contains the password * to kernel */ packet. hIn = (HANDLE)atoi (argv[1]). SYSLOG (message). return (1). SYSLOG (message). return (1). "WriteFile wrote %d bytes instead of %d". VERSANT Database Fundamentals Manual { o_auth_packet packet. GetLastError ()). GetLastError ()). NULL) == 0) { sprintf (message. &BytesWritten. PASSWORD. } /* write an O_AUTH_READ packet to kernel and wait for an reply */ packet.len = strlen(PASSWORD). SYSLOG (message). hOut). hIn. NULL) == 0) { sprintf (message. SYSLOG (message). return (1). } if (BytesWritten != packet. HANDLE hIn.opcode = O_AUTH_WRITE. char message[256]. hOut = %d". if (WriteFile (hOut. packet. sizeof(o_auth_packet). "WriteFile wrote %d bytes instead of %d". 403 . } if (BytesWritten != sizeof(o_auth_packet)) { sprintf ( message. "hIn = %d. if (argc < 3) SYSLOG("Bad arguments"). packet. hOut = (HANDLE)atoi (argv[2]). SYSLOG("Start"). sizeof(o_auth_packet)).len. &packet.

&packet. GetLastError ()). "WriteFile wrote %d bytes instead of %d". GetLastError ()). return (1). } /* verify the reply packet */ switch (packet. BytesRead. return (1). case O_AUTH_DENIED: 404 . &BytesRead. sizeof(o_auth_packet)). sizeof(o_auth_packet)). SYSLOG (message). "ReadFile failed : %d". } break. SYSLOG (message). } if (BytesWritten != sizeof(o_auth_packet)) { sprintf (message. SYSLOG (message). "WriteFile wrote %d bytes instead of %d". sizeof (o_auth_packet)). sizeof (o_auth_packet). NULL) == 0) { sprintf (message. return (1). } if (BytesWritten != sizeof (o_auth_packet)) { sprintf (message. } if (BytesRead != sizeof (o_auth_packet)) { sprintf (message. NULL) == 0) { sprintf (message. &packet.VERSANT Database Fundamentals Manual &BytesWritten. } if (ReadFile (hIn. BytesWritten. GetLastError ()). "WriteFile failed : %d". return (1). NULL) == 0) { sprintf (message. "ReadFile read %d bytes instead of %d". sizeof (o_auth_packet). &BytesWritten. "WriteFile failed : %d". if (WriteFile (hOut. return (1). SYSLOG (message). BytesWritten. SYSLOG (message). SYSLOG (message).opcode) { case O_AUTH_GRANTED: /* forward the packet to kernel */ SYSLOG("Access granted"). return (1).

h> #include <stdlib. SYSLOG (message). return (1). GetLastError ()). } break.h> #define PASSWORD "simple-but-unsafe" FILE *outputFile = NULL. return(0). "(BE): %s\n".h> #include <omapi. exit(2). "WriteFile failed : %d". \ } /* * This is a bare-bone back-end authentication program whose * sole purpose is to demonstrate the usage of Versant user * authentication facility. &BytesWritten. sizeof(o_auth_packet)).out". NULL) == 0) { sprintf (message. BytesWritten. */ #include <stdio. \ fclose(outputFile). } /* done */ SYSLOG("Done"). * It simply reads in a plain-text password and verifies it. "WriteFile wrote %d bytes instead of %d". "a"). 405 . \ fprintf(outputFile. char **argv) { o_auth_packet packet. SYSLOG (message). VERSANT Database Fundamentals Manual /* forward the packet to kernel */ SYSLOG("Access denied"). char buff[30].h> #include <windows. if (WriteFile (hOut. */ int main (int argc. } if (BytesWritten != sizeof (o_auth_packet)) { sprintf (message. } /* * A sample server user authentication program. #define SYSLOG(msg) { \ outputFile = fopen("authbe. (msg)). return (1). sizeof (o_auth_packet). default: SYSLOG("Wrong reply packet"). &packet.

SYSLOG (message). if (WriteFile (hOut. return (1). SYSLOG("Start"). packet. GetLastError ()). BytesWritten. buff. return (1). GetLastError ()). } if (BytesWritten != sizeof(o_auth_packet)) { sprintf (message.opcode = O_AUTH_READ.len) { sprintf (message. &BytesRead. BytesRead. packet. NULL) == 0) { sprintf (message. hIn = (HANDLE)atoi (argv[1]). "ReadFile read %d bytes instead of %d". return (1). hOut). hOut. char message[256]. return (1). hOut = (HANDLE)atoi (argv[2]). sizeof (o_auth_packet)). sizeof (o_auth_packet). SYSLOG (message). sizeof(o_auth_packet)). &BytesWritten. SYSLOG (message). SYSLOG (message). } if (BytesRead != packet. "WriteFile wrote %d bytes instead of %d". "ReadFile failed : %d". HANDLE hIn. "WriteFile failed : %d". BytesRead. hOut = %d".len. "hIn = %d. &BytesRead.VERSANT Database Fundamentals Manual DWORD BytesWritten. hIn. if (argc < 3) SYSLOG("Bad arguments"). return (1). &packet. GetLastError ()).len = 0. 406 . "ReadFile read %d bytes instead of %d". SYSLOG (message). sprintf (message. } if (ReadFile (hIn. NULL) == 0) { sprintf (message. } if (BytesRead != sizeof (o_auth_packet)) { sprintf (message. &packet. /* write an O_AUTH_READ packet to kernel and wait for an reply */ packet. } if (ReadFile (hIn. sizeof(o_auth_packet). SYSLOG(message). "ReadFile failed : %d". NULL) == 0) { sprintf (message.

BytesWritten. "WriteFile wrote %d bytes instead of %d". return 0. GetLastError ()). SYSLOG (message). } /* done */ SYSLOG("Done"). sizeof(o_auth_packet)). } /* verify the reply packet */ if (packet. return (1). packet. } 407 . sizeof(o_auth_packet). } if (BytesWritten != sizeof(o_auth_packet)) { sprintf (message. &packet. packet.len == strlen(PASSWORD) && !strncmp(buff. return (1). packet. } else { SYSLOG("Access denied"). if (WriteFile (hOut.opcode = O_AUTH_DENIED. return (1). SYSLOG (message). SYSLOG (message). PASSWORD.opcode = O_AUTH_GRANTED. "WriteFile failed : %d". VERSANT Database Fundamentals Manual BytesRead. &BytesWritten.len). NULL) == 0) { sprintf (message. } /* write the authentication result to kernel */ packet. strlen(PASSWORD))) { SYSLOG("Access granted").len = 0.

PUBLIC access When the PUBLIC access is granted for a database. only the DBA can access the database in single-process mode. does not guarantee entry into the database system while running in single- process mode. _&_. which can be executed remotely. The DBA always has read-write access privilege. dbsa dba dbuser Remote Execution addvol no yes no yes comparedb no yes no yes compardb (pc) no yes no yes convertdb no yes no no cnvrtdb (pc) no yes no no createdb no yes no yes createreplica no yes no yes creatrep (pc) no yes no yes db2tty no yes yes yes 408 . As stated earlier.VERSANT Database Fundamentals Manual User Privileges A privilege of a user is a right to access a database or objects in a database. the database is completely accessible to anyone. However it should be noted that setting the database to public access. Please see User Management Utility (dbuser) for details on how to grant access privileges to a user to access a database. Utility Access Privileges Access privileges to . When this is true. No user authentication is done. Following are VERSANT system utility access privileges for each database role. Also shown are the utilities. Access Modes • Read-Only • Read Write These access privileges can be granted to a database user by the DBA while adding a user to the system. anyone can access the database. These privileges are the same whether a system utility is executed from a command line or from the VERSANT Utility Tool. None of the above requirements need to be satisfied in order to gain access entry into that database system. or execute database utilities.

409 .d yes yes yes yes startdb no yes no yes stopdb no yes no yes vbackup no yes no yes vcopydb no yes no yes verr no yes yes no verrindx no no no no vstats no yes yes yes Only a dba can delete the files in a database directory. VERSANT Database Fundamentals Manual dbsa dba dbuser Remote Execution dbid yes yes yes yes dbinfo no yes no yes dblist yes yes yes yes dbtool no yes no no dbuser no yes no yes dropclass no yes yes yes dropcls (pc) no yes yes yes dropinst no yes yes yes ftstool no yes yes yes makedb no yes no yes makeprofile no yes no yes makeprof (pc) no yes no yes oscp no yes yes yes polling no yes yes yes removedb no yes no yes removereplica no yes no yes removrep (pc) no yes no yes reorgdb no yes no no sch2db no yes yes yes setdbid no yes yes yes ss.

... 412 Globalization........................................................................................................................................................................................................................................................................................................................................................................ 414 Back-end profile parameter......................virtual_locale............................................................................. 415 Locale Specific Pattern Matching ................................................................................................... 422 Localizing the Standard Localization Facility Files ............................... 424 410 ............................................................................................................................................................................................. 423 Localization Files Details ............................................................. 414 Pass-through/8-bit clean certification...................................................................................................................................................................................................................................................... 420 Standard Character Set ..................................................................... 419 Versant Localization ................................................................................................................................................................................ 412 Developing applications using Versant Internationalization ............................................................................................. 414 Searching and sorting of string-data are allowed in Non-English languages ..................................................................................................................................................................................................................................................................................VERSANT Database Fundamentals Manual Chapter 21: Internationalization Overview ............. 416 VQL ................................................................ 416 Examples..................................................................................................................................................... 416 C++ .................................................................................................................................................................................................... 418 Error Message ............................................ 420 Files Used to Generate Messages .......... 418 Deployment Issues............................................................................. 417 Java......... 414 /national......... 412 Internationalization ............................................................................................................................................. 418 Errors returned............................................................................................................................................................................................................................... 417 Application Support............................. 417 Database Utilities ......................................................................................... 420 VERSANT_LOCALE......................................................................................... 418 Application Impact.......................................... 420 Localizing Interfaces and Tools ........... 415 Back-end profile parameter...............................................locale ................................................................................................................................ 417 C++ ..... 412 Localization ........................................................ 418 Error Message files........................................................................................................................................

......................... 428 Localizing Usage Notes ............................................................................................. 433 411 .................................................................................................. 428 Restrictions............................................. VERSANT Database Fundamentals Manual Localizing VERSANT View.................................................................................................................................................................... 428 Encoding and Locales ........... 431 Syntax for Virtual Attribute ............................................................................................................................

412 .VERSANT Database Fundamentals Manual Overview Current global economy requires global computing solutions. Instead they are stored outside the source code and retrieved dynamically. because there are 18 letters between the first "I" and the last "N". Internationalization has the following characteristics: • Textual elements.0. which consists of two distinct steps: internationalization and localization. • Support for new languages does not require recompilation. The rest of the chapter will explain Versant internationalization framework. Versant will expand the scope to include other tools and products. Globalization The process of enabling a software product for global market is called globalization. Versant has focused on allowing the Versant database to be used in “internationalized” applications. The term internationalization is also abbreviated as I18N. are not hardcoded in the program. These global computing solutions should be in harmony with users' cultural and linguistic rules. Users expect the software to run in their native language. • The product can be localized quickly. Localization Localization is the process of adapting an internationalized product to meet the requirements of one particular language or region. such as status messages and the GUI component labels. In the 6. This overview will cover terms related to internationalization. Versant acknowledges the use of the IBM ICU library to implement the locale dependent string comparisons. such as dates and currencies.0 Release. The VERSANT ODBMS product consists of the database management system as well as utilities and administration tools. • Culturally dependent data. Over subsequent releases. appear in formats that conform to the end user's region and language. Steps are provided to help you in localizing versant error messages. Internationalization Internationalization is the process of designing software that can be adapted to various languages and regions without changing executables.

In this release Versant has internationalized the product so that you can develop Internationalized application. 413 . VERSANT Database Fundamentals Manual The first step in globalizing a product is to internationalize it. It will also help in localizing it.

/national Versant can use users native language collating sequence when executing queries on string valued attributes. C++ string types etc. Following components are ensured to be pass-through certified: 1. User names. 2. 5.e. For developing "internationalized" applications. Error messages.). is what you get back") • Searching and sorting of string-data is possible in Non-English languages • Locale sensitive pattern matching at various collation strengths will be supported • Error messages can be localized Versant supports string valued datatype in users locale.5 offers the following additional features: • Pass-through guarantee (that ensures "what you store. Names of volumes and log files. It is achieved by using special virtual attribute for I18N. /national. The core features mentioned above are described in detail in the sub-sections that follow. 3. java strings. Environment variables. trace file names in profile. 6. 8. (For details on virtual attributes please refer 414 . VQL queries. Database names and directories involved. Pass-through/8-bit clean certification Pass-through certification: Versant guarantees that the left most bit in a data-byte will not be used for internal purpose.0.VERSANT Database Fundamentals Manual Developing applications using Versant Internationalization The essence of how you develop Versant applications remains largely unchanged. Searching and sorting of string-data are allowed in Non-English languages This feature has been implemented using the concept of Virtual Attributes introduced in this database release. Versant release 6.be. 4. Output of command line utilities. Character attribute values of object instances (i. 7. The localization of the error messages is described in the section Versant Localization.

Back-end profile parameter.virtual_locale Syntax: virtual_locale “/national $locale_name $encoding $attr” This parameter should be used when you need nested virtual attributes involving /national. en_US locale will be used. Back-end profile parameter.be Syntax for `locale` is <locale_name>:<encoding> For German locale and UTF8 `locale` _parameter will be as follows: locale de_DE:UTF8 Firstname = “Andrè” is transformed to `/national de_DE utf8 Firstname` == “Andrè” This removes the overhead of specifying `/national` for all queries in the application.locale If you want a particular locale and encoding to be applied to all string attributes in your defined classes then the “locale” parameter needs to be set in profile.be setting for I18N in profile.) User should modify query attributes as follows `/national LOCALE ENCODING attrname` Valid examples : `/national de_DE UTF8 first_name == "Andre" ` // valid `/national en_US LATIN_1 last_name == "try" ` // valid `/national BRIGHT LATIN_1 last_name == "lll" `// will be done on en_US locale. A typical profile.be is as follows de_DE:UTF_8 locale /versant/lib/libnational. VERSANT Database Fundamentals Manual to the end of the chapter. If the encoding specified by you does not exist then an error will be returned. Default values 415 .so$/versant custom_be_plugins You will have to specify a virtual attribute template to indicate encoding and collating sequence specifier. Invalid examples: // `/national UTF8 de_DE first_name == "Paul"` `/national de_DE bogus_encode last_name == "Yulin"` If the locale specified by you does not exist then a default.

There are instances of German and English books. but not ‘a’ and ‘A’. O_NOT_EQ. Identical: no difference. Secondary: an accent difference. 'a' and 'b' are considered as different.5. the wild card “*”. 'a' and 'a'. For example. 416 . Note that. 'a' and 'A' are considered different. strings with less equality as compared to the secondary strength and O_EQ will be returned. For example. “$attr” should be used for specifying nested virtual attributes. For example.5 will allow users to run pattern queries in their native locale languages. For example. From release 6. For example in a comparison at primary strength with operator O_EQ.be parameter. this collation strength will impact not only the behavior of operators O_MATCHES (like. Tertiary strength will compare two variant representations of the same string as equal. “$encoding” will be used from “locale” profile. virtual_locale "/national de_DE utf8 $attr" $attr . In locale-language.0. Examples VQL In VQL queries can be written to use I18N feature as under: Suppose a class ‘Book’ has a attribute ‘Title’.specifies that you can specify a single string attribute to an index.VERSANT Database Fundamentals Manual for “$locale_name”. applications can specify the collation strengths per predicate term. but identical strength will compare them as different). A VQL query on books with titles beginning with letter "U" might be: int run_query() { d_VQL_query query("select OID from Book where title >= "U" and title <= "V"). in VQL) and O_NOT_MATCHES (not_like. Locale Specific Pattern Matching This Unicode pattern matcher in 6. ‘A’ and ‘à’. in VQL). but also on the equality operators O_EQ. Tertiary: a case difference. the icu collation framework provides four strength-levels to allow different levels of differences to be considered significant: Primary: a letter difference. ‘?’ and “[- ]“. 'a' and 'à' are considered as different. the comparison isn’t at character level. It will support all features similar to existing English pattern matcher. but not ‘a’. For example.0. For locale-sensitive string comparison. (The difference between tertiary and identical is that some strings can be spelled with more than one different sequence of numeric Unicode values.

select(NULL. } From 6...5 onwards the following locale specific pattern matching queries are allowed: select * from BasicEmployee where `/national fr_FR utf8 Tertiary BasicEmployee::emp_name` like ‘Frèd’ C++ In C++. the given query will not retrieve the titles beginning with "Ü". .structVstr). PPredicate needs to be changed as follows: PClassObject<Book>::Object(). C++ You can use C++ application to insert data into the database.be to enter the data. } But. . 417 . Ensure that you are using the same encoding as specified in the profile.. d_oql_excute(query. Versant will ensure that data entered is not lost.FALSE... Versant will ensure that data entered is not lost. you will have to modify the query as follows: int run_query() { d_VQL_query query("select OID from Book where `/national de_DE utf8 title` >= "U" and `/national de_DE utf8 title` <= "V" " )... VERSANT Database Fundamentals Manual d_oql_excute(query. In order to achieve the required result. RESULT: will include books beginning with "U" or "Ü" upto "V" Application Support Java You can use Java application to insert data into the database. Ensure that you are using the same encoding as specified in the profile. PPredicate(PAttribute("/national de_DE utf8 Book::title") > "U" " && PAttribute("/national de_DE utf8 Book::title") == " "V" "))..be to enter the data.structVstr)..0.

VERSANT Database Fundamentals Manual Database Utilities All the regular VERSANT utilities like vstream. • lib/en_us_L1. Application Impact Developer impact To internationalize application a developer must be aware of • virtual attribute . will work with internationalization. if the error message file named by the 418 . encodings application needs and set the parameters accordingly.msg. vbackup etc.so.msg This is an example. The same format is applied to de_ch_L1. Once the data has been loaded you cannot modify the locale. V_BAD_ENCODING You have specified an invalid Encoding. lib/error. • Display issues if any Database Administrator (DBA) impact Must know locale.be parameter locale • Review queries and indices on string valued attributes. Errors returned Error Message V_BAD_STRING_EXPANSION String cannot be converted to Unicode due to incomplete data string. The new error message file named by locale name is suffixed with ".msg" if in national code set.msg file still exists for backward compatibility./national • profile. Error Message files Error message file will be managed according to national code set. V_CANNOT_LOAD_COMPARE_ROUTINE Could not load user defined compare routine or could not load libnational . V_BAD_LOCALE Locale cannot be opened.

Deployment Issues As an application developer you need to ensure that your application (at client side) displays the data correctly.be file contains database's national code set information. VERSANT will not do any code conversion. then use "error. Verrindx needs to be run before using versant if user has copied his error files using a particular locale. 419 . Appropriate VERSANT_LOCALE value needs to be set to get an error message in a particular locale. In db directory: • db/dbname/profile. VERSANT Database Fundamentals Manual Environment variable is not found.msg".msi Above file is generated and used internally by Versant. • lib/en_us_L1. For more details refer to the section on Versant Localization.

message retrieval is accelerated. C interface. You will have to copy the modified files like error. prompts./lib/en_US_latin1. database utilities.msg file.msg as $VERSANT_LOCALE.VERSANT Database Fundamentals Manual Versant Localization VERSANT_LOCALE The environment variable will indicate if you want to choose a locale specific error messages or not. error. the Standard Localization Facility uses the following files.txt and error. and $VERSANT_LOCALE. and C++ interface.txt. These files are all located in the lib directory for a particular release.msi This binary file is an index of the locations of the error messages in the error. For example: .msg (using JIS encoding For ja_JP) If a you set VERSANT_LOCALE to "ja_JP" then all Versant error messages will be displayed in Japanese language. 420 ..msg This text file is the source of all natural language messages for all interfaces and tools that use the standard facility. progress messages. The last letter of that file has been changed to "i" to mean "index". If it does not exist or is inaccurate.. and names seen in graphical interfaces are all generated by the Standard Localization Facility. VERSANT interfaces and tools use a common mechanism called Standard Localization Facility to generate all natural language messages. error./lib/ja_JP_jis. Files Used to Generate Messages Versant localization is achieved using the environment variable VERSANT_LOCALE. Default error messages will be in Latin-1.msg (using Latin1 encoding for US English) . When this file exists and is accurate.msg. To generate messages. For example. Localizing Interfaces and Tools Following are instructions for localizing the database kernel. both error messages and non-error messages.

The additional lines in this file provide elaboration on the error messages. error.msg file are a subset of the lines in this file. The lines in the error. VERSANT Database Fundamentals Manual messages will still be retrieved.msi file should be rebuilt by running the verrindx command.txt This text file is only used by the verr command.msg. Thus any time a change is made to error. the error. but slowly. 421 .

Used as a special token in . Used in formatted error messages.msg.msg and error. Delimiter in error. Used for escape sequences in error.VERSANT Database Fundamentals Manual Standard Character Set The following ASCII characters are treated specially by some components of C++/VERSANT. angle-bracket < 60 close-angle-bracket > 62. You may have problems if they are given new meanings as letters. backslash \ 92. Used in error.msg. bang ! 33.txt 422 . Description Example ASCII # white space 32 tab \t 9 newline \n usually 10. Used for substitution marks in error. a standard word and line separator.txt colon : 58. 44.msg and error. Delimiter in error. comma .txt. zero 0 48 one 1 49 two 2 50 three 3 51 four 4 52 five 5 53 six 6 54 seven 7 55 eight 8 56 nine 9 57. Used in formatted error messages.sch files percent % 37.msg and error. forward-quote \' 39 backward-quote ` 96.

VERSANT Database Fundamentals Manual

Localizing the Standard Localization Facility Files
To localize the files used by the Standard Localization Facility:

1. Edit error.txt.

Edit the error.txt file, translating the English messages into the local language.

• You must retain the syntax of this file, as documented below.

• The "%" substitutions must also be retained, in exactly the order they appear here.

For example, the following error message must be translated so that the attribute name is still substituted
first, and the class name is still substituted second, even if that is inconvenient in the local language:
8544, SCAP_NEWATTRAT: Cannot add new attribute %s to class %d

2. Build error.msg.

Build the error.msg file by copying the new error.txt file, but retaining only the lines that begin
with a digit.

The following UNIX command will do it for you:
cd .../lib ; grep "^[0-9]" < error.txt > error.msg

In the above, for .../lib substitute the path to the VERSANT lib directory.

3. Run verrindx.

Run the VERSANT verrindx command. This should be done any time the error.msg file is altered.

423

VERSANT Database Fundamentals Manual

Localization Files Details
error.txt

There are two types of lines in the error.txt file: primary lines and secondary lines.

Primary lines — Primary lines have the following syntax:
nnnn, error_name: message \n

Elements:
nnnn

Primary lines begin with a digit, which is the error number. The error number can be one or more digits,
0-9.
,

A comma delimiter.
space

A space delimiter.
error_name

The error name, which can be one or more characters. You can use any character except a colon.
:

A colon delimiter.
space

A space delimiter
message

The natural language message, which can be any characters.
\n

normal line termination

Within message, certain two-characters sequences have special meaning:
%s

Substitute a string

424

VERSANT Database Fundamentals Manual

%d

Substitute a number, print in decimal.
%x

Substitute a number, print in hexadecimal.
\n

Substitute a newline character, the \n of C.
\t

Substitute a tab character, the \t of C.
\b

Substitute a backspace character, the \b of C.
\f

Substitute a formfeed character, the \f of C.
\\

Substitute a backspace character, for escaping.
\%

Substitute a percent character, for escaping.

Secondary lines — Zero or more secondary lines follow each primary line and elaborate on the error in the
primary line.

The syntax for secondary lines is:
\t message \n

Elements:
tab

Secondary lines begin with a tab character.
message

The message can contain any characters except for escape characters.

425

VERSANT Database Fundamentals Manual

\n

normal line termination

Some secondary lines are of this form:
[ used by ` class Link (vnih)']

These lines are not used consistently, and could be left out rather than translated.

error.msg

The syntax of the error.msg file is the same as the error.txt file, except that secondary lines are not allowed.

Following is a fragment from the error.txt file with the components described above.

Each primary line must be one long line in the file. For example, the lines beginning with 8052 and 8054 are
shown here as two lines, but in the file they must each be a single line.

The lines that do not start with a digit must begin with a tab character.

8045, CXX_HASH_UNDEFINED: hashing method undefined
It is the responsibility of a subclass of PVirtual to define
a hash method. This error is thrown by the default
PVirtual::hash().
8050, CXX_ZERO_F_ARG: bad zero argument for %s in function %s
8051, CXX_ZERO_M_ARG: bad zero argument for %s in method %s
8052, CXX_OM_PANIC: internal object manager panic: %s (line %d file %s)
This is a serious error. No other database object
manager operations will be possible for this process
after this error. This is cause for terminating your
program and trying again. It may indicate database
corruption.
8054, CXX_CLASS_SIGNATURE: for class %s, compiled class signature %x does not match
schema signature %x in database %s
A 32-bit signature is calculated for each class during
schema capture using a CRC function across the class and its
attributes. This 32-bit signature is compiled into your
application and is also deposited in the .sch file.

426

VERSANT Database Fundamentals Manual

In the error.msg file, all of the secondary lines in the above fragment would be left out and only the
following would remain (again, each element must be a single long line in the file):

8045, CXX_HASH_UNDEFINED: hashing method undefined
8050, CXX_ZERO_F_ARG: bad zero argument for %s in function %s
8051, CXX_ZERO_M_ARG: bad zero argument for %s in method %s
8052, CXX_OM_PANIC: internal object manager panic: %s (line %d file %s)
8054, CXX_CLASS_SIGNATURE: for class %s, compiled class signature %x does not match
schema signature %x in database %s

427

VERSANT Database Fundamentals Manual

Localizing VERSANT View

Localizing Usage Notes
Debugging Messages

Debugging messages are not localized at the present time. Instead, they are compiled out of production
releases. In the future, debugging messages will be localized.

Shell Scripts

Some shell scripts do not use the Standard Localization Facility. Their messages are in the shell scripts,
and can be easily edited. Other shell scripts do use the Standard Facility. These scripts can be identified
because they call the undocumented command perrfilt.

Encoding and Locales
LOCALE— represents ONLY the collating sequence and is not used for date and time attributes.

A partial list of the locales supported by VERSANT is as follows:

German

Country Language
(German=de)
de_AT
Austria
de_DE
Germany
de_LU
Luxembourg
de_CH
Switzerland

French

Country Language
(French=fr)
fr_BE
Belgium

428

VERSANT Database Fundamentals Manual

fr_CA
Canada
fr_FR
France
fr_LU
Luxembourg
fr_CH
Switzerland

Chinese

Country Language
(Chinese=zh)
zh_CN
China
zh_HK
Hong Kong
zh_TW
Taiwan

Spanish

Country Language
(Spanish=es)
es_AR
Argentina
es_BO
Bolivia
es_CL
Chile
es_CO
Colombia
es_CR
Costa Rica
es_DO
Dominican Republic
es_EC
Ecuador
es_SV
El Salvador
es_GT
Guatemala
es_HN
Honduras

429

VERSANT Database Fundamentals Manual

es_MX
Mexico
es_NI
Nicaragua
es_PA
Panama
es_PY
Paraguay
es_PE
Peru
es_PR
Puerto Rico
es_ES
Spain
es_UY
Uruguay
es_VE
Venezuela

English

Country Language
(English=en)
en_AU
Australia
en_BE
Belgium
en_CA
Canada
en_IE
Ireland
en_NZ
New Zealand
en_ZA
South Africa
en_GB
United Kingdom
en_US
United States

ENCODING — this specifies the encoding used in this attribute.

A partial list of encodings supported by VERSANT is as follows:

430

VERSANT Database Fundamentals Manual

8859-1[LATIN_1] ascii[LATIN_1] iso-8859-1[LATIN_1]

8859-15 [923] asmo-708 [1089] iso-8859-15 [923]

8859-2 [912] big-5 [1370] iso-8859-2 [912]

8859-3 [913] big-5 [1370] iso-8859-3 [913]

8859-4 [914] chinese [1386] iso-8859-4 [914]

8859-5 [915] cp037 [1140] iso-8859-5 [915]

8859-6 [916] cp1008 [5104] iso-8859-6 [1089]

8859-7 [917] cp1025 [1154] iso-8859-7 [4909]

8859-8 [918] cp1026 [1155] iso-8859-8 [916]

8859-9 [919] cp1027 [5123] iso-8859-8i [916]

Versant will support locales and encodings supported by ICU 1.3.1. For more details go to
www.alphaworks.ibm.com.

If a wrong LOCALE is specified, a default locale, en_US will be used. For example: if you misspell a locale and
the corresponding locale does not exist , then en_US will be used

Restrictions
Versant internationalization has the following restrictions:

Class names and attribute names

Class names and attribute names are not certified to be Unicode/multi-byte compliant.

No conversion between different locales for Client-side and Server-side

Client-side environment variable VERSANT_LOCALE and Server-side variable, virtual_locale for Locale
does not indicate any code conversion between Client-side and Server-side.

Pass through certification in beta version

• Versant/SQL is not pass through certified.

431

VERSANT Database Fundamentals Manual

• vexport, vimport and vstream is pass-through certified for UTF-8, Latin-1 only.

• X-based utilities are not pass-through certified

• FTS, Event Notification in C++, Java are not be tested in lab-to-lab release

No increase in OS paths and file name size

OS paths, file name sizes will not be increased. The length of these variables will remain the same. Some
of the Operating Systems do not allow non-ASCII file names.

It is advisable to check these restrictions.

Current limits for Versant are as follows:
Database names, User names 31 bytes
Node name 223 bytes

For detailed listing of limits refer to "Names rules" section in VERSANT/C Manual.

Profile.be should not be modified

Internationalization parameters like 'locale' that can be specified in the database server profile file (
profile.be) should not be modified, after the data has been loaded in the database. If you change the
profile parameters, the locale specific string comparisons may yield incorrect results as the data may be in
a different encoding.

Locale specific data comparisons cannot be specified in path-queries.

Operator [] returns nth byte instead of character

Vstr<char> will be treated as Vstr<o_ulb>, that is [] operator will return nth byte rather than a
character.

Supports encoding that do not use NULL

Versant will support encodings, which do not use NULL as part of any character. For example: UTF-8,
Latin-1.

Java strings not converted to encoding

Java strings will be returned as ByteArray. It will not be converted to encoding as done currently.

Pattern matching query with accent character

A pattern matching query with accent character before the wildcard may not work correctly under the

432

.. Following is the Virtual Attribute grammar that uses an informal BNF notation. terminal symbols are represented in uppercase 433 . { symbol } means a mandatory symbol . To indicate that it is virtual. This is important. and are case-insensitive . + represents 1 or more symbols . it begins with a slash (/) character.}). SLASH “/” BRACE-START “{“ BRACE-END “}” virtual-attribute ::= SLASH<virtual-attribute-template> { <attribute> | BRACE-START <virtual-attribute> <BRACE-END } [ { <attribute> | BRACE-START <virtual-attribute> <BRACE-END }+ ] virtual-attribute-template ::= nocase <encoding> | tuple | national <locale> <encoding> | … . as parameters could be other Virtual Attribute with parameters. keywords are presented in bolded font. Parameters that contain SPACE or TAB characters are quoted within curly (braces({. VERSANT Database Fundamentals Manual following conditions: • Accent character before the wildcard in the pattern string • There is a corresponding index • Primary strength level For example. the following query doesn’t return the object that contains “Frederic” select selfoid from BasicEmployee where `/national fr_FR utf8 PRIMARY BasicEmployee::emp_name` like 'fr?*' The workaround for this problem is to avoid using the accent character in the pattern string: select selfoid from BasicEmployee where `/national fr_FR utf8 PRIMARY BasicEmployee::emp_name` like 'fre*' Syntax for Virtual Attribute A Virtual Attribute is used in certain operations where a normal attribute would be used. * represents 0 or more symbols . [ symbol ] means an optional symbol .

non-terminal symbols are represented in italic font for example: virtual-attribute 434 .VERSANT Database Fundamentals Manual .

...................... In more recent applications................................................................................. For the traditional "telco" application.. 437 createdb .................................................................... The Versant Developer Suite 6........................................................... Furthermore................................................ 437 o_writeprofile() ...... The latter set of applications also tend to use Java based application servers................. VERSANT Database Fundamentals Manual Chapter 22 : Embedding Versant Utilities in Applications APIs ...................... The term "embedded" implies the database is not visible to the user of the application directly.................. Versant ODBMS has been embedded in switching and network management systems........................ 439 SS daemon enhancements .......................................................................................... it also implies the typical administration of the database can be done by the application transparently................................................................................................................. 438 vmovedb.............................................................0 has been enhanced to provide support to embed the utilities within user applications................... 438 sch2db................................................................................................................................ This has been achieved in the following ways • Support of utility functionality through API interface • Remove interactive nature of utilities • Returning of proper return codes to aid embedding • Support for remote database cases 435 ...................... without much involvement by DBAs........................ 440 Most applications use Versant ODBMS as an embedded database...... the trend is to use Versant ODBMS as a metadata or enterprise data cache for Java based e-biz applications..................... 436 makedb..................................................

VERSANT Database Fundamentals Manual APIs The following APIs (in C.copydbToExistingDB DBUtility.killAndRemoveDBDir ectory removereplica o_removereplica() PDOM::removereplica() DBUtility.getProfile removedb o_removedb() PDOM::removedb() DBUtility.writeBEProfile These behave with the same functionality of their utility counterparts.addVol comparedb o_comparedb() PDOM::comparedb() - createdb o_createdb() PDOM::createdb() ity. Please refer to the C / C++ / Java Versant Manuals for a description of each of these interfaces.copydb vmovedb o_vmovedb() PDOM::vmovedb() - writeprofile o_writeprofile() PDOM::writeprofile() DBUtility.reorgdb setdbid o_setdbid() PDOM::setdbid() DBUtility.stopDB DBUtility.startDB stopdb o_stopdb() PDOM::stopdb() DBUtility. C++ and Java) are available for use directly through application programs: Utility C API C++ API Java API addvol o_addvol() PDOM::addvol() DBUtility. C API C++ API o_addtonvlist() NameValueList::add() o_createnvlist() NameValueList::create() 436 .createReplica ity.removeDB DBUtility.replicateToExistingDB dbuser o_dbuser() PDOM::dbuser() ity.createDB ity.removeReplicaForce reorgdb o_reorgdb() PDOM::reorgdb() DBUtility.ftstoolDisablePolling ity. Passing of parameters to these functions is to be achieved through the use of the "o_nvlist" structure (class NameValueList in C++).removeReplica DBUtility.ftstoolStopSync makedb o_makedb() PDOM::makedb() ity.setDBID sch2db o_sch2db() PDOM::sch2db() - startdb o_startdb() PDOM::startdb() DBUtility.ftstoolEnablePolling ity.makePDB ity.makeGDB makeprofile o_makeprofile() PDOM::makeprofile() - readprofile o_readprofile() PDOM::readprofile() BEProfile.createAndInitializeDB createreplica o_createreplica() PDOM::createreplica() ity.killAndRemoveDB DBUtility.killDB vcopydb o_vcopydb() PDOM::vcopydb() DBUtility.removeDBDirectory DBUtility.getDBUsers ftstool o_ftstool() PDOM::ftstool() ity.makeDB ity. Functions to manipulate the variables of these types are listed in the table below.

"vsntuser"). ::dom->makedb("versantdb". makedbList). makedbList. makedbList). VERSANT Database Fundamentals Manual o_deletenvlist() NameValueList::release() o_firstnamefromnvlist() NameValueList::get_first_name() o_freevaluefromnvlist() NameValueList::free() o_getnameatcursorfromnvlist() NameValueList::get_current_name() o_getnamecountfromnvlist() NameValueList::count() o_getvalueatcursorfromnvlist() NameValueList::get_current_value() o_getvaluefromnvlist() NameValueList::get_value() o_nextnamefromnvlist() NameValueList::get_next_name() o_nvlistlength() NameValueList::length() o_removeatcursorfromnvlist() NameValueList::remove_current() o_removefromnvlist() NameValueList::remove() o_replacevalueatcursorinnvlist() NameValueList::replace_current() o_replacevaluebyindexinnvlist() NameValueList::replace() o_replacevaluebyvalueinnvlist() NameValueList::replace() The "o_nvlist" structure hold numerous name-value pairs that is common when invoking command-line utilities. To invoke this utility from the command-line. makedb The utility "makedb" accepts an option "-owner" which also requires a value. "-owner". 437 . o_addtonvlist(makedbList. the following piece of C code can be written: o_nvlist makedbList. the following command is to be specified makedb -owner vsntuser versantdb To achieve the same through an application. Normally. o_makedb("versantdb". ::dom = new PDOM().be". this is achieved by editing the back-end profile file "profile. The same functionality in C++ would be as follows: NameValueList makedbList. o_writeprofile() This API can be used to modify the contents of the back-end profile for the database. o_deletenvlist(makedbList). "vsntuser").add("-owner". o_createnvlist(&makedbList).

o_addtonvlist(prflList. o_createnvlist(&prflbList). "4M physical. "event_daemon". prflList).log 100"). "extent_size". NULL). o_writeprofile(O_BE_PROFILE. o_addtonvlist(prflList. "150"). o_addtonvlist(prflList. we want to add the following parameters to the back-end profile for the database "versantdb". the following code snippet can be used: o_nvlist prflList. createdb The next task would be to invoke "createdb" invoked from the command line as: createdb versantdb This could be invoked from a C program as o_createdb("versantdb". "plogvol". o_addtonvlist(prflList. "heap_size". "versantdb". "logging". o_addtonvlist(prflList.VERSANT Database Fundamentals Manual As an example. "/opt/versant/nvlist/list \"abc\""). extent_size 8 heap_size 150 logging on polling_optimize off commit_flush on plogvol 4M physical. o_addtonvlist(prflList. "commit_flush". "virtual_locale". "off"). "polling_optimize". "8"). vmovedb vmovedb –threads 5 –C node employee person src_db dest_db 438 . "\"abc 123\""). Equivalent C++ program invocation: ::dom->createdb("versantdb"). o_addtonvlist(prflList. o_addtonvlist(prflList. "on").log 100 virtual_locale "abc 123" event_daemon /opt/versant/nvlist/list "abc" To achieve this through the application program. "on").

schdbList). ::dom->vmovedb(src_db. &vmoveList).sch To implement the same through the C program: o_nvlist schdbList. o_sch2db("schema. "versantdb"). o_addtonvlist(schdbList. "-threads". schdbList. o_createnvlist(&vmoveList).add("-threads".sch" is to be loaded into the database just created. o_createnvlist(&schdbList). "5"). The C++ program would have the following statements: NameValueList schdbList. o_deletenvlist(schdbList). 439 . schdbList. "-D". dest_db. NULL). vmoveList. o_addtonvlist(schdbList.add("-D". vmoveList. The command line utility is invoked as: sch2db –D versantdb –y schema. sch2db A schema file "schema. “5”). "-C".add("-C". o_deletenvlist(vmoveList). The C++ program would have the following statements: NameValueList vmoveList.sch". "versantdb"). vmoveList).add("-y". o_addtonvlist(vmoveList. VERSANT Database Fundamentals Manual To implement the same through the C program: o_nvlist vmoveList. ‘node employee person’). o_addtonvlist(vmoveList. "y". ‘node employee person’). dest_db. ::dom->sch2db("schema. NULL). schdbList).sch". o_vmovedb(src_db.

Therefore root priviledge is required to install Versant ODBMS completely. The "inetd" is configured to invoke this daemon during Versant ODBMS installation. This daemon handles all initial requests from the client application. Please refer to the "SS daemon" chapter for details. This proves to be a hurdle to embed Versant in an application. 440 . In the Versant Developer Suite 6.0 new functionality has been added to the SS daemon.VERSANT Database Fundamentals Manual SS daemon enhancements The Versant SS daemon is the Versant system services daemon that is invoked by "inetd" on Unix machines. The daemon can now be executed from the command line (and hence does not require root priviledges).

........................................... 444 Concepts.................................................................................................. 466 Attributes that Can be Indexed ..................................... 450 Attribute Specification by Name......................................................... 449 Attribute Types NOT Allowed ............................................................................................................................................ VERSANT Database Fundamentals Manual Chapter 23: Query Processing Search Queries ......................................................................................................................................................... 466 Attributes that Cannot be Indexed ............................... 444 Mechanisms .......................................... 449 Attribute Types Allowed ............................................... 453 Comparison Operators.................................................................................................. 473 Indexes and Unique Attribute Values ....................................................................... 468 Indexable Predicate Term .............................................................................................................................................................................................................. 470 Query Usage of Indexes ............................................................................................................................................................................................................................................................................................................................................................................................................................... 456 Predicate Term Concatenation ................... 454 String operators .................................................. 471 Sorting Query Results ............................................................................................................................................................... 445 Structure .. 475 441 ................................ 455 Set operators...... 467 Mechanisms .......................................................... 464 General Rules ............................................................................................................................................................................................................................................................. 469 Query Evaluation and B-tree Indexes ....................................................................................................................................................... 467 Query Costs ...................................................................................................... 454 Relational operators .......................................................... 459 Search Query Indexes ........................................... 446 Predicate Term............................................................................................................................................................................................................................................................................................................................................................................................ 464 Attribute Rules ....................... 447 Evaluation and Key Attributes .................................................................... 458 Logical Paths.................................................................................. 454 Class operators ...................................................................... 464 Concepts............................................................................................................................................................................................................................................................................................................ 451 Attribute Specification by Path............................................

.............................................. 522 Examples...................................... 481 Concepts.................................................................................................................................................... 479 Cursor Queries .......................................................................................................................................................................................................................... 518 Virtual Attribute ............................................................................................................................................................................................................................................................................................................................................................ 498 Overview .................................................................................... 521 Virtual Atrributes in VQL Query.................. 523 442 ......................................... 510 Advanced Queries ......................................................................................... 520 Virtual Attributes in Index Operation.. 519 Virtual Attributes Usage ........................................................................................................................................................................................... 521 Supported Virtual Attributes Templates....................................................... 498 VQL Procedures. 483 Cursors and Locks .................................................................................................................................... 481 Mechanisms ................................. 501 Not Supported .......................................................................................................................................................................................................................................................................................................................................................................................................................................... 518 Loading Virtual Attribute Template (VAT) Implementation ........................................................................ 518 Syntax of Virtual Attribute ..................................................................................................................................................... 482 Result Set Consistency ............................................................................................................................................................. 504 Creating a Predicate .................. 501 Specifying an object with a loid ........................................................................................................................................................................................................... 482 Elements ....................... 519 Virtual Attributes in Predicate Term of Search Queries and Cursors........................... 484 Example ...................................................................................................... 501 Case Sensitivity ..................................... 498 Statement Usage Notes......................................................... 509 Example ...................................................................................................................................................................................................................................................... 501 Specifying Attributes ........................................................... 503 Data type conversion....................... 505 VQL Syntax and BNF notation................................. 501 Statement Strings................................................................................................................................................................................................. 498 Mechanisms ...................................................................................................VERSANT Database Fundamentals Manual Indexes and Set Queries......................................... 486 VQL Queries ........................................................................................................................................

......... 523 443 ......................................................................................................... VERSANT Database Fundamentals Manual Restrictions.............

" or "get" routines. and then use a dereference method to retrieve them as desired. you can send the same search query to numerous databases. VERSANT evaluates "get" queries on the application machine and then retrieves the desired objects from any connected database. objects to be found by a "find" query must be located in a single database. However. 444 . VERSANT evaluates "find" queries on the server machine containing the database to be searched and then sends links to the found objects to the application. Because of the client/server architecture for search queries. Query types — The general term "query" conceptually refers both to routines that evaluate object values ("find") and routines that evaluate object identities using links ("get").VERSANT Database Fundamentals Manual Search Queries Concepts Query definition — A "query" examines a group of objects and returns those that satisfy a search condition. store the object references (links) to objects in multiple databases in a collection. get Functions and methods that use links to bring objects in memory are called "dereference." "retrieval. The term "query" is often used to refer to just "find" routines. find Functions and methods that use search conditions to find objects and return links are called "search" or "find" routines.

they are not query functions. links. o_defineevent() define event to find objects o_fetchcursor() find objects with cursor o_findarchivedobj() find objects in an archive o_pathpcheckout() find objects and check it out o_pathselect() find objects of a class or vstr o_pathselectcursor() find objects with cursor o_pcheckout() find objects and checkout o_select() find objects of a class Logical database — If you want to perform a query in parallel over a number of databases. o_newlogicaldb() Create a logical database. 445 . In a sense. o_removefromlogicaldb() Remove a database from a logical database. o_gcheckout() Get and check out a group of objects o_getclosure() Get a group of objects o_greadobjs() Get a group of objects o_locateclass() Get a class object o_locateobj() Get an object o_locatevsn() Get an object version o_refreshobj() Get a fresh object o_refreshobjs() Get fresh objects The remainder of this chapter is concerned only with functions that perform a search. but rather they are "get" functions. VERSANT Database Fundamentals Manual Mechanisms Find Object — The following functions find objects by using a search condition. Get Object — The following functions use handles. or pointers to retrieve objects. you can use the following functions to create and manage a logical database: o_addtologicaldb() Add a database to a logical database. o_deletelogicaldb() Delete a logical database.

such as o_locateobj() or o_greadobj(). such as o_pathselect(). Let's examine this function conceptually. VERSANT evaluates "find" queries on the server machine containing the database to be searched. In the above. o_dbname dbname. o_bool iflag. or a specific group of objects. you can send the same search query to numerous databases. In a query. o_vstr predicate ). ("Get" functions are evaluated on a client machine and can fetch objects from any connected database. Starting point objects — A query evaluates a group of objects known as the "starting point objects. allow you to query over a specific group of objects. a select operation returns a vstr of links to the objects that satisfy the query conditions. Return value — A query returns links to objects that satisfy the query: the objects themselves are not passed from the server database to the client application. the syntax of o_select() is: o_vstr o_select( o_clsname classname. After evaluating the starting point objects.) iflag Inheritance specifier: specify TRUE to evaluate and return instances of both the class and its subclasses or specify FALSE to evaluate and return only instances of the class. To actually use a returned object. you must use a link to bring it into memory with a "get" function. classname Name of a class. Other functions. dbname Name of a database. the lock that you specify in the lockmode parameter will be placed on the class object for the returned objects. and then use a "get" function to retrieve them as desired. you will usually want to set an intention read lock on a class. a class and its subclasses. For example. so the starting point objects must be located in a single database. Lock mode — By definition. In the above. which prevents the definition of the class from changing while still allowing other users to use instances of the class in a normal manner. However." The starting point objects may be a class of objects. a query can expand outwards to examine attribute values in embedded objects and linked objects. o_lockmode lockmode.VERSANT Database Fundamentals Manual Structure Parameters — The functions that search for objects require specifications of various parameters. the starting point objects are specified by the following parameters. store the returned links in a vstr. For 446 .

To express how predicate terms are to be collectively applied. or a set operator. A comparison operator can be a relational operator for comparing scalar values. 447 . and NOT. a pattern matching operator for comparing strings. Query key value (the key and keytype parameters) — A "key value" is the value to which a specified attribute is compared. Let's examine this structure conceptually. a starting point object is returned only if a valid leaf attribute is found and the value found in the leaf attribute satisfies the specified search condition. } o_predterm. Query comparison operator (the oper parameter) — A "comparison operator" determines how an attribute value is compared to a key value. A predicate term specifies: • An evaluation attribute • A comparison operator • A key value • An optional logical path statement. boolean operators. The syntax of the o_predterm data type is: typedef struct o_predterm { o_attrname attribute. non-ambiguous way that is understandable to a database. The remainder of this section discusses predicates and predicate terms. an "is-a" operator for determining class membership. Evaluation attributes must be specified in a precise. or a value for any type of attribute allowed in a query. A key value can be a link. o_bufdesc key. OR. Predicate Term In C/VERSANT. o_typetype keytype. VERSANT Database Fundamentals Manual information on locks and how they are applied to class objects. Allowed boolean operators are logical AND. Query logical path statement (the flags parameter) — A "logical path statement" determines how to handle cases where leaf attributes (the attribute being evaluated) are null or where there are multiple leaf attributes for a particular starting point object. Query evaluation attribute (the attribute parameter) — The "evaluation attribute" is the attribute whose value is to be examined. see the chapter "Locks". o_opertype oper. Predicate — A predicate is a vstr of pointers to search conditions called "predicate terms". predicate terms are structures of type o_predterm. links. By default. o_u4b flags. The real action of a find function happens in the predicate term. they are concatenated into a predicate using logical.

448 . a predicate term looks like this: Predicates — Predicate terms can be used alone as a predicate or concatenated to form a multi-part predicate.VERSANT Database Fundamentals Manual Predicate Term — Conceptually.

The following discusses predicate term attributes. Evaluation and Key Attributes An "evaluation attribute" is the attribute whose value is to be examined. The following explains the attribute types allowed and how to specify an evaluation attribute. comparison operators. predicate terms can be concatenated with other predicates. char o_1b o_2b o_4b o_8b o_double o_float o_u1b o_u2b o_u4b o_u8b 449 . you can use the following types of attributes when specifying a search condition: Many elemental C types with a repeat count of 1. A "key value" is the value to which a specified attribute is compared. VERSANT Database Fundamentals Manual Also. and path statements in detail. Attribute Types Allowed Query attribute types allowed — In search functions.

o_object. vstr of char vstr of o_1b vstr of o_u1b Links of type o_object. Do not use other types of Do not use fixed arrays of types other than char. you cannot struct use Vstr<Employee>. Do not use an embedded Do not use an embedded class or struct with a fixed length that class or struct with a fixed embeds another fixed array. o_date o_interval o_time o_timestamp Attribute Types NOT Allowed You cannot use the following types of attributes in a search method: Do not use enum You should not use enum. Do not use other types of Do not use vstrs of types other than char. For example. length Do not use vstrs of class or Do not use vstrs of class or struct types. you cannot use o_4b pixel[5]. o_object vstr of o_object Vstrs containing links. o_1b.VERSANT Database Fundamentals Manual Many fixed arrays of one byte elemental types. Fixed array of o_object For example: o_object names[20] Date and time types. and vstrs. class or struct. fixed arrays and links. o_1b. Fixed arrays of links. as it is not portable: some machines implement enum as o_2b. fixed array of char For example: char firstname[20] fixed array of o_1b fixed array of o_u1b Some vstrs of one byte elemental types. For example. o_u1b. 450 . while others implement enum as o_4b. o_u1b.

suppose that Employee has a worksIn attribute that points to a Department object. Precise attribute names are needed. 451 . then the database names for these attributes are: Base::id Base::code Derived::value Name of a link attribute The database name for a link attribute is: classname:attribute_name For example. if attributes id and code are in class Base and attribute value is in class Derived. Name of an elemental attribute The database name of an elemental type attribute is: Class_name::attribute_name This form should be used even when an attribute is used in a derived class. Even if there is no initial ambiguity. If you specify an attribute by name. you must use a special. VERSANT Database Fundamentals Manual Attribute Specification by Name You can specify an evaluation attribute by name or by path. non-ambiguous. classes may later be created which do cause ambiguity. Following are attribute name rules required by VERSANT for each type of attribute that may be used to query or index. For example. database syntax for the name. because a derived class could conceivably inherit attributes with the same name from numerous superclasses along one or more inheritance paths. The database name for the attribute is: Employee::worksIn This form should be used even when an attribute is used in a derived class.

if Department has an attribute named employees to hold department members that is a vstr of o_object. 452 . including an embedded class or embedded struct type. The attribute names used in the database include the subscript inside of brackets. and o_object with two or more fixed length dimensions are flattened into discrete attributes. or o_object is: classname::attribute_name For example.ClassB::attributeB The name ClassA::embeddedObject. The general form is: class::attribute_name[0] class::attribute_name[1] class::attribute_name[. For example. Then the database name of attributeB in embeddedObject is: ClassA::embeddedObject. whether in ClassA or in a class derived from ClassA. For example. which is given to the database as a repeat count for each database attribute. The attribute attributeB can itself be of any type. then the database name for the attribute is: Department::employees Name of a class or struct attribute Embedded attributes of struct or class data types are flattened into simpler individual attributes.. suppose that embeddedObject is an attribute of ClassA and is of type ClassB. o_u1b.VERSANT Database Fundamentals Manual Name of a fixed array attribute Fixed arrays of char. if a struct Date and struct Base are specified as: struct Date { int day. }.] class::attribute_name[n-1] This form should be used even when an attribute is used in a derived class.ClassB::attributeB must be used to refer to the embeddedObject attribute wherever it appears. Base b. o_1b. o_1b. Name of a vstr attribute The database name of an attribute that is a vstr of char. Also suppose that ClassB has an attribute named attributeB. except for the last dimension.. o_u1b.

are called "non-leaf" names. int code. is called the "leaf name. membership. we can specify it with the path from Person to colors using \t: Person::garages\tGarage::cars\tCar::colors This is conceptually similar to specifying the colors attribute by name as: Person::garages->Garage::cars->Car::colors The last name in the attribute path. VERSANT Database Fundamentals Manual struct Base { int id. Now suppose that we want to search over the Person class for people with cars of a certain color. }." By definition. As with names. When you use a path name for an attribute to be examined: • All objects involved must be in the same database • All non-leaf attributes must be a link. In ODMG. Attribute Specification by Path You can specify an evaluation attribute with a path name rather than an attribute name. this is called a "path expression. 453 . The general syntax for a path expression is a listing of the attribute names on the path to the attribute to be examined. suppose that a class Person has a links attribute garages whose domain is class Garage. For example. in this case colors. to specify the attribute colors in a predicate.Base::id Date::b. and set operators to make comparisons between a key value and an attribute specified with a path. with the names on the path delimited with \t.Base::code Query Attribute Names Not Allowed You cannot query on an attribute whose name contains an ASCII TAB character. Then. Suppose also that class Garage also has a links attribute cars whose domain is class Car. you can use relational." The intermediate names. or link vstr. decimal value 9. a "patch expression" specifies a path through several interrelated objects to access a destination object. match. in this case garages and cars. and that class Car has an attribute colors. Then the database attribute names are: Date::day Date::b. link array.

A comparison operator can be a relational operator for comparing scalar values. or a set operator for comparing sets. you can also return objects linked to the starting point objects to a specified level of closure.VERSANT Database Fundamentals Manual • The comparison operator must be a relational operator or a set operator. Comparison Operators A "comparison operator" determines how an attribute value is compared to a key value. • The attribute path can include any number of steps to the final attribute. The following of links to a particular level of closure is unrelated to the following of a path to a leaf attribute. an "is-a" operator for determining class membership. • Once the starting point objects have been returned. possibly containing wildcards 454 . • Only starting point objects can be returned from a query using paths. Relational operators Compare scalar values — Evaluation attribute a scalar value Key attribute a scalar value Operator Evaluation attribute is: O_EQ Equal to key value O_NE Not equal to key value O_LT Less than key value O_LE Less than or equal to key value O_GT Greater than key value O_GE Greater than or equal to key value String operators Compare strings — Evaluation attribute a string Key attribute a string. Objects encountered along the path cannot be returned. a pattern matching operator for comparing strings. • The starting point objects can be either the objects in a class or the objects in a link vstr or link array.

455 . inclusive. VERSANT Database Fundamentals Manual Operator Evaluation attribute: O_MATCHES Matches key string O_NOT_MATCHES Does not match key string Wildcards Match * Any sequence. [x-y] Any character between x and y. including an empty sequence. ? Any single character [chars] Any character in set. O_NOT_ISA_EXACT Is not a member of key class. Evaluation attribute an instance object Key attribute class name of a class object Operator Evaluation attribute O_ISA_EXACT Is a member of key class. \x Single character x (avoid wildcard interpretation of * ? [ ] in a pattern) Class operators Compare class memberships — These operators test whether an object is an instance of a given class. A null link returns true if flags is set to 0 and false if flags is set to O_EMPTY_TRUE. but they do not test whether the object is an instance of a subclass. A null link returns false if flags is set to 0 and true if flags is set to O_EMPTY_TRUE.

operator O_INTERSECT performs inquiries on those objects linking to some specific objects. operator O_NOT_INTERSECT performs inquiries those not linking to any of the given objects. O_NOT_SUPERSET_OF Does not contains all links that are in the key attribute (superset is false). O_SUBSET_OF Contains links that are all in the key attribute (subset is true). In reverse. operator O_INTERSECT checks whether found objects link to a set of specific objects. In a set query. For example. O_EQUIVALENT_SETS Contains the same set of links that are in the key attribute (equivalent is true). a "set query" compares sets of objects. O_SUPERSET_OF Contains all links that are in the key attribute (superset is true). except available heap space on both the client and server machines at the time the query is executed. the evaluation operator and the key attribute can be either a link or a set of links. Usage Notes • By definition. O_NOT_INTERSECT Contains no link that is in the key links (intersection of links is empty). O_NOT_EQUIVALENT_SETS Does not contain the same set of links that are in the key attribute (equivalent is false). O_NOT_SUBSET_OF Contains at least one link that is not in the key attribute (subset is false). 456 .VERSANT Database Fundamentals Manual Set operators Compare sets of objects — Evaluation attribute a link or set of links Key attribute a link or set of links Operator Evaluation attribute: O_INTERSECT Contains at least one link that is in the key attribute (intersection of links is not empty). • A sequence of queries provides the means of eliminating incongruent search outcomes as a result of ambiguous expressions caused by a multiple path query. For example. • There is no restriction on the number of links in the key attribute.

but is returned because she sells a red Ford and a blue Honda ("a red car" and a "Honda"). but we can easily construct a sequence of queries that will return the expected 457 . s2 This broker does sell a red Honda. v5} v2: white GM s4:{d2} v4: blue Honda v5: red Honda v6: red Honda Suppose that we want to select those brokers who sell a "red Honda". make Each broker works for some dealers. v3. v6} v2: blue VW s3:{} d3:{v2. To correctly get only brokers who sell red Hondas can become quite intricate if no set operators are used. it seems as if this request can be described in the VERSANT Query Language as: SELECT selfoid FROM Broker WHERE dealers->vehicles->color = "red" AND dealers->vehicles->make = "Honda" But the above query returns a broker who does not sell a red Honda: s1 This broker does not sell a red Honda. you can create a btree index on an attribute containing links. Each vehicle has attributes of color and make. Its performance can becomes an issue for a large starting class with complex relationship among classes along the navigation path as it requires an exhaustive traversal defined on the links from the given path expressions. Each dealer has certain inventory of vehicles. v4. s4 This broker does sell a red Honda. Assume the following objects in these classes in a database: Broker Dealer Vehicle s1:{d1} d1:{v1. A query with path expressions uses a Depth-First-Fetch approach to evaluate each path expression. Example For the following example. v4} v1: red Ford s2:{d3. d2} d2:{v2. assume that we have the following three classes and attributes: Classes Attributes Broker dealers(linkvstr) Dealer vehicles(linkvstr) Vehicle color. At first. VERSANT Database Fundamentals Manual • To improve the performance of a query involving links.

458 . get the brokers who represent dealers with red Hondas. SELECT selfoid FROM Broker WHERE dealers INTERSECT Dealers_red_Honda Predicate Term Concatenation When multiple predicate terms and/or predicates are used in a search query. operator O_NOT binds tightest and O_OR binds weakest. which is a collection of the logical object identifiers of all dealers who have "red Honda" in their inventory: SELECT selfoid FROM Dealer WHERE vehicles INTERSECT Vehicles_red_Honda Note that we use operator INTERSECT to find all dealers having a vehicle in Vehicles_red_Honda in their inventory. incidentally. they are concatenated with logical operators. using reverse traversal and reverse joins: 1. First. Next. which is a collection of the logical object identifiers of all red Hondas in inventory from all dealers: SELECT selfoid FROM Vehicle WHERE color = "red" AND make = "Honda" 2. get all dealers who have a red Honda.VERSANT Database Fundamentals Manual outcome if we use set operators. Let Vehicles_red_Honda be the result of the following query. Finally. get all red Hondas. Let Dealers_red_Honda be the result of the following query. get better performance. The following boolean operators can be used to logically join predicate terms and predicates: O_AND logical AND O_OR logical OR O_NOT logical NOT Per precedence rules. (And.) Here is one way to get only brokers who sell red Hondas. 3.

459 . For example. For example. then for Henry the predicate evaluates true. A query's value test occurs in its predicate. but when you are phrasing some kinds of queries. • The comparison operator specified is appropriate for comparing the data types of the evaluation attribute and the key value." For example. are all of your Porsches red? In this case. This means that a search with numerous link arrays as intermediate steps can involve a large number of paths and a large number of objects. If you ask for all persons with a red Porsche ("Porsche = red"). • A link may point to an object in another database. • The data type of the evaluation attribute is such that it can be compared with the key value specified in the predicate. • The attribute may not be the same type as the key value. • A link may point to an object that has been deleted. When you consider paths. suppose that Henry has a red Porsche. There are many reasons a particular path can be "incomplete. the number of object paths searched using intermediate arrays or vstrs of links can expand to any number. if you have no Porsches. Most of the time you can ignore the path test. VERSANT Database Fundamentals Manual Logical Paths When you specify an attribute path. you may need to consider paths. Logical path statements are a way of being more precise about search conditions. A predicate is said to be "true" if an attribute has a value that meets the search condition expressed by the comparison operator and the key value. A query's path test occurs in its logical path statement. • A leaf or non-leaf object might not have the attribute named. • A link in a non-leaf attribute may be NULL. the answer depends upon your logical path statement. the following things can go wrong when a query attempts to follow a particular actual object path. a query can represent both a value test and a path test. A particular path is said to be "complete" when all of the following are true: • The path can be followed all the way from a starting point object to an evaluation attribute. • The operator may not be valid for the leaf attribute.

O_EMPTY_TRUE Return a starting point object if there exists one complete path with a true predicate OR if no paths are complete. by default. This option is the same as "exists" except that you also get the starting point object if there are no complete paths. The following principles form the basis of the logical evaluation of paths: • Incomplete paths are ignored. 0 ("exists") Return a starting point object if there exists one complete path for which the predicate evaluates true. • If complete paths > 1. It does not ignore complete paths whose predicate is false. Notice that this option ignores incomplete paths. then you get the starting point object only if your predicate is true. you also get people with no cars. then you get the starting point object only if all predicates are evaluated as true. For example. This option is the default. • If complete paths = 0. You can combine the above flag options with the | operator. This option ignores incomplete paths. then you get the starting point object only if you also ask for "empty succeeds. you get the starting point object if at least one predicate is true. In C/VERSANT. • If complete paths > 1 and you also ask that "all paths" be evaluated.VERSANT Database Fundamentals Manual VERSANT allows you to specify what happens when paths are complete or incomplete. then the first attribute in the attribute path must exist on the class which is selected on. O_ALL_PATHS Return a starting point object if there is at least one complete path and if all complete paths have a predicate that evaluates true. then the remainder of the query is performed per the 460 . A useful combination is the following. logical path conditions are specified as a parameter. Exceptions • If recursion has been turned off. if you ask for people with red Porsches." • If complete paths = 1. O_ALL_PATHS | Return a starting point object if there are no complete paths ("empty O_EMPTY_TRUE succeeds") OR if all complete paths have a predicate which evaluates true. The only test is whether there is one complete path whose predicate is true. or else the query returns an error code regardless of option selected. If the first attribute in the path exists. Also ignored are complete paths whose predicate evaluates false. then. Following are options for logical path conditions.

461 . Example For example. or else the query returns an error code. VERSANT Database Fundamentals Manual option selected. and that a garage can be associated with more than one car. • If there is only one attribute name in the attribute path. we will test whether a person has a red car. In this example. suppose that a person can be associated with more than one garage. blue All Jan blue All Ned none None In the following. The cases are: Person Colors Complete paths Sue red Some (2 out of 3) Rob red. Suppose the following cases. then in all cases the comparison operator must apply to the data type found there. consider the example of persons who have garages which have cars which have colors.

Rob Returned One path to red. Rob Returned One path to red. the results are: Test — There is at least one complete path to not red. Jan Returned One path to blue. Ned Returned There are no complete paths. Ned Not returned There is no complete path. Test for NOT red If you evaluate for not red (!= "red").VERSANT Database Fundamentals Manual Test for red If you evaluate for red (= "red"). Jan Not returned Two complete paths. Rob Not returned Four complete paths. Path condition = O_ALL_PATHS | O_EMPTY_TRUE Results: Sue Returned All complete paths are red. and all complete paths are red. Jan Not returned One complete path is not red. 462 . Test — All complete paths are red OR there are no complete paths. Path condition = O_ALL_PATHS Results: Sue Returned Two complete paths. Ned Returned There are no complete paths. Jan Not returned No path to red and at least one path is complete. Path condition = O_EMPTY_TRUE Results: Sue Returned One path to red. Ned Not returned No path to not red. Test — There is at least one complete path. Rob Not returned One complete path is not red. Ned Not returned No path to red. and all complete paths are red. Rob Returned One path to blue. Test — There is at least one path to red OR all paths are not complete. Path condition = 0 Results: Sue Not returned No path to not red. Jan Not returned No path to red. Path condition = 0 Results: Sue Returned One path to red. but one complete path is not red. but all complete paths are not red. the results are: Test — There is at least one complete path to red.

Path condition = O_ALL_PATHS Results: Sue Not returned All complete paths are red. Jan Returned All complete paths are not red. Ned Returned All paths are not complete. Ned Returned There are no complete paths. 463 . Jan Returned Two complete paths. Rob Not returned One path to red. and all complete paths are not red. Path condition = O_ALL_PATHS | O_EMPTY_TRUE Results: Sue Not returned One complete path is red. Rob Not returned One complete path is red. but no path to not red. Rob Returned One complete path to not red. Ned Not returned There is no complete path. and all complete paths are not red. Test — There is at least one path to not red OR all paths are not complete. Jan Returned One complete path to not red. VERSANT Database Fundamentals Manual Test — There is a least one complete path. Path condition = O_EMPTY_TRUE Results: Sue Not returned Two complete paths. Test — All complete paths are not red OR there are no complete paths.

General Rules Indexes do not have names. The type of structure that you want to use depends upon the types of queries you will be making. There are two kinds of index structures: b-tree and hash table. indexes are maintained automatically. It is a list of pairs consisting of key values and associated object identifiers. Create and update routines can use indexes to enforce uniqueness constraints on attribute values. Once created. 464 . Index constraints There are two kinds of index constraints: "normal" and "unique. only their organization is different. Indexes are maintained automatically.VERSANT Database Fundamentals Manual Search Query Indexes Concepts Index purpose Indexes allow routines that query. This can improve query performance in many situations. you can use either a b-tree or hash table structure. and deletion of instances. updating. Index structure An index is set on a single attribute of a class and affects all instances of the class. which means that they may somewhat slow the creation. create." A "normal" index places no constraints on attribute values. The only difference is that when you create the index. you specify that you want unique values. If you want to create a unique index. Query routines can use indexes to filter objects so that only objects of interest within a specified range are fetched from disk. Both types of structures maintain a separate storage area containing attribute values. A "unique" index requires that each instance of a class has a value in the indexed attribute that is unique with respect to the values in that attribute in all other instances of the class. and update objects to have quick access to the values of a particular attribute of a class.

a b-tree index (normal or unique) and a hash table index (normal or unique). In other words. When you create an index. 465 . To index subclass attributes. An attribute can have up to two indexes. Each database has its own indexes. and index behavior as the source database. For example. This is important to remember if you are using multiple inheritance and/or are querying over members of a class and its subclasses. then you may get anomalies. the class definition. The actual creation of an index does not occur until the current short transaction is committed. When you migrate an object to a database in which its class is already defined. you need to specifically set indexes on each subclass. suppose that you have the following schema. Attributes can have two indexes. The general caution is that if you use multiple inheritance but treat inheriting classes separately. the migration will fail if the target database does not have the same class definition. index definition. VERSANT Database Fundamentals Manual Indexes must be committed. and index behavior are also migrated. When you migrate an object to a database in which its class is not defined. An index is set on one attribute in one class. that index is created on an attribute of a class and not on an attribute in any other class. Each database has its own set of indexes. index definition. indexes are not inherited.

and Intern. a uniqueness check on id is not made.VERSANT Database Fundamentals Manual In the above. o_object Note — A unique BTree index cannot be created on o_object data types. For example. If you set an index on id in Person and then perform a query on Employee. o_float. class Person has an id attribute that is inherited by several subclasses. Attribute Rules Attributes that Can be Indexed You can index on the following types of attributes: • Elementary types with a repeat count of 1: char. if you set a unique index on id in Employee. Developer. in the above. o_u1b. You can set a unique BTree index on the C++ link and link vstr types so that arrays of links can be used for query operations on sets of objects. o_8b. o_1b. 466 . Similarly. o_4b. o_u8b. Cursor queries use indexes in the same way that other queries do. Because indexes are set only on one attribute in one class. then when you create a new Developer. enum. o_u2b. o_2b. then the index on Person is not used. if you set an index on Person. Employee. o_double. o_u4b. you should set corresponding indexes on all classes that have an inheritance relationship. then set the same index on Customer. Indexes should be consistent.

For example: char firstname[20] • Vstrs of the following elemental types: o_1b. 467 . For example: o_4b pixel[5] • Embedded struct with a fixed length. and o_object. -icbu Create unique b-tree. either normal or unique. o_u1b. o_interval. except for o_1b. -idh Delete hash table. and o_object. o_u1b. • Vstrs of elemental types except o_1b. and char. Attributes that Cannot be Indexed You cannot index on the following types of attributes: • Elementary fixed arrays with a repeat count. and char. -ichu Create unique hash table. char. o_u1b. o_1b. o_u1b. -ich Create hash table. -idb Delete b-tree. • Lists of type o_list. either normal or unique. o_time. -il [cls[attr]] Print index information. • Date and time types: o_date. VERSANT Database Fundamentals Manual • The following elementary types with a repeat count: char. • Vstrs of objects of struct types. Index Utility The dbtool utility has the following index options: -icb Create b-tree. o_deleteindex() Delete a b-tree or hash index. and o_timestamp. The indexed attribute can have a maximum size of 2k bytes. Mechanisms Index Functions o_createindex() Create a b-tree or hash index.

A b-tree index is useful for value-range comparisons. and a hash index is useful for direct comparisons of values. if a query evaluates a class and its subclasses. generally a hash table is better. If you use no indexes. a quarter or less of all instances. If you have a large number of objects and want to return. O_IT_BTREE b-tree O_IT_UNIQUE_BTREE unique b-tree O_IT_HASH hash O_IT_UNIQUE_HASH unique hash Query Costs One of the costs of a query is fetching data pages from disk so that the server process can evaluate objects. Alternately. subclasses. A b-tree index will return objects in ascending order. say. a query will fetch all data pages for a class and evaluate all objects in a single pass through the data pages. applying the predicate happens quickly.VERSANT Database Fundamentals Manual Index Options In routines that create and delete indexes. access the returned vstr or array from its end rather than beginning. or dropped. changed. following are options for the type of index. otherwise. 468 . to access objects in descending order. The tradeoff is improved query speed versus index overhead. which means that the set of all objects are not necessarily in ascending order. Once objects are in memory. and links for queries that evaluate substructures. If you will only be making equality comparisons. However. then an index can improve query performance. This approach optimizes the disk fetch and is appropriate if you want to return a relatively large proportion of the instances of a class. use a b-tree index. Following is additional detail on how indexes are used. they may be set on a first-level attribute used frequently as a search condition or on logical object identifiers. An index might logically be set on attributes related to domains. as indexes are automatically updated when objects are added. objects are returned in ascending order in each subclass.

O_EQUIVALENT_SET Set equal to Can use a b-tree index. If there are both kinds of indexes on the evaluation operator. O_NOT_SUBSET_OF Set not subset Does not use an index. if the key string to be compared does not start with "*" or "?". O_NE Scalar not equal to Does not use an index. O_NOT_SUPERSET_OF Set not superset Does not use an index. O_ISA_EXACT Class is same as Not relevant. O_NOT_EQUIVALENT_SET Set not equal to Does not use an index. • The evaluation attribute has an index on it. Scalar relative to Can use a b-tree index. O_GE. O_SUPERSET_OF Set superset Can use a b-tree index. • The comparison operator is appropriate to the type of index. The following types of comparison operators can use the following types of indexes. O_LE O_MATCHES String equal to Can use a b-tree index." A predicate term is indexable if all of the following are true. O_EQ Scalar equal to Can use either a hash or b-tree index. • The evaluation attribute is not expressed in terms of a path. O_INTERSECT Set intersection Can use a b-tree index. the hash index will be used. O_GT. 469 . VERSANT Database Fundamentals Manual Indexable Predicate Term The system optimizer will automatically use an index in a query if a predicate term is "indexable. O_SUBSET_OF Set subset Does not use an index. O_LT. O_NOT_INTERSECT Set not intersection Does not use an index. O_NOT_MATCHES String not equal to Does not use an index. O_NOT_ISA_EXACT Class is not same as Not relevant.

then no object satisfies the predicate. Range predicate By definition. If the index is not unique. Exact match predicate By definition. or link vstrs. This continues until either the upper boundary. is reached. evaluated. a query with a range predicate traverses a b-tree index searching for an entry on a leaf page whose key value is greater than or equal to the lower bound. If the index is a unique index. A query with an exact match predicate will traverse a b-tree index on an attribute starting from the root page down through interior node pages. or the last leaf page has been processed. then all objects with the key value are retrieved. if any. each object has an entry on a leaf page of the b-tree. further evaluated. and returned if it satisfies all predicate terms. array of link. then the object is retrieved into server memory from the corresponding data page whose location is stored inside the entry for the key value. As in the exact match case. If the key value cannot be located. Predicate using a set operator A set predicate has the form: attribute set_operator key_links where attribute has the type: link. If there are other predicate terms.VERSANT Database Fundamentals Manual Query Evaluation and B-tree Indexes A query can use a b-tree index in an exact match or range predicate. 470 . to a leaf page with an entry for the key value. an exact match predicate has the form (attribute == key_value). the query is finished. as each entry that matches the range predicate is found. and returned if they satisfy all predicate terms. a range predicate has the form (attribute >= lower_bound and attribute <= upper_bound). An exact match predicate is a special form of a range predicate where the lower_bound is the same as the upper_bound. the retrieved object is further evaluated and returned to the application if it satisfies all predicate terms. its corresponding object is retrieved. the query follows the next pointer of the doubly linked entries to the right-hand neighbor and resumes sequential processing with the first entry. and the query is finished. If the last entry of a leaf page is processed and the upper bound has not been reached. Like the exact match case. These leaf pages are sorted on the b-tree attribute and doubly linked. When a b-tree index exists. u. If an entry for the key value is found.

are likely to remain in the buffer cache. Query with terms concatenated only with AND Suppose you have a predicate such as: ( A and B and C and . or O_EQUIVALENT_SETS are used. index pages are brought into memory and read sequentially on its leaf pages. The B-tree index can then be used to drive the predicate evaluation. reducing the time and resource costs because the number of links in key_links is generally much smaller than the number of links in the class.. such as the root page and its directly descendent interior node pages. If an index value satisfies the predicate term. O_SUPERSET. B. the cost of b-tree overhead for a query includes a couple of node pages down the traversed path. frequently referenced pages. then the data page for the corresponding object is fetched. In this case. the targets to be examined can be reduced by searching the B-tree index from key_links.. Query with a single predicate term Suppose that your predicate consists of a single predicate term. and that it is indexable. VERSANT Database Fundamentals Manual The operator options for a set_operator are: O_INTERSECT O_NOT_INTERSECT O_SUBSET_OF O_NOT_SUBSET_OF O_SUPERSET_OF O_NOT_SUPERSET_OF O_EQUIVALENT_SETS O_NOT_EQUIVALENT_SETS If the operators O_INTERSECT. Query Usage of Indexes Various types of queries use indexes differently. and a list of leaf pages covered by the key values. In this case. then all objects will be fetched and evaluated in a single pass through 471 ." such as color=="Red" or age>=65 . and C.. When a query traverses a B-tree index.. are "terms. As a result. a B-tree index can be created on the attribute. Instead of scanning the entire class. the query terms will be read from left to right. If none of the terms are indexable. ) where A.

If an index value satisfies the predicate term. evaluating the query on each object (with shortcut optimization when an orterm is true or a term inside an orterm is false). and an index is used to traverse each orterm in succession. index pages for that term will be brought into memory and read sequentially. To avoid having it used as the access path. such as (sex >= 'M' and sex <= 'M'). In this case. its components will be evaluted left-to-right per the following discussion. and then move it to the right end of your predicate. such as (sex=='M'). If your query has to be converted to disjunctive normal form. then the entire query is indexable. If there is only one indexable term. and the object is evaluated further. If an index value satisfies the indexable term. where A. If you write your query in this form to begin with. then the terms will be evaluated to determine which one to use. you can phrase your query to use the indexable term that you want. you can rewrite this term as a range predicate. and that all objects in the result set are not necessarily sorted in 472 . DeMorgan's rules and the distributive rule of boolean algebras will be applied.. then the first term using the equals operator. then the entire class extent will be walked. one object at a time. If any orterm lacks an indexable term. If any of the indexable terms uses the equals operator. (The reasoning for preferring the equals operator is that it will likely produce fewer objects for evaluation. suppose that you have an indexable term with an equality operator. because if all objects need to be evaluated. If each orterm has at least one indexable term. are "terms" and groups like (A and B and C) are called "orterms". C. which means that mathematical conversions are done so that the query is expressed in a left-to-right format such as: ( A and B and C ) or ( D and E ) or ( F ) . This means that objects in each orterm are returned in ascending order with respect to the index attribute.VERSANT Database Fundamentals Manual the data pages. then the data page for the corresponding object is fetched. will be used. reading from left to right. then the first term found. Knowing that access paths are chosen with left-to-right. reading from left to right. then the data page for the corresponding object is fetched. Query with terms concatenated with OR If your query uses terms concatenated with the OR operator. then the index pages are brought into memory and read sequentially from its leaf pages.. If none of the indexable terms use the equals operator. If there are multiple indexable terms.) Once an indexable term is chosen. then what happens is more complex.. but the basic left-to-right ordering of elements in your query is preserved as much as possible. B. First your query is converted to disjunctive normal form.. For example. is used. and the object is evaluated further using the rest of the predicate te