db4o from db4objects (www.db4objects.com) is an open-source object database that provides the capabilities that I've described. db4o is available in Java and .NET flavors; in this article, I use its Java version.
Besides being open source, db4o's features include an easy-to-grasp API, equally lucid persistence model, and the fact that it is a true object database (not an object/relational mapping database). Add to this its invisible transactioning and its adherence to ACID (atomicity, consistency, isolation, and durability) behavior, and you have an embeddable database that concentrates a lot of power in a small area.
The entire db4o library is provided in a single .JAR file (or .DLL if you're using .NET), and you'll typically find yourself handling better than 90 percent of your database work with about 10 API calls. In addition, as far as db4o is concerned, all objects are persistence capable. Classes whose objects are to be persistent need not be derived from a persistence-aware base class, nor must persistent classes implement any specialized persistence interface. If you want to put an object into the database, you more or less tell db4o, "Please put this object into the database," and it does the rest.
In fact, db4o doesn't need any description of a persistent object's structure (a schema file). When you tell db4o to put an object in the database, the runtime engine uses reflection to "spider" the object's architecture and deduce how the object is to be stored. The spidering works in reverse, too; when you fetch an object, db4o need not be told anything about that object to properly instantiate it.
Replication is relatively new in db4o, having appeared in the 5.0 release. Replication support within a given database is optional, and for good reason. Again, replication requires that db4o attach a universal identifier to each object, as well as maintain versioning information. This necessarily consumes space in the database, so it should be enabled only when required.
Specifically, the universal identifier that db4o constructs is composed of two parts:
- An object ID number. Every object in the database has associated with it a unique 32-bit long. This identifier is unique within the database.
- A database signature. This signature is associated with the entire database. Typically, it is about 30 bytes long, and is derived from a variety of sources. For example, one element used is the host name of the computer that the database was originally created on. The signature is guaranteed unique for all db4o databases.
So, the logical concatenation of the signature with the object ID provides a truly universal identifier for any object in any db4o database.
This, however, is not all the information you need for complete replication support. Again, versioning must be attached to objects so that modifications can be properly reconciled at synchronization. To this end, when databases are replicated, db4o records the transaction number (in both databases) of the replication operation. This transaction number effectively becomes the object's version number. (The original transaction number is also retained.) Any subsequent modification to the object causes its version number to be incremented. Consequently, when synchronization takes place at a future point, db4o compares version numbers to see which objects have been modified since the last replication.
Here, db4o takes a cautious approach. It does not presume that the object with the higher version number is the winner. Instead, db4o uses the following replication plan:
- If neither object has changed since the last replication, nothing happens.
- If one object has changed, and the other has not, the changed object wins (overwriting the loser).
- If both objects have changed, then a user-supplied conflict resolution routine is called.
Consequently, db4o passes off to you the problem of determining which object is the more current. db4o does not assume that a bigger version number indicates a later object. The aforementioned conflict resolution routine is a sort of deus ex machina method that must be supplied to the replication process, and that steps in to decide which object is the winner.