Oct 8, 2007

Enabling transparent activation in your db4o applications

As a software developer, one common pattern I've found over and over again is the typical parent/child relationship.

In this post I'll present you a program
(a WinForms based application) that lets you create, store and delete objects (representing tasks) that follows this common structure in a db4o database and take the opportunity to show how a new db4o feature (to be introduced in our next release) helps to solve some related problems.

Obs: I'll focus on the .Net side of db4o but these concepts apply equally to our Java interface. Also, in order to be able to access various links related in this post you'll be required to join (for free) the "db4o Developer Community"; it's a very simple process: just click on join when asked for your credentials (user name/password).

Ok, let's use the application for while ...

Open TaskSample.sln solution in Visual Studio 2005 (it should also work on the Express Edition) and compile it. Then, launch it and add some tasks by pressing "CTRL-A" or selecting "Tasks/Add.." menu.

Now add some tasks as the following structure ...

  • Work
    • Todo
    • Projects
      • Super hyper ultra mega project
        • Components
          • GoldenHammer.dll
            • GoldenNail.dll
            • GoldenHead.dll

... close the database selecting "File/Close" in the main menu ...


... and reload it (select "File/Open") .

Now expand the tasks in order to see "Super hyper ultra mega project" sub tasks.


What? What happened to Components, GodenHammer.dll, GodenNail.dll and GondelHead.dll? Where are they?

Take it easy; I assure you that db4o didn't ate your task objects :) What happened is that our old friend, the cost/benefit trade-off is showing its ugly head.

In order to keep memory consumption low and object throughput high, db4o sets a hard limit
on "how deep the rabbit hole goes" (a concept called activation depth), or, in other words, how many levels it is willing to go down in the object graph reading (activating) them from the database.

It just happens that in its current version, db4o sets this limit to 5, i.e, starting from each object directly selected by a query, at most 5 levels bellow will be returned.

That explains why the sub tasks were not loaded from the database.
(they are six levels down the root task so db4o stopped following references when it reached the "Super hyper ultra mega project" task.

How can we ensure smooth operation of our application?
  1. setting the activation level to a higher value might be an option (but which value? small values will activate too little objects; higher values may lead to high memory consumption and possibly out of memory exceptions):
    IConfiguration configuration = Db4oFactory.NewConfiguration();
    configuration.ObjectClass(typeof(Task)).MinimumActivationDepth(10);
    
    using(IObjectContainer db = Db4oFactory.OpenFile(configuration, Db4oFileName))
    {
    // perform some work here
    }
    

    To test this option, select a higher activation depth (let's say, 8) in the sample application; the database will be reopened; now you'll be able to see all the tasks :) For more details about activation depth, please, see here.


  2. Manually activating objects as needed;

    In this scenario we may track expansions in out task treeview and activate them as needed.
    db.Activate(task, 1);
    AddOutlines(task.FirsChild);
    

    To test this option select the "Enables automatic activation" button on the toolbar (the little bulb lamp). The database will be reloaded and now you'll be able to see all tasks again.

  3. Or, IMHO, the best one, letting db4o take care of this through Transparent Activation (herein referred only as TA), a new feature to be introduced in our next release (download the latest development build here) (for more details and samples about this feature look here and here);
Note that in order to benefit from TA (solution 3) objects must implement IActivable interface, either explicitly or through instrumentation as explained here.

I recommend following the instrumentation path (let the computer do the dirty work for us :). Db4o ships with an utility program (Db4oTool.exe) that you may use among other duties, to instrument assemblies to support TA.

All you need is to call Db4oAdmin.exe after building your assemblies and it'll add the required pieces to support TA.

Db4oTool -ta assembly_name.ext

If you prefer, add a post build step to TaskSample.snl project as follows:

\db4o-8.0\bin\net-3.0\Db4oTool.exe -ta "$(TargetPath)"
In order to instrument signed assemblies you'll need to delay sign them (because instrumentation process changes the assembly). For more information about delay signed assemblies, please, refer to this msdn article.

The application title bar shows you if the application was instrumented or not (if it supports TA or not).

Try to play with the sample and check the results. You may download the sample (source files) for this post here.

Thank you and see you soon ;)

Adriano

1 comment:

Anonymous said...

Thanks YOU very much! J.S., Prague, CZ