Reference Cache In Client-Server Mode

Db4o uses object reference cache for easy access to persistent objects during one transaction. In client/server mode each client has its own reference cache, which helps to achieve good performance. However it gets complicated, when different clients work on the same object, as this object's cached value is used on each side. It means, that even when the operations go serially, the object's value won't be updated serially unless it is refreshed before each update.

The following example demonstrates this behaviour.

InconsistentGraphExample.cs: Main
1public static void Main(string[] args) 2 { 3 new InconsistentGraphExample().Run(); 4 }
InconsistentGraphExample.cs: Run
01public void Run() 02 { 03 File.Delete(Db4oFileName); 04 IObjectServer server = Db4oFactory.OpenServer(Db4oFileName, Port); 05 try 06 { 07 server.GrantAccess(User, Password); 08 09 IObjectContainer client1 = OpenClient(); 10 IObjectContainer client2 = OpenClient(); 11 12 if (client1 != null && client2 != null) 13 { 14 try 15 { 16 // wait for the operations to finish 17 WaitForCompletion(); 18 19 // save pilot with client1 20 Car client1Car = new Car("Ferrari", 2006, new Pilot("Schumacher")); 21 client1.Set(client1Car); 22 client1.Commit(); 23 System.Console.WriteLine("Client1 version initially: " + client1Car); 24 25 WaitForCompletion(); 26 27 // retrieve the same pilot with client2 28 Car client2Car = (Car)client2.Query(typeof(Car)).Next(); 29 System.Console.WriteLine("Client2 version initially: " + client2Car); 30 31 // delete the pilot with client1 32 Pilot client1Pilot = (Pilot)client1.Query(typeof(Pilot)).Next(); 33 client1.Delete(client1Pilot); 34 // modify the car, add and link a new pilot with client1 35 client1Car.Model = 2007; 36 client1Car.Pilot = new Pilot("Hakkinnen"); 37 client1.Set(client1Car); 38 client1.Commit(); 39 40 WaitForCompletion(); 41 42 client1Car = (Car) client1.Query(typeof(Car)).Next(); 43 System.Console.WriteLine("Client1 version after update: " + client1Car); 44 45 46 System.Console.WriteLine(); 47 System.Console.WriteLine("client2Car still holds the old object graph in its reference cache"); 48 client2Car = (Car) client2.Query(typeof(Car)).Next(); 49 System.Console.WriteLine("Client2 version after update: " + client2Car); 50 IObjectSet result = client2.Query(typeof(Pilot)); 51 System.Console.WriteLine("Though the new Pilot is retrieved by a new query: "); 52 ListResult(result); 53 54 55 WaitForCompletion(); 56 } 57 catch (Exception ex) 58 { 59 System.Console.WriteLine(ex.ToString()); 60 } 61 finally 62 { 63 CloseClient(client1); 64 CloseClient(client2); 65 } 66 } 67 } 68 catch (Exception ex) 69 { 70 System.Console.WriteLine(ex.ToString()); 71 } 72 finally 73 { 74 server.Close(); 75 } 76 }
InconsistentGraphExample.vb: Main
1Public Shared Sub Main(ByVal args As String()) 2 Dim example As InconsistentGraphExample = New InconsistentGraphExample() 3 example.Run() 4 End Sub
InconsistentGraphExample.vb: Run
01Public Sub Run() 02 File.Delete(Db4oFileName) 03 Dim server As IObjectServer = Db4oFactory.OpenServer(Db4oFileName, Port) 04 Try 05 server.GrantAccess(User, Password) 06 07 Dim client1 As IObjectContainer = OpenClient() 08 Dim client2 As IObjectContainer = OpenClient() 09 10 If client1 IsNot Nothing AndAlso client2 IsNot Nothing Then 11 Try 12 ' wait for the operations to finish 13 WaitForCompletion() 14 15 ' save pilot with client1 16 Dim client1Car As New Car("Ferrari", 2006, New Pilot("Schumacher")) 17 client1.[Set](client1Car) 18 client1.Commit() 19 System.Console.WriteLine("Client1 version initially: " + client1Car.ToString()) 20 21 WaitForCompletion() 22 23 ' retrieve the same pilot with client2 24 Dim client2Car As Car = DirectCast(client2.Query(GetType(Car)).[Next](), Car) 25 System.Console.WriteLine("Client2 version initially: " + client2Car.ToString()) 26 27 ' delete the pilot with client1 28 Dim client1Pilot As Pilot = DirectCast(client1.Query(GetType(Pilot)).[Next](), Pilot) 29 client1.Delete(client1Pilot) 30 ' modify the car, add and link a new pilot with client1 31 client1Car.Model = 2007 32 client1Car.Pilot = New Pilot("Hakkinnen") 33 client1.[Set](client1Car) 34 client1.Commit() 35 36 WaitForCompletion() 37 38 client1Car = DirectCast(client1.Query(GetType(Car)).[Next](), Car) 39 System.Console.WriteLine("Client1 version after update: " + client1Car.ToString()) 40 41 42 System.Console.WriteLine() 43 System.Console.WriteLine("client2Car still holds the old object graph in its reference cache") 44 client2Car = DirectCast(client2.Query(GetType(Car)).[Next](), Car) 45 System.Console.WriteLine("Client2 version after update: " + client2Car.ToString()) 46 Dim result As IObjectSet = client2.Query(GetType(Pilot)) 47 System.Console.WriteLine("Though the new Pilot is retrieved by a new query: ") 48 ListResult(result) 49 50 51 WaitForCompletion() 52 Catch ex As Exception 53 System.Console.WriteLine(ex.ToString()) 54 Finally 55 CloseClient(client1) 56 CloseClient(client2) 57 End Try 58 End If 59 Catch ex As Exception 60 System.Console.WriteLine(ex.ToString()) 61 Finally 62 server.Close() 63 End Try 64 End Sub

In order to make the objects consistent on each client you must refresh them from the server when they get updated. This can be done by using Committed Callbacks.