• Kirill Smelkov's avatar
    go/zodb: Implement Connection · fb343a6f
    Kirill Smelkov authored
    Connection represents an application-level view of a ZODB database.
    It has groups of in-RAM application-level objects associated with it.
    The objects are isolated from both changes in further database
    transactions and from changes to in-RAM objects in other connections.
    
    Connection, as objects group manager, is responsible for handling
    object -> object database references. For this to work it keeps
    
    	{} oid -> obj
    
    dict and uses it to find already loaded object when another object
    persistently references particular oid. Since it related pydata handling
    of persistent references is correspondingly implemented in this patch.
    
    The dict must keep weak references on objects. The following text
    explains the rationale:
    
    	if Connection keeps strong link to obj, just
    	obj.PDeactivate will not fully release obj if there are no
    	references to it from other objects:
    
    	     - deactivate will release obj state (ok)
    	     - but there will be still reference from connection `oid -> obj` map to this object,
    	       which means the object won't be garbage-collected.
    
    	-> we can solve it by using "weak" pointers in the map.
    
    	NOTE we cannot use regular map and arbitrarily manually "gc" entries
    	there periodically: since for an obj we don't know whether other
    	objects are referencing it, we can't just remove obj's oid from
    	the map - if we do so and there are other live objects that
    	reference obj, user code can still reach obj via those
    	references. On the other hand, if another, not yet loaded, object
    	also references obj and gets loaded, traversing reference from
    	that loaded object will load second copy of obj, thus breaking 1
    	object in db <-> 1 live object invariant:
    
    	     A  →  B  →  C
    	     ↓           |
    	     D <--------- - - -> D2 (wrong)
    
    	- A activate
    	- D activate
    	- B activate
    	- D gc, A still keeps link on D
    	- C activate -> it needs to get to D, but D was removed from objtab
    	  -> new D2 is wrongly created
    
    	that's why we have to depend on Go's GC to know whether there are
    	still live references left or not. And that in turn means finalizers
    	and thus weak references.
    
    	some link on the subject:
    	https://groups.google.com/forum/#!topic/golang-nuts/PYWxjT2v6ps
    fb343a6f
persistent.go 12.5 KB