db4o: Activation- & Update-Depth
Activation is a very basic concept in db4o. In this post I’ll illustrate what it is, why it’s there and how you handle it.
(All posts of this series: the basics, activation, object-identity, transactions, persistent classes, single container concurrency, Queries in Java, C# 2.0, client-server concurrency, transparent persistence, adhoc query tools)
The Mysterious Null-Pointer
Let’s start with a mysterious exception! With the knowledge of the previous post we store some objects. This time a person has a property which refers to the person’s boss. We store six instances. Each person is the boss of another one.
var ceo = new Person("Julius", "Caesar"); var firstGeneral = new Person("NoIdea", "WhoCareus", ceo); var secondGeneral = new Person("Master", "Chiefius", firstGeneral); var captain = new Person("Biggest", "Halo-Geekius", secondGeneral); var officer = new Person("Plus", "Nixus", captain); var normalPerson = new Person("Mius", "Dius", officer); container.Store(normalPerson);
Everything fine so far. Then we decide to write a little method which prints the initials “Mius Dius” and all its superiors. It runs fine until it should print the initials of “Julius Caesar”. There a NullReferenceException is thrown. Somehow all the properties of that person are null. But why?
var person = (from Person p in db where p.FirstName.Equals("Mius") select p).Single(); while (null != person) {
// on the last person 'Julius Caesar' properties are null, hence this will fail Console.Out.WriteLine( string.Format("Persons initials {0}.{1}.", person.FirstName[0], person.SirName[0])); person = person.Boss; }
Activation. What is it? Why is it there?
As seen above, all properties of “Julius Caesar” are empty. db4o simply hasn’t loaded the “Julius Caesar”-object from the database into memory yet. And there’s a good reason for that. db4o stores object-graphs. Assume you have stored a complex object-graph with thousands of objects. Now you load a single object from the database. Imagine db4o would ensure that all references to other objects are set properly. Then db4o would have to load your whole object-graph (this could be the whole database) into memory.
To avoid that, db4o introduces a concept called Activation. db4o loads only a part of the object-graph into memory. The fully loaded objects are ‘activated’. At the ‘edge’ of the the object-graph are object which are not activated yet. All properties of such objects are not set. To use such a object, you have to ‘activate’ it first. This will load the missing data from the database.
Dealing With Activation
By default db4o has an activation-depth of 5. That means that the retrieved object and all objects which can be reached over 4 references are activated. If you want more, you can activate an object anytime. You just pass the object and the activation-depth to IObjectContainer.Activate()
db.Activate(person,5);
Its also possible to change the global default or change the activation-depth for a specific class.
A higher activation-depth makes it more pleasant to work. However it uses more memory and can have a negative impact on the performance. You have to experiment with it.
Get Rid Of The Activation-Pain
Well activation can be a pain in the ass. So, witty people came up with a solution: Transparent Activation. Basically this makes persisted objects aware of their activation-state. As soon as you access a property the first time the object activates itself. You can hand-code Transparent Activation by implementing interfaces or used byte-code-enhancers. I haven’t used Transparent Activation so far, so I can’t share any experience.
The Lost Update
So after all this complex activation stuff we update some objects.
person.SirName = "Cool-NewName"; person.Boss.SirName = "Cool-NewBoss"; db.Store(person);
Later we retrieve the same person and read the properties:
Console.Out.WriteLine(person.SirName);
Console.Out.WriteLine(person.Boss.SirName);
And the console output is this:
Cool-NewName
Nixus
Oh noes, the name-change on the boss is lost. Well you can thinks of the reason?
Update-Depth
Analogical to the activation-depth there is an update-depth in db4o. For similar reasons as the activation-depth. By default db4o simple doesn’t traverse the object-graph to look for changes. It only updates objects which was updated explicitly with IObjectContainer.Store(). (This applies only for updating. New objects are always stored completely).
Again you can change this setting globally, for a class or specify it on the Store()-call.
I’m Really To Lazy For All This Stuff
Well then you should try Transparent Persistance. Basically this is a way to make your object fully database-aware. You store the object once in the database. After that, all changes you make on the object are reflected in the database ‘by magic’. Again you can implement this manually or use byte-code-enhancers. And again, I haven’t tried it so far.
Next time
You might wonder how the heck db4o identifies its objects. There are no explicit ids like you use in hibernate & co. Well I’ll explain that next time =)
Example-Source-Code: Person.cs, Program.cs
- db4o, The Basics
- C vs Java, Doctor Who and Slow Club
Pingback: db4o: Client-Server and Concurrency « Gamlor
Thanks, your article explains the concept 10 times better than the official tutorial.
Thanks =)