From 41afb73b7ecb5e5e3e3d0c0d8916554367170c59 Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Sat, 22 Jun 2013 07:19:02 +0000 Subject: fsemulation: don't try to duplicate data store / Xapian matching _matches_root_query() was meant to verify that a requested entity has actually been exported by the user (using root_query). But in order to do that, a lot of the matching functionality in the data store (usually implemented using Xapian) would have to be duplicated for any except the most basic export selections to work. E.g. exporting based on tags needs to work on parts (words) of a single value, rather than an exact match on the full string. Instead, let the data store do the verification by using its searching API even if we already know the object id. There's some performance impact to this, but it's not clear a reasonably functional _matches_root_query() would be much faster. --- diff --git a/fsemulation.py b/fsemulation.py index 26b5cb9..beade38 100644 --- a/fsemulation.py +++ b/fsemulation.py @@ -135,8 +135,8 @@ class DataStore(object): Only return the latest version of each entry for data stores with version support. """ - query = dict(query or {}) - query.update(self._root_query) + query = self._merge_root_query(query) + if self._data_store.dbus_interface == DS_DBUS_INTERFACE2: options = {'metadata': ['tree_id', 'version_id'], 'order_by': ['-timestamp']} @@ -165,8 +165,7 @@ class DataStore(object): Returns a list of tuples containing the object_id and metadata. """ - query = dict(query or {}) - query.update(self._root_query) + query = self._merge_root_query(query) properties = list(_USEFUL_PROPS) if self._data_store.dbus_interface == DS_DBUS_INTERFACE2: @@ -205,15 +204,15 @@ class DataStore(object): @synchronised def list_tree_ids(self, query=None): """Retrieve the tree_ids of all (matching) data store entries""" + query = self._merge_root_query(query) return [unicode(entry[0]) for entry in self.list_object_ids(query)] @synchronised def list_property_values(self, name, query=None): """Return all unique values of the given property""" assert isinstance(name, unicode) + query = self._merge_root_query(query) - query = dict(query or {}) - query.update(self._root_query) if self._data_store.dbus_interface == DS_DBUS_INTERFACE2: options = {'metadata': [name], 'all_versions': True} entries = self._data_store.find(query, options, @@ -239,7 +238,7 @@ class DataStore(object): return False raise - return self._matches_root_query(entry) + return True @synchronised def check_tree_id(self, tree_id): @@ -306,11 +305,17 @@ class DataStore(object): else: assert isinstance(object_id, unicode) + query['uid'] = object_id + results = self._data_store.find(query, names or [], + timeout=DBUS_TIMEOUT_MAX, + byte_arrays=True)[0] + metadata = self._data_store.get_properties(object_id, byte_arrays=True) - if not self._matches_root_query(metadata): + if not results: raise ValueError('Object %r does not exist' % (object_id, )) + metadata = results[0] metadata['uid'] = object_id if names: metadata = dict([(name, metadata[name]) for name in names @@ -469,10 +474,14 @@ class DataStore(object): timeout=DBUS_TIMEOUT_MAX) return unicode(object_id) - def _matches_root_query(self, metadata): - """Return True if metadata matches the root query""" - return not [True for key, value in self._root_query.items() - if metadata.get(key) != value] + def _merge_root_query(self, query): + query = dict(query or {}) + xapian_query = query.get('query', '') + query.update(self._root_query) + if ('query' in self._root_query) and xapian_query: + query['query'] = '(%s) AND (%s)' % (self._root_query['query'], + xapian_query) + return query def _convert_metadata(self, metadata): """Convert metadata (as returned by the data store) to a unicode dict -- cgit v0.9.1