[Zodb-checkins] CVS: StandaloneZODB/ZODB - DB.py:1.35 PersistentMapping.py:1.12

Jeremy Hylton jeremy@zope.com
Tue, 27 Nov 2001 16:38:07 -0500


Update of /cvs-repository/StandaloneZODB/ZODB
In directory cvs.zope.org:/tmp/cvs-serv4971/ZODB

Modified Files:
	DB.py PersistentMapping.py 
Log Message:
Simplify and cleanup implementation of PersistentMapping.

The implementation now defers all implementation decisions to UserDict
and merely handles updates to _p_changed in the PersistentMapping
implementation.  This change simplifies the implementation and ensures
that it implements all the new methods of dictionaries like popitem()
and setdefault().

There is one (important?) behavioral change:  The old implementation
of the keys() method did not return keys that were strings starting
with underscore.  This behavior was undocumented and could lead to
problems for implementations that expect keys() to working like a
regular mapping.

    The feature was removed after verifying that the Zope test suite
    does not depend on this behavior.

An internal implementation change is that the PersistentMapping does
not keep a copy of the keys() of the dict.  It simplifies the
implementation a lot to remove the cacheing and the benefit is
unclear.  It only benefits applications that call keys() frequently
without modifying the dict.  And it requires that two copies of the
list exist for each call to keys() which may require a lot of space.





=== StandaloneZODB/ZODB/DB.py 1.34 => 1.35 ===
         storage.registerDB(self, None)
         if not hasattr(storage,'tpc_vote'): storage.tpc_vote=lambda *args: None
-        try: storage.load('\0\0\0\0\0\0\0\0','')
-        except:
+        try:
+            storage.load('\0\0\0\0\0\0\0\0','')
+        except KeyError:
+            # Create the database's root in the storage if it doesn't exist
             import PersistentMapping
-            file=cStringIO.StringIO()
-            p=cPickle.Pickler(file,1)
-            p.dump((PersistentMapping.PersistentMapping,None))
-            p.dump({'_container': {}})
-            t=Transaction()
-            t.description='initial database creation'
+            root = PersistentMapping.PersistentMapping()
+            # Manually create a pickle for the root to put in the storage.
+            # The pickle must be in the special ZODB format.
+            file = cStringIO.StringIO()
+            p = cPickle.Pickler(file, 1)
+            p.dump((root.__class__, None))
+            p.dump(root.__getstate__())
+            t = Transaction()
+            t.description = 'initial database creation'
             storage.tpc_begin(t)
             storage.store('\0\0\0\0\0\0\0\0', None, file.getvalue(), '', t)
             storage.tpc_vote(t)


=== StandaloneZODB/ZODB/PersistentMapping.py 1.11 => 1.12 ===
 import Persistence
 import types
+from UserDict import UserDict
 
 _marker=[]
-class PersistentMapping(Persistence.Persistent):
+
+class PersistentMapping(UserDict, Persistence.Persistent):
     """A persistent wrapper for mapping objects.
 
-    This class allows wrapping of mapping objects so that
-    object changes are registered.  As a side effect,
-    mapping objects may be subclassed.
+    This class allows wrapping of mapping objects so that object
+    changes are registered.  As a side effect, mapping objects may be
+    subclassed.
     """
 
-    def __init__(self,container=None):
-        if container is None: container={}
-        self._container=container
+    __super_delitem = UserDict.__delitem__
+    __super_setitem = UserDict.__setitem__
+    __super_clear = UserDict.clear
+    __super_update = UserDict.update
+    __super_setdefault = UserDict.setdefault
+    __super_popitem = UserDict.popitem
 
     def __delitem__(self, key):
-        del self._container[key]
-        try: del self._v_keys
-        except: pass
+        self.__super_delitem(key)
         self.__changed__(1)
 
-    def __getitem__(self, key):
-        return self._container[key]
-
-    def __len__(self):     return len(self._container)
-
     def __setitem__(self, key, v):
-        self._container[key]=v
-        try: del self._v_keys
-        except: pass
+        self.__super_setitem(key, v)
         self.__changed__(1)
 
     def clear(self):
-        self._container.clear()
-        self._p_changed=1
-        if hasattr(self,'_v_keys'): del self._v_keys
-
-    def copy(self): return self.__class__(self._container.copy())
-
-    def get(self, key, default=_marker):
-        if default is _marker:
-            return self._container.get(key)
-        else:
-            return self._container.get(key, default)
-
-    def has_key(self,key): return self._container.has_key(key)
-
-    def items(self):
-        return map(lambda k, d=self: (k,d[k]), self.keys())
-
-    def keys(self):
-        try: return list(self._v_keys) # return a copy (Collector 2283)
-        except: pass
-        keys=self._v_keys=filter(
-            lambda k: not isinstance(k,types.StringType) or k[:1]!='_',
-            self._container.keys())
-        keys.sort()
-        return list(keys)
+        self.__super_clear()
+        self._p_changed = 1
 
     def update(self, b):
-        a=self._container
-        for k, v in b.items(): a[k] = v
-        try: del self._v_keys
-        except: pass
-        self._p_changed=1
-
-    def values(self):
-        return map(lambda k, d=self: d[k], self.keys())
-
-    def __cmp__(self,other):
-        return cmp(self._container, other._container)
+        self.__super_update(b)
+        self._p_changed = 1
 
+    def setdefault(self, key, failobj=None):
+        # We could inline all of UserDict's implementation into the
+        # method here, but I'd rather not depend at all on the
+        # implementation in UserDict (simple as it is).
+        if not self.has_key(key):
+            self._p_changed = 1
+        return self.__super_setdefault(key, failobj)
+
+    def popitem(self):
+        self._p_changed = 1
+        return self.__super_popitem()