Unique Universal IDs

For long-term external references and to identify an object even after it has been copied or moved to another ObjectContainer, db4o supplies Unique Universal IDs (UUIDs).

Every newly created db4o database generates a signature object. It is stored as an instance of Db4oDatabase in your database file.

This signature is linked to all newly created objects (if UUID generation is enabled) as the "signature part" of the UUID.

Further to that db4o creates a timestamp for every new object and uses an internal counter to make sure that timestamps are unique. This is called the "long part" of the UUID.

The long part is indexed to make the search fast. If two objects with an identical long parts are found, the signature parts are compared also.

The long part of the UUID can also be used to find out when an object was created. You can use

Java: com.db4o.foundation.TimeStampIdGenerator#idToMilliseconds()

to get object creation time in milliseconds.

UUIDs are guaranteed to be unique, if the signature of your db4o database is unique.

Normally any database has a unique signature unless its file is copied. The original and copied database files are identical, so they have the same signatures. If such files are used in replication, the process will end up with exceptions. What is the solution then?

Signature of a database file can be changed using

Java: YapFile#generateNewIdentity

method.

UUIDExample.java: testChangeIdentity
01public static void testChangeIdentity(){ 02 new File(YAPFILENAME).delete(); 03 ObjectContainer oc = Db4o.openFile(YAPFILENAME); 04 Db4oDatabase db; 05 byte[] oldSignature; 06 byte[] newSignature; 07 try { 08 db = oc.ext().identity(); 09 oldSignature = db.getSignature(); 10 System.out.println("oldSignature: " + printSignature(oldSignature)); 11 ((LocalObjectContainer)oc).generateNewIdentity(); 12 } finally { 13 oc.close(); 14 } 15 oc = Db4o.openFile(YAPFILENAME); 16 try { 17 db = oc.ext().identity(); 18 newSignature = db.getSignature(); 19 System.out.println("newSignature: " + printSignature(newSignature)); 20 } finally { 21 oc.close(); 22 } 23 24 boolean same = true; 25 26 for (int i = 0; i < oldSignature.length; i++) { 27 if(oldSignature[i] != newSignature[i]){ 28 same =false; 29 } 30 } 31 32 if (same){ 33 System.out.println("Database signatures are identical"); 34 } else { 35 System.out.println("Database signatures are different"); 36 } 37 }

UUIDs are not generated by default, since they occupy extra space in the database file and produce performance overhead for maintaining their index. UUIDs can be turned on globally or for individual classes:

Java: Db4o.configure().generateUUIDs(Integer.MAX_VALUE)

- turns on UUID generation for all classes in a database.

Java: Db4o.configure().objectClass(Foo.class).generateUUIDs(true)

- turns on UUID generation for a specific class.

You can get the UUID value for an object using the following methods:

Java:

ExtObjectContainer#getObjectInfo(Object)
ObjectInfo#getUUID()

To get the object from the database, knowing its UUID, use:

Java: ExtObjectContainer#getByUUID(Db4oUUID)

The following example shows the usage of UUID:

UUIDExample.java: setObjects
01public static void setObjects(){ 02 Db4o.configure().objectClass(Pilot.class).generateUUIDs(true); 03 new File(YAPFILENAME).delete(); 04 ObjectContainer oc = Db4o.openFile(YAPFILENAME); 05 try { 06 Car car = new Car("BMW", new Pilot("Rubens Barrichello")); 07 oc.set(car); 08 } finally { 09 oc.close(); 10 } 11 }

UUIDExample.java: testGenerateUUID
01public static void testGenerateUUID(){ 02 ObjectContainer oc = Db4o.openFile(YAPFILENAME); 03 try { 04 Query query = oc.query(); 05 query.constrain(Car.class); 06 ObjectSet result = query.execute(); 07 Car car = (Car)result.get(0); 08 ObjectInfo carInfo = oc.ext().getObjectInfo(car); 09 Db4oUUID carUUID = carInfo.getUUID(); 10 System.out.println("UUID for Car class are not generated:"); 11 System.out.println("Car UUID: " + carUUID); 12 13 Pilot pilot = car.getPilot(); 14 ObjectInfo pilotInfo = oc.ext().getObjectInfo(pilot); 15 Db4oUUID pilotUUID = pilotInfo.getUUID(); 16 System.out.println("UUID for Pilot:"); 17 System.out.println("Pilot UUID: " + pilotUUID); 18 System.out.println("long part: " + pilotUUID.getLongPart() +"; signature: " + printSignature(pilotUUID.getSignaturePart())); 19 long ms = TimeStampIdGenerator.idToMilliseconds(pilotUUID.getLongPart()); 20 System.out.println("Pilot object was created: " + (new Date(ms)).toString()); 21 Pilot pilotReturned = (Pilot) oc.ext().getByUUID(pilotUUID); 22 System.out.println("Pilot from UUID: " + pilotReturned); 23 } finally { 24 oc.close(); 25 } 26 }

Sometimes you can find out that you need UUIDs only when the database is already created and has some data in it. What can you do in that case?

Fortunately enabling replication for existing data files is a very simple process:

Java: Db4o.configure().objectClass(Task.class).enableReplication(true)

After that you will just need to use the old defragment tool from tools package supplied with the distribution before version 6.0 (source code only) to enable replication.

You can use UUID for replication and as a reference to a specific object instance from an external application or data store.