Db4o, Activation and Transparent Activation I
[ bamboo ] 21:58, Wednesday, 16 May 2007

Life looks good so let's consider a very simple data structure. A linked list:

   1:import System.Collections
   2:
   3:class LinkedList(IEnumerable):
   4:    
   5:    _head as Node
   6:    
   7:    def constructor(*values):
   8:        for value in values:
   9:            Add(value)
  10:    
  11:    def Add(value):
  12:        _head = Node(value, _head)
  13:        
  14:    def GetEnumerator():
  15:        node = _head
  16:        while node is not null:
  17:            yield node.Value
  18:            node = node.Next
  19:            
  20:    class Node:
  21:    
  22:        _value as object    
  23:        _next as Node
  24:        
  25:        def constructor(value, next as Node):
  26:            _value = value
  27:            _next = next
  28:
  29:        Value:
  30:            get:
  31:                return _value
  32:            
  33:        Next:
  34:            get:
  35:                return _next

Our LinkedList class can be used like this:

   1:list = LinkedList("Eric Idle",
   2:                "John Cleese",
   3:                "Graham Chapman",
   4:                "Terry Gilliam",
   5:                "Terry Jones",
   6:                "Michael Palim")
   7:for item in list:
   8:    print item

Which unsurprisingly gives the following output:

Michael Palim
Terry Jones
Terry Gilliam
Graham Chapman
John Cleese
Eric Idle

Now let's move on and store our beautifully crafted LinkedList instance with Db4o:

   1:
   2:using container = Db4oFactory.OpenFile(fname):
   3:    container.Set(list)
   4:

Some time later:

   1:
   2:using container = Db4oFactory.OpenFile(fname):
   3:    list = container.Query(LinkedList).Next()
   4:    for item in list:
   5:        print item or "<null>"
   6:

Which gives:

Michael Palim
Terry Jones
Terry Gilliam
Graham Chapman
<null>

Uh, oh... What's going on?

Activation is going on, that's what it is.

Activation is the process of populating the attributes of an object with previously stored data.

Db4o activates an object the first time it is retrieved from the database and whenever instructed to do so by the application through IObjectContainer.Activate.

During activation Db4o will also follow the references in the object graph activating any referenced objects until a configured activation depth is reached.

We can make sense of the output if we consider that Db4o has its default activation depth set to 5.

When activating the list Db4o will follow the LinkedList._head reference and activate the first node, then follow the Node._next reference and so on until it reaches the 5th node which it's not activated further and has its members set to null.

Now that we can understand the output has life gotten any easier?

Well, we can ask Db4o to activate the list to the depth of 7:

   1:
   2:using container = Db4oFactory.OpenFile(configuration, fname):
   3:    list = container.Query(LinkedList).Next()
   4:    container.Activate(list, 7)
   5:    for item in list:
   6:        print item or "<null>"

Which gives us the correct output but smells funny.

Application logic shouldn't have to worry about activation depth and all that. And how are we supposed to track the required activation depth for these dynamic object graphs?

Enter Transparent Activation.

Transparent Activation works by giving the objects in the system the responsibility of activating themselves before accessing any attribute. The activation must happen through a provided activator object which keeps track of everything needed for activation to work. The activator object is made available to any object that implements the IActivatable interface:

   1:
   2:class LinkedList(IEnumerable , IActivatable):
   3:    
   4:    _head as Node
   5:    
   6:    transient _activator as IActivator
   7:    
   8:    def constructor(*values):
   9:        for value in values:
  10:            Add(value)
  11:    
  12:    def Add(value):
  13:        Activate()
  14:        _head = Node(value, _head)
  15:        
  16:    def GetEnumerator():
  17:        Activate()
  18:        node = _head
  19:        while node is not null:
  20:            yield node.Value
  21:            node = node.Next
  22:  

  23:    def IActivatable.Bind(activator as IActivator):
  24:        _activator = activator
  25:        
  26:    def Activate():
  27:        if _activator is null: return
  28:        _activator.Activate()
  29:        

  30:    class Node(IActivatable):
  31:
  32:        _value as object
  33:
  34:        _next as Node
  35:        
  36:        transient _activator as IActivator
  37:        
  38:        def constructor(value, next as Node):
  39:            _value = value
  40:            _next = next
  41:
  42:        Value:
  43:            get:
  44:                Activate()
  45:                return _value
  46:            
  47:        Next:
  48:            get:
  49:                Activate()
  50:                return _next
  51:        

  52:        def IActivatable.Bind(activator as IActivator):
  53:            _activator = activator
  54:            
  55:        private def Activate():
  56:            if _activator is null: return
  57:            _activator.Activate()

  58:            

The application just needs to enable Transparent Activation once and then everything should work as expected (no more explicit Activate calls from the application):

   1:                    
   2:configuration = Db4oFactory.NewConfiguration()
   3:configuration.Add(TransparentActivationSupport())
   4:
   5:using container = Db4oFactory.OpenFile(configuration, fname):
   6:    list = container.Query(LinkedList).Next()
   7:    for item in list:
   8:        print item or "<null>"

Life looks better but what about all that boilerplate code that must go into the object model?

The next Db4o release will ship with an instrumentation tool capable of injecting the right IL instructions into an object model to make it Transparent Activation ready.

If you are curious to see this code in action grab it here.

In a next blog entry I'll go into how to encapsulate this logic behind a smart boo attribute.


Comments
Post a comment









Remember personal info?