[ZODB-Dev] BTrees and Mutables, was Re: [IndexedCatalog] bug in default indexing

Shane Hathaway shane@zope.com
Tue, 11 Feb 2003 16:21:59 -0500


Christian Reis wrote:
> On Tue, Feb 11, 2003 at 03:24:05PM -0500, Shane Hathaway wrote:
> 
>>Casey Duncan wrote:
>>
>>>An alternative which is perhaps more palatable is to just set the whole 
>>>mutable object into the btree again. Like:
>>>
>>>l = tree['bar']
>>>l.append(4)
>>>tree['bar'] = l # Trigger list persistance
>>
>>In fact, if you put simple lists in BTrees, you have to use this 
>>pattern.  Setting tree._p_changed will not get the right object stored. 
> 
> 
> Whoa. You mean to say that:
> 
>     l = tree['bar']
>     l.append(4)
>     tree['bar'] = l
> 
> is *not* the same as:
> 
>     tree['bar'].append(4)
> 
> right? And the first form *does* work as expected, or are there
> side-effects?

That's correct, although the purist way is like this:

     l = tree['bar']
     tree['bar'] = l
     l.append(4)

That way the notification happens before the actual change.  If an 
exception happens and the transaction is aborted, the changed list will 
be reverted.

> This *really* should be documented on the BTrees page - I've never heard
> it mentioned and it is biting us badly inside IC (since we can't use
> Persistent* for performance reasons). Can anybody offer a bit of
> explanation as to why so I can put up on the page a reasonable
> explanation beyond "don do dat"?

This isn't specific to BTrees.  It's a ZODB wart, and it's explained in 
the Zope Developer's Guide: if you store mutable, non-persistent objects 
in ZODB, you have to do special things to get ZODB to see changes to 
them.  I can understand how you might miss it, since it's such a big 
surprise.

Under the hood, a BTree consists of many ZODB records.  If you set 
tree._p_changed = 1, you're just storing a small object that refers to 
the real data.  But if you set a key in a BTree, even if you set it to 
the same value it had before, the BTree will store the correct object.

I've tried to come up with ways to change Python to fix this nasty 
issue.  Python provides no object mutation notification mechanism.  The 
solution, whatever it might be, must have zero impact on non-ZODB software.

Shane