[Checkins] SVN: mongopersist/trunk/ - Implemented several more mapping methods for the Mongo Container, so that

Stephen Richter cvs-admin at zope.org
Mon Apr 2 14:06:06 UTC 2012


Log message for revision 124881:
  - Implemented several more mapping methods for the Mongo Container, so that
    all methods getting the full list of items are fast now.
  
  - Bug: When looking for an item by key/name (``find_*()`` methods) , you would
    never get the right object back, but the first one found in the
    database. This was due to clobbering the search filter with more general
    parameters.
  
  

Changed:
  U   mongopersist/trunk/CHANGES.txt
  U   mongopersist/trunk/src/mongopersist/performance.py
  U   mongopersist/trunk/src/mongopersist/zope/container.py
  U   mongopersist/trunk/src/mongopersist/zope/interfaces.py
  U   mongopersist/trunk/src/mongopersist/zope/tests/test_container.py

-=-
Modified: mongopersist/trunk/CHANGES.txt
===================================================================
--- mongopersist/trunk/CHANGES.txt	2012-04-02 11:27:33 UTC (rev 124880)
+++ mongopersist/trunk/CHANGES.txt	2012-04-02 14:06:02 UTC (rev 124881)
@@ -2,7 +2,7 @@
 CHANGES
 =======
 
-0.7.0 (2012-03-??)
+0.7.0 (2012-04-??)
 ------------------
 
 - Feature: A new ``IConflictHandler`` interface now controls all aspects of
@@ -73,13 +73,16 @@
     of object and where the documents do not store the type (i.e. it is
     stored in the name map collection).
 
-  - The Zope Container fast load via find() did not work correctly, since
+  - The Mongo Container fast load via find() did not work correctly, since
     setstate() did not change the state from ghost to active and thus the
     state was loaded again from MongoDB and set on the object. Now we use the
     new ``_latest_states`` cache to lookup a document when ``setstate()`` is
     called through the proper channels. Now this "fast load" method truly
     causes O(1) database lookups.
 
+  - Implemented several more mapping methods for the Mongo Container, so that
+    all methods getting the full list of items are fast now.
+
   - Whenever the Mongo Object Id is used as a hash key, use the hash of the id
     instead. The ``__cmp__()`` method of the ``ObjectId`` class is way too
     slow.
@@ -98,7 +101,12 @@
   lower problems (by the ratio of read over modified objects) due to lack of
   full MVCC.
 
+- Bug: When looking for an item by key/name (``find_*()`` methods) , you would
+  never get the right object back, but the first one found in the
+  database. This was due to clobbering the search filter with more general
+  parameters.
 
+
 0.6.1 (2012-03-28)
 ------------------
 

Modified: mongopersist/trunk/src/mongopersist/performance.py
===================================================================
--- mongopersist/trunk/src/mongopersist/performance.py	2012-04-02 11:27:33 UTC (rev 124880)
+++ mongopersist/trunk/src/mongopersist/performance.py	2012-04-02 14:06:02 UTC (rev 124881)
@@ -75,14 +75,22 @@
     # Profile slow read
     transaction.begin()
     t1 = time.time()
-    for name in people:
-        person = people[name]
-        person.name
+    [people[name].name for name in people]
+    #cProfile.runctx(
+    #    '[people[name].name for name in people]', globals(), locals())
     t2 = time.time()
-    cache = dm._object_cache
     transaction.commit()
-    print 'Slow Read:    %.4f secs' % (t2-t1)
+    print 'Slow Read:        %.4f secs' % (t2-t1)
 
+    # Profile fast read (values)
+    transaction.begin()
+    t1 = time.time()
+    [person.name for person in people.values()]
+    #cProfile.runctx(
+    #    '[person.name for person in people.find()]', globals(), locals())
+    t2 = time.time()
+    print 'Fast Read (values): %.4f secs' % (t2-t1)
+
     # Profile fast read
     transaction.begin()
     t1 = time.time()
@@ -90,7 +98,7 @@
     #cProfile.runctx(
     #    '[person.name for person in people.find()]', globals(), locals())
     t2 = time.time()
-    print 'Fast Read:    %.4f secs' % (t2-t1)
+    print 'Fast Read (find):   %.4f secs' % (t2-t1)
 
     # Profile modification
     t1 = time.time()
@@ -103,7 +111,7 @@
     #cProfile.runctx(
     #    'modify()', globals(), locals())
     t2 = time.time()
-    print 'Modification: %.4f secs' % (t2-t1)
+    print 'Modification:     %.4f secs' % (t2-t1)
 
     if options.delete:
         # Profile deletion
@@ -112,7 +120,7 @@
             del people[name]
         transaction.commit()
         t2 = time.time()
-        print 'Deletion:     %.4f secs' % (t2-t1)
+        print 'Deletion:         %.4f secs' % (t2-t1)
 
 parser = optparse.OptionParser()
 parser.usage = '%prog [options]'

Modified: mongopersist/trunk/src/mongopersist/zope/container.py
===================================================================
--- mongopersist/trunk/src/mongopersist/zope/container.py	2012-04-02 11:27:33 UTC (rev 124880)
+++ mongopersist/trunk/src/mongopersist/zope/container.py	2012-04-02 14:06:02 UTC (rev 124881)
@@ -149,6 +149,11 @@
             filter[self._m_parent_key] = gs(self._m_get_parent_key_value())
         return filter
 
+    def _m_add_items_filter(self, filter):
+        for key, value in self._m_get_items_filter().items():
+            if key not in filter:
+                filter[key] = value
+
     def _load_one(self, doc):
         # Create a DBRef object and then load the full state of the object.
         dbref = pymongo.dbref.DBRef(
@@ -206,17 +211,29 @@
         # Send the uncontained event.
         contained.uncontained(value, self, key)
 
+    def __contains__(self, key):
+        return self.raw_find_one(
+            {self._m_mapping_key: key}, fields=()) is not None
+
+    def __iter__(self):
+        result = self.raw_find(
+            {self._m_mapping_key: {'$ne': None}}, fields=(self._m_mapping_key,))
+        for doc in result:
+            yield doc[self._m_mapping_key]
+
     def keys(self):
-        filter = self._m_get_items_filter()
-        filter[self._m_mapping_key] = {'$ne': None}
-        coll = self.get_collection()
-        return [doc[self._m_mapping_key]
-                for doc in coll.find(filter, fields=(self._m_mapping_key,))]
+        return list(self.__iter__())
 
+    def iteritems(self):
+        result = self.raw_find()
+        for doc in result:
+            obj = self._load_one(doc)
+            yield doc[self._m_mapping_key], obj
+
     def raw_find(self, spec=None, *args, **kwargs):
         if spec is None:
             spec  = {}
-        spec.update(self._m_get_items_filter())
+        self._m_add_items_filter(spec)
         coll = self.get_collection()
         return coll.find(spec, *args, **kwargs)
 
@@ -232,7 +249,7 @@
             spec_or_id  = {}
         if not isinstance(spec_or_id, dict):
             spec_or_id = {'_id': spec_or_id}
-        spec_or_id.update(self._m_get_items_filter())
+        self._m_add_items_filter(spec_or_id)
         coll = self.get_collection()
         return coll.find_one(spec_or_id, *args, **kwargs)
 

Modified: mongopersist/trunk/src/mongopersist/zope/interfaces.py
===================================================================
--- mongopersist/trunk/src/mongopersist/zope/interfaces.py	2012-04-02 11:27:33 UTC (rev 124880)
+++ mongopersist/trunk/src/mongopersist/zope/interfaces.py	2012-04-02 14:06:02 UTC (rev 124881)
@@ -60,6 +60,12 @@
         """Returns a query spec representing a filter that only returns
         objects in this container."""
 
+    def _m_add_items_filter(filter):
+        """Applies the item filter items to the provided filter.
+
+        Keys that are already in the passed in filter are not overwritten.
+        """
+
     def get_collection():
         """Get the Python representation of the collection.
 

Modified: mongopersist/trunk/src/mongopersist/zope/tests/test_container.py
===================================================================
--- mongopersist/trunk/src/mongopersist/zope/tests/test_container.py	2012-04-02 11:27:33 UTC (rev 124880)
+++ mongopersist/trunk/src/mongopersist/zope/tests/test_container.py	2012-04-02 14:06:02 UTC (rev 124881)
@@ -193,6 +193,8 @@
                          ObjectId('4e7e9d3ae138232d7b000000'),
                          u'mongopersist_container_test')}]
 
+      >>> 'stephan' in dm.root['c']
+      True
       >>> dm.root['c'].keys()
       [u'stephan']
       >>> dm.root['c']['stephan'].__parent__
@@ -207,6 +209,9 @@
       ...
       KeyError: 'roy'
 
+      >>> 'roy' in dm.root['c']
+      False
+
     Now remove the item:
 
       >>> del dm.root['c']['stephan']



More information about the checkins mailing list