Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/olpc/datastore/datastore.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/olpc/datastore/datastore.py')
-rw-r--r--src/olpc/datastore/datastore.py119
1 files changed, 66 insertions, 53 deletions
diff --git a/src/olpc/datastore/datastore.py b/src/olpc/datastore/datastore.py
index d197eda..3c99177 100644
--- a/src/olpc/datastore/datastore.py
+++ b/src/olpc/datastore/datastore.py
@@ -406,10 +406,20 @@ class DataStore(dbus.service.Object):
@dbus.service.signal(DS_DBUS_INTERFACE, signature="s")
def Created(self, uid): pass
+
+ def _single_search(self, mountpoint, query, order_by, limit):
+ results, count = mountpoint.find(query.copy(), order_by, limit)
+ return list(results), count, 1
- def _multiway_search(self, query):
+ def _multiway_search(self, query, order_by=None, limit=None):
mountpoints = query.pop('mountpoints', self.mountpoints)
mountpoints = [self.mountpoints[str(m)] for m in mountpoints]
+
+
+ if len(mountpoints) == 1:
+ # Fast path the single mountpoint case
+ return self._single_search(mountpoints[0], query, order_by, limit)
+
results = []
# XXX: the merge will become *much* more complex in when
# distributed versioning is implemented.
@@ -417,7 +427,7 @@ class DataStore(dbus.service.Object):
# some queries mutate the query-dict so we pass a copy each
# time
for mp in mountpoints:
- result, count = mp.find(query.copy())
+ result, count = mp.find(query.copy(), order_by, limit)
results.append(result)
# merge
@@ -430,7 +440,7 @@ class DataStore(dbus.service.Object):
# XXX: age/version check
d[hit.id] = hit
- return d, len(d)
+ return d, len(d), len(results)
@dbus.service.method(DS_DBUS_INTERFACE,
in_signature='a{sv}',
@@ -482,8 +492,10 @@ class DataStore(dbus.service.Object):
# distribute the search to all the mountpoints unless a
# backingstore id set is specified
- results, count = self._multiway_search(kwargs)
-
+ # backends may be able to return sorted results, if there is
+ # only a single backend in the query we can use pre-sorted
+ # results directly
+ results, count, results_from = self._multiway_search(kwargs, order_by, limit)
# ordering is difficult when we are dealing with sets from
# more than one source. The model is this.
@@ -491,64 +503,65 @@ class DataStore(dbus.service.Object):
# in post processing. This allows use to assemble partially
# database sorted results from many sources and quickly
# combine them.
- if order_by:
- # resolve key names to columns
- if isinstance(order_by, basestring):
- order_by = [o.strip() for o in order_by.split(',')]
-
- if not isinstance(order_by, list):
- logging.debug("bad query, order_by should be a list of property names")
- order_by = None
-
- # generate a sort function based on the complete set of
- # ordering criteria which includes the primary sort
- # criteria as well to keep it stable.
- def comparator(a, b):
- # we only sort on properties so
- for criteria in order_by:
- mode = 1 # ascending
- if criteria.startswith('-'):
- mode = -1
- criteria = criteria[1:]
- pa = a.get_property(criteria, None)
- pb = b.get_property(criteria, None)
- r = cmp(pa, pb) * mode
- if r != 0: return r
- return 0
-
-
- r = results.values()
- r.sort(comparator)
- results = r
- else:
- results = results.values()
+ if results_from > 1:
+ if order_by:
+ # resolve key names to columns
+ if isinstance(order_by, basestring):
+ order_by = [o.strip() for o in order_by.split(',')]
+
+ if not isinstance(order_by, list):
+ logging.debug("bad query, order_by should be a list of property names")
+ order_by = None
+
+ # generate a sort function based on the complete set of
+ # ordering criteria which includes the primary sort
+ # criteria as well to keep it stable.
+ def comparator(a, b):
+ # we only sort on properties so
+ for criteria in order_by:
+ mode = 1 # ascending
+ if criteria.startswith('-'):
+ mode = -1
+ criteria = criteria[1:]
+ pa = a.get_property(criteria, None)
+ pb = b.get_property(criteria, None)
+ r = cmp(pa, pb) * mode
+ if r != 0: return r
+ return 0
+
+
+ r = results.values()
+ r.sort(comparator)
+ results = r
+ else:
+ results = results.values()
d = []
+ c = 0
+ if results_from == 1:
+ mp = results[0].backingstore.id
+ else:
+ mp = None
+
for r in results:
- props = {}
- props.update(r.properties)
+ props = r.properties
# on versioning stores uid will be different
# than r.id but must be set
- if 'uid' not in props:
- props['uid'] = r.id
+ #if 'uid' not in props:
+ props['uid'] = r.id
- if 'mountpoint' not in props:
- props['mountpoint'] = r.backingstore.id
+ #if 'mountpoint' not in props:
+ props['mountpoint'] = mp and mp or r.backingstore.id
+
+ # filename not included in find results
+ #props['filename'] = ''
- filename = ''
- if include_files :
- try: filename = r.filename
- except KeyError: pass
- # XXX: this means that find never shows the internally
- # stored filename attribute (which is private)
- props['filename'] = filename
d.append(props)
-
- if limit:
- d = d[offset: offset+limit]
+ c+= 1
+ if limit and c > limit: break
- return (d, len(results))
+ return (d, len(d))
def get(self, uid, rev=None, mountpoint=None):
mp = self._resolveMountpoint(mountpoint)