Although it seems like ages ago, I can still distinctly remember my training in the navy ı after the free and easy days at college and the relaxed life at home, where you knew your room and the relational-like layout of your neighborhood streets and avenues. When we arrived at the drab collection of buildings on the desolate, barren west coast, we were told: "Sailors, this is a ship." "Aye, sir!" (all at once). We were instructed: "Sailors, make your bunks (beds), clean the scuttles (windows), dust the bulkheads (walls), polish the deck (floor), and clean the heads (toilets)." "Aye, sir!" (all at once). And if you missed any little detail, you were called aft to the quartermasterıs lobby, which incidentally was at the center of the "brick ship." We did some really strange things ı we ironed our bed covers sopping wet onto the bed to make them square, and we walked on little cloths called taxis to keep the deck shining. We were taught about some very strange things and most of these new things had very, very strange names, not to mention the "names" you had to call people. Talk about a paradigm shift! It was adapt or die ı or so I felt.
I am sure there are many DBAs like me with a relational database background who now have to make the change over to object-oriented databases as they become more accepted by the mainstream. In this monthıs column I review the Versant 5.0 ODBMS from Versant Object Technology Corp. Because most reviews of object databases focus on object-oriented application development, I review Versant from the perspective of a traditional relational DBA. We are used to creating databases with tablespaces and physical database extensions, normalized tables to hold the data, indexes to improve the usersı response times, checkpoints and journals for backups, grants for security, triggers, and stored procedures, and so on. Armed with our relational experience, letıs take a trip through the uncharted waters of managing object-oriented databases.
I expected a strange world. But unlike my first encounter with the armed forces, my first encounter with the Versant 5.0 ODBMS was not traumatic. A Versant database, similar to a relational database, is just a collection of related data managed by a database server and administered by a DBA. Obviously, on a detailed level, there are many differences.
Versant employs a conventional client/server architecture, as illustrated in Figure 1. Client applications link to and communicate with a Versant manager on the client platform through language-specific interfaces. The Versant manager communicates with the Versant database server through TCP/IP and routes the clientıs queries to the server. The server executes the queries and provides the requested objects to the clients via the Versant manager. The Versant manager consists of a few software modules that perform object caching, object validation, transaction and session management, schema management, and checkouts and checkins. The Versant server performs query execution, object retrieval and updating, page caching, indexing, logging, and locking.
Most RDBMSs implement a server-centric architecture in which all the database processing functions are executed by the database server process. Versant employs a "balanced" client/server implementation. Some database management functions such as transaction control are performed on the client, while other functions such as query execution and indexing are performed by the server. Certain functions, such as dual caching, are performed at both ends in an attempt to reduce network traffic.
Each Versant installation has a software root directory under which the Versant server software executables and database management utilities are stored and a database root directory under which all the databases are created. Each database is created in a database directory under the database root directory.
A Versant database consists of a number of storage volumes, which are files or raw disk devices. Each database consists of one system volume, one logical log volume, one physical log volume, and zero or more additional data volumes. The system volume is typically located in the database root directory. It is used to store class descriptions (metadata) and object instances (the data itself). The log volumes are used for transaction and longer-term rollback and recovery. They are usually located in the database root directory. The additional data volumes can be used to increase the databaseıs capacity.
When you create a new Versant database, you have to make it, edit its profile, physically create it, and then (optionally) expand or move it. Making a database entails creating a database directory, assigning the necessary access privileges, and creating the database profiles. The Versant makedb utility can make a default database. If you want to change any of the databaseıs physical characteristics, you have to edit its profile, which is stored in a file within the database root directory. There are lists and lists of parameters defined in the database profile, such as volume sizes and file locations, application process parameters, and server process parameters. The physical database is created by running the Versant createdb utility, which creates the system and log volumes, and updates the network database identifier file to indicate the presence of a new database.
The user that created a Versant database is considered the owner and DBA of that database. Only the DBA can perform certain administrative tasks, such as adding and removing users, and only the DBA may remove a database. There can be many different DBAs working on different databases in a Versant installation.
The directory structures Versant uses are not unlike those used by many relational DBMSs, but the creation of a database has an extra step to first "make" the database.
A Versant database models data as objects. A database object that holds data is called an instance object. Each object has a class, which defines its structure. A Versant database can have any number of classes, and any number of objects per class. When you create a class, Versant creates a corresponding class object in the database. The attributes of an object can be used to store any datatype, such as numeric and character values, images, sounds, documents, and references to other objects, as defined in the class. An object can contain other objects with their own attributes, or even arrays of other objects. The object attributes are generally defined in C++ class files, which are then compiled and loaded in the database, where they are stored as class objects. An object also has methods, which are executable units of program code associated with the object. The methods are usually defined in C++ class files, which are then compiled and linked with the applications. Each object has a unique logical object identifier, made up of a database identifier and an object identifier. A logical object identifier always points to the same object, and it can never change its value.
Versant keeps track of a number of states for each object. An object can be transient or persistent, where only persistent objects are saved to the database and can be locked to guarantee access to it. It can have a dirty state, which means it has been changed, but not yet saved. An object can be checked out, which means that a user has set a long-term lock to work on the object for longer than the duration of a transaction.
You can convert an instance object to a versioned object. This instructs Versant to keep track of the changing states of the object by keeping a graph of the versions of the object. When updating a versioned object, the changes are automatically saved as a new version and linked to the version of the object to which the changes were made.
You can use the Versant Multimedia Access (VMA) module to load multimedia files into a Versant database as text, audio, image, video, URL, or application-specific C++ classes. VMA includes a run-time version of the Verity SEARCH ı97 engine, which automatically creates and maintains indexes for each managed database. You can extend the predefined classes to create custom classes, and you can create custom interfaces using the Verity Software Development Kit.
Just as the command "full kit" meant trouble to a sailor, object modeling can mean trouble to a relational DBA. You have to change your way of thinking about data modeling. It is better to design the database in terms of objects, classes, and inheritance than to find analogies for the known relational concepts. For example, it is difficult to determine the equivalent of a referential integrity constraint. The relationships between Versant objects are not trivial. An object can contain other objects, it can contain structures, such as arrays of other objects, or it can contain "is a" (inheritance) or "has a" (association) references to other objects. Object versions and object states are also two powerful and useful concepts to get used to.
Versant databases are used mostly with object-oriented programming languages that implement classes or templates and support delegation or inheritance. Versantıs language-specific interfaces map the capabilities of the programming language to the object database model. Each language interface consists of several libraries and precompiled routines.
Versant release 5.0 has language-specific interfaces for C++, Smalltalk, and Java, but it can also be used with standard nonobject-oriented C. The C++/Versant interface implements the full object model. The C/Versant interface does not support messaging, so the methods are executed as functions, and you have to use the Versant View utility to view and edit class definitions. The Smalltalk/Versant programming interface consists of a set of Smalltalk classes that maps the Smalltalk objects directly to the Versant database objects. For example, when you retrieve an object from a Versant database, it is placed in the Smalltalk Image as a standard Smalltalk object. The Java/Versant interface gives you access to the data storage primitives of the Versant database, including schema definition and access; object creation, deletion, and update; value-based and navigational query; full transaction support for distributed databases; and object sharing with other languages. Versant plans to ship a release with more extensive Java support toward the end of this year. A DBA will be able to extend the functionality of the Versant Server with user-written methods. The release will also have a pure Java interface, which would allow pure Java applications to access all of the features of Versantıs object database via standard or user-defined transport protocols.
A Versant query starts with a group of so-called "starting point objects," which may be a class of objects, a class and its subclasses, or an array of objects. After evaluating the starting point objects, the query can examine the attribute values in embedded and linked objects. There are basically two types of queries: dereference queries, which load objects from their links into memory, and search queries, which find objects and return their links. You can specify predicates in the search queries to locate specific objects. In the C++/Versant, Smalltalk/Versant and Java/Versant interfaces, there are quite a number functions that you can call to perform dereference and search queries. Some of the C++/Versant functions enable you to process the object instances through a cursor.
Versant (the company) is a founding member of ODMG, and Versant (the ODBMS) supports a subset of the ODMG 2.0 Object Query Language (OQL) released in mid-1997; it also supports OQL bindings to C++ and Java. Versant also has its own proprietary high-level Versant Query Language (VQL). Queries expressed in a SQL-like syntax are assigned to strings, which are parsed and executed using C++/Versant or C/Versant routines. VQL contains a number of extensions to SQL that cater to object-oriented concepts. An example is the only keyword in the from clause to restrict the query to the class named in the clause. Without the only keyword, the classıs subclasses will also be inspected.
Queries in Versant, like objects and classes, are a lot different from those in a relational DBMS, but that is to be expected. However, although the syntax is different, cursor processing in Versant is similar to its counterpart widely used in relational database applications. Cursors are very useful for accessing a large volume of objects without excessive locking and long wait times.
Versant/SQL Suite is an amazing knapsack of tools for relational DBAs (and users) to tackle Versant databases. Versant/SQL provides a SQL-92 standard interface to Versant databases. Versant/ISQL is an interactive tool that lets you fire SQL-92 queries interactively to a Versant database. Versant/ODBC is a client-side DLL that accepts ODBC 2.0 calls and translates them to Versant/SQL ı this allows any ODBC-compliant tool to access a Versant database. The Versant/SQL Mapper maps the object model stored in a Versant database to a relational data model, which can be presented to users and can be accessed using standard SQL. It can perform complex mappings, such as transforming a many-to-many relationship between two objects to an intersection table. Similarly, it converts a multivalued attribute to a table with a many-to-one reference to the table representing the main object.
A client can access multiple Versant databases concurrently, and the Versant server can obviously serve multiple clients concurrently. The operations on a database are grouped in transactions. An application has to start a session to access any database. When an application starts a session, Versant creates various areas in memory, such as an object cache, an object cache table, and a server page cache for each database accessed in the session. A session starts up against a default database, but the application can connect to other databases as well. The session also opens up a connection to a session database, where it logs all the transaction details. There are various types of sessions for an application, such as standard, shared, nestable transaction, high-performance, optimistic, and custom locking.
Versant supports short and long transactions in the context of a session. Short transactions are logical units of work under the applicationıs control. An application can explicitly commit or roll back a short transaction, or set a save point for the transaction. Whenever a session starts or a short transaction is ended, a new short transaction is automatically started. However, you must have logging and locking enabled for the database. If a transaction spans more than one database, a two-phase commit is automatically invoked at commit time. Long transactions start and end by default when the sessions start and end. However, you can join to a previous long transaction ı that is, make the long transaction continue in a subsequent session ı by specifying the long transactionıs name at session startup time. You can use long transactions to keep track of different sets of checked out objects. You switch between multiple long transactions by stopping and restarting sessions.
Short locks are set at the object level for concurrency control. There are various types of short locks, such as write locks, update locks, read locks (which can be shared), and so-called null locks (used for dirty reads). Applications waiting for locks can be set to time out. Single database deadlocks are immediately detected and disallowed by Versant. It uses a timeout mechanism to detect deadlocks between multiple databases.
Versant has a very extensive set of concurrency control mechanisms ı from types of locks to check-in and check-out operations in the context of multiple long transactions ı much more extensive than any relational DBMS currently offers. This makes it possible to tune the database serverıs locking behavior very closely to any applicationıs requirements. However, DBAs must know their drill before fooling around with these lethal weapons. You really have to know your concurrency control theory and have your lock behavior models ready when starting to tune the Versant locking system.
Just as we had to do circuits (training and penalty runs), obstacle courses, and 2.4-kilometer time trails as fast as we could, an object DBMS should also perform its tasks as fast as possible. Although performance is evaluated based on the application requirements, most users have expeditious performance requirements. Versant has a number of mechanisms for tuning its performance.
Versant uses indexes to filter objects so that query routines only fetch the objects of interest from disk. Create and update routines also use indexes to enforce uniqueness constraints on object attributes. An index is defined on a single attribute of a class and indexes the specified attribute of all the objects of that class. You can have B-tree or hash indexes, where B-tree indexes are good for range queries and sufficient for direct key queries, and hash indexes are good for direct key queries. However, there are many restrictions and peculiarities about indexes that make them very different from their relational counterparts. Indexes do not have names. An index only applies to a single attribute. An attribute can only have two indexes ı one B-tree and one hash. An index only applies to a specific class and it is not inherited, so you have to define corresponding indexes for all the subclasses where it is required. Some complex attributes, such as fixed arrays and fixed length structures, cannot be indexed.
Versant has many memory-management facilities that application developers and DBAs can use to improve the applicationsı performance. For example, its various caches can be configured, and objects can be pinned in their respective caches. Similarly, log files can be configured, and objects can be located on multiple disks, even on raw disk devices, to improve performance. This compares well with the facilities provided by the more tunable relational DBMSs. A DBA must be skilled in the Versant-specific techniques to be able to use them advantageously.
Obviously, database and application design, as in a relational database application system, play the biggest roles in achieving good database and application performance.
Versant provides two different mechanisms to cater for disasters. The DBA can make online or online incremental backups of the database. An online backup can only be used to restore a crashed database to a specific previous correct state, when the backup was taken. An incremental backup has an associated rollforward log, which keeps track of all database activity that occurs between backup operations. You can use this log to restore the database to the point of the last committed transaction.
You can use the Versant Fault Tolerant Server, which is a synchronous replicator, to maintain hot standby databases. The contents of one database can be mirrored to another local or remote database to form a so-called replica pair. When one database becomes unavailable, Versant will continue to use the remaining one. When the crashed database returns to an operational state, Versant will automatically resynchronize the two databases. There are some limitations to synchronous replication. Each database can only have a single replica. Cursor queries and event notification only work on a single database and are therefore not transferred to the standby database. You cannot set and undo savepoints or use nested transactions when you use synchronous replication. Schema changes have to be performed while both databases are available. However, if you can live with these limitations, synchronous replication is excellent for maintaining a hot standby database. Alternatively, you can implement asynchronous replication using Versantıs event-notification mechanisms.
When I look at the Versant ODBMS, I have to disagree with the relational stalwarts who still claim that object-oriented databases are immature. Versant 5.0 is a powerful, tunable DBMS with all the necessary facilities to run large-scale production systems. It is obviously outside the scope of this column to indicate in detail where this exciting technology can be used, but Nelson King gave an interesting perspective in his article "Object DBMSs: Now or Never" in the July 1997 DBMS. On the same tack, the contents of a Versant database can be published on the Web through VersantWeb, a C++ framework to construct and deploy interactive Web-based applications.
The Versant ODBMS gives DBAs more than enough capabilities to tune the database serverıs behavior ı more than many RDBMSs do. Versant also has extensive distributed database capabilities, which I didnıt have room to review here. Surely, any relational DBA would need to be retrained in managing objects and methods and many other product-specific idiosyncrasies. However, a skilled DBA with experience in managing complex and tunable systems will appreciate the extensive facilities provided by Versant 5.0.
The next release of Versant will have a pure Java interface and extensive Java support. A DBA will be able to extend the functionality of the Versant Server with user-written methods, which brings it straight into the firing line with the extendible object/relational database servers, or so-called universal servers. My advice to you soldiers out there is to get yourself retrained for the onslaught of the heavyweight ODBMSs!
Figure 1.
The Versant process architecture.