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

c#:Db4objects.Db4o.Foundation.TimeStampIdGenerator#IdToMilliseconds()

VB:Db4objects.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

c#: YapFile#GenerateNewIdentity

VB: YapFile#GenerateNewIdentity

method.

UUIDExample.cs: TestChangeIdentity
01public static void TestChangeIdentity() 02 { 03 File.Delete(YapFileName); 04 IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 05 Db4oDatabase db; 06 byte[] oldSignature; 07 byte[] newSignature; 08 try 09 { 10 db = oc.Ext().Identity(); 11 oldSignature = db.GetSignature(); 12 Console.WriteLine("oldSignature: " + PrintSignature(oldSignature)); 13 ((YapFile)oc).GenerateNewIdentity(); 14 } 15 finally 16 { 17 oc.Close(); 18 } 19 oc = Db4oFactory.OpenFile(YapFileName); 20 try 21 { 22 db = oc.Ext().Identity(); 23 newSignature = db.GetSignature(); 24 Console.WriteLine("newSignature: " + PrintSignature(newSignature)); 25 } 26 finally 27 { 28 oc.Close(); 29 } 30 31 bool same = true; 32 33 for (int i = 0; i < oldSignature.Length; i++) 34 { 35 if(oldSignature[i] != newSignature[i]) 36 { 37 same =false; 38 } 39 } 40 41 if (same) 42 { 43 Console.WriteLine("Database signatures are identical"); 44 } 45 else 46 { 47 Console.WriteLine("Database signatures are different"); 48 } 49 }

UUIDExample.vb: TestChangeIdentity
01Public Shared Sub TestChangeIdentity() 02 03 File.Delete(YapFileName) 04 Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 05 Dim db As Db4oDatabase 06 Dim oldSignature() As Byte 07 Dim NewSignature() As Byte 08 Try 09 db = oc.Ext().Identity() 10 oldSignature = db.GetSignature() 11 Console.WriteLine("oldSignature: " + PrintSignature(oldSignature)) 12 Dim yf As YapFile = DirectCast(oc, YapFile) 13 yf.GenerateNewIdentity() 14 Finally 15 oc.Close() 16 End Try 17 oc = Db4oFactory.OpenFile(YapFileName) 18 Try 19 db = oc.Ext().Identity() 20 NewSignature = db.GetSignature() 21 Console.WriteLine("newSignature: " + PrintSignature(NewSignature)) 22 Finally 23 oc.Close() 24 End Try 25 26 Dim same As Boolean = True 27 28 Dim i As Integer 29 For i = 0 To oldSignature.Length - 1 Step i + 1 30 If oldSignature(i) <> NewSignature(i) Then 31 32 same = False 33 End If 34 Next 35 36 If (same) Then 37 Console.WriteLine("Database signatures are identical") 38 Else 39 Console.WriteLine("Database signatures are different") 40 End If 41 End Sub

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:

c#: Db4oFactory.Configure().GenerateUUIDs(Int32.MaxValue)

VB: Db4oFactory.Configure().GenerateUUIDs(Int32.MaxValue)

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

c#:Db4oFactory.Configure().ObjectClass(typeof(Foo)).GenerateUUIDs(true)

VB:Db4oFactory.Configure().ObjectClass(GetType(Foo)).GenerateUUIDs(true)

- turns on UUID generation for a specific class.

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

c#:

IEExtObjectContainer#GetObjectInfo(Object)
IObjectInfo#GetUUID()

VB:

IExtObjectContainer#GetObjectInfo(Object)
IObjectInfo#GetUUID()

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

c#:IExtObjectContainer#GetByUUID(Db4oUUID)

vb: IExtObjectContainer#GetByUUID(Db4oUUID)

The following example shows the usage of UUID:

UUIDExample.cs: SetObjects
01public static void SetObjects() 02 { 03 Db4oFactory.Configure().ObjectClass(typeof(Pilot)).GenerateUUIDs(true); 04 File.Delete(YapFileName); 05 IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 06 try 07 { 08 Car car = new Car("BMW", new Pilot("Rubens Barrichello")); 09 oc.Set(car); 10 } 11 finally 12 { 13 oc.Close(); 14 } 15 }

UUIDExample.vb: SetObjects
01Public Shared Sub SetObjects() 02 Db4oFactory.Configure().ObjectClass(GetType(Pilot)).GenerateUUIDs(True) 03 File.Delete(YapFileName) 04 Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 05 Try 06 Dim car As Car = New Car("BMW", New Pilot("Rubens Barrichello")) 07 oc.Set(car) 08 Finally 09 oc.Close() 10 End Try 11 End Sub

UUIDExample.cs: TestGenerateUUID
01public static void TestGenerateUUID() 02 { 03 IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 04 try 05 { 06 IQuery query = oc.Query(); 07 query.Constrain(typeof(Car)); 08 IObjectSet result = query.Execute(); 09 Car car = (Car)result[0]; 10 IObjectInfo carInfo = oc.Ext().GetObjectInfo(car); 11 Db4oUUID carUUID = carInfo.GetUUID(); 12 Console.WriteLine("UUID for Car class are not generated:"); 13 Console.WriteLine("Car UUID: " + carUUID); 14 15 Pilot pilot = car.Pilot; 16 IObjectInfo pilotInfo = oc.Ext().GetObjectInfo(pilot); 17 Db4oUUID pilotUUID = pilotInfo.GetUUID(); 18 Console.WriteLine("UUID for Car class are not generated:"); 19 Console.WriteLine("Pilot UUID: " + pilotUUID); 20 Console.WriteLine("long part: " + pilotUUID.GetLongPart() +"; signature: " + PrintSignature(pilotUUID.GetSignaturePart())); 21 long ms = TimeStampIdGenerator.IdToMilliseconds(pilotUUID.GetLongPart()); 22 Console.WriteLine("Pilot object was created: " + (new DateTime(1970,1,1)).AddMilliseconds(ms).ToString()); 23 Pilot pilotReturned = (Pilot)oc.Ext().GetByUUID(pilotUUID); 24 Console.WriteLine("Pilot from UUID: " + pilotReturned); 25 } 26 finally 27 { 28 oc.Close(); 29 } 30 }

UUIDExample.vb: TestGenerateUUID
01Public Shared Sub TestGenerateUUID() 02 Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 03 Try 04 Dim query As IQuery = oc.Query() 05 query.Constrain(GetType(car)) 06 Dim result As IObjectSet = query.Execute() 07 Dim car As Car = CType(result(0), Car) 08 Dim carInfo As IObjectInfo = oc.Ext().GetObjectInfo(car) 09 Dim carUUID As Db4oUUID = carInfo.GetUUID() 10 Console.WriteLine("UUID for Car class are not generated:") 11 If carUUID Is Nothing Then 12 Console.WriteLine("Car UUID: null") 13 Else 14 Console.WriteLine("Car UUID: " + carUUID.ToString()) 15 End If 16 17 18 Dim pilot As Pilot = car.Pilot 19 Dim pilotInfo As IObjectInfo = oc.Ext().GetObjectInfo(pilot) 20 Dim pilotUUID As Db4oUUID = pilotInfo.GetUUID() 21 Console.WriteLine("UUID for Car class are not generated:") 22 If pilotUUID Is Nothing Then 23 Console.WriteLine("Pilot UUID: null") 24 Else 25 Console.WriteLine("Pilot UUID: " + pilotUUID.ToString()) 26 End If 27 28 Console.WriteLine("long part: " + pilotUUID.GetLongPart().ToString() + "; signature: " + PrintSignature(pilotUUID.GetSignaturePart())) 29 Dim ms As Long = TimeStampIdGenerator.IdToMilliseconds(pilotUUID.GetLongPart()) 30 Console.WriteLine("Pilot object was created: " + (New DateTime(1970, 1, 1)).AddMilliseconds(ms).ToString()) 31 Dim pilotReturned As Pilot = CType(oc.Ext().GetByUUID(pilotUUID), Pilot) 32 Console.WriteLine("Pilot from UUID: " + pilotReturned.ToString()) 33 Finally 34 oc.Close() 35 End Try 36 End Sub

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:

c#:Db4oFactory.Configure().ObjectClass(typeof(Task)).EnableReplication(true)

vb: Db4oFactory.Configure().ObjectClass(GetType(Task)).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.