Skip to content
This repository has been archived by the owner on May 13, 2020. It is now read-only.

Commit

Permalink
- Implemented several more mapping methods for the Mongo Container, s…
Browse files Browse the repository at this point in the history
…o 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.
  • Loading branch information
strichter committed Apr 2, 2012
1 parent 0d7210f commit 32cd056
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 17 deletions.
12 changes: 10 additions & 2 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -73,13 +73,16 @@ CHANGES
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.
Expand All @@ -98,6 +101,11 @@ CHANGES
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)
------------------
Expand Down
24 changes: 16 additions & 8 deletions src/mongopersist/performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,21 @@ def run_basic_crud(options):
# 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()
Expand All @@ -90,7 +98,7 @@ def run_basic_crud(options):
#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()
Expand All @@ -103,7 +111,7 @@ def modify():
#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
Expand All @@ -112,7 +120,7 @@ def modify():
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]'
Expand Down
31 changes: 24 additions & 7 deletions src/mongopersist/zope/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ def _m_get_items_filter(self):
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(
Expand Down Expand Up @@ -206,17 +211,29 @@ def __delitem__(self, key):
# 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)

Expand All @@ -232,7 +249,7 @@ def raw_find_one(self, spec_or_id=None, *args, **kwargs):
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)

Expand Down
6 changes: 6 additions & 0 deletions src/mongopersist/zope/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ def _m_get_items_filter():
"""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.
Expand Down
5 changes: 5 additions & 0 deletions src/mongopersist/zope/tests/test_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ def doctest_MongoContainer_basic():
ObjectId('4e7e9d3ae138232d7b000000'),
u'mongopersist_container_test')}]
>>> 'stephan' in dm.root['c']
True
>>> dm.root['c'].keys()
[u'stephan']
>>> dm.root['c']['stephan'].__parent__
Expand All @@ -207,6 +209,9 @@ def doctest_MongoContainer_basic():
...
KeyError: 'roy'
>>> 'roy' in dm.root['c']
False
Now remove the item:
>>> del dm.root['c']['stephan']
Expand Down

0 comments on commit 32cd056

Please sign in to comment.