Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Silbe <sascha@silbe.org>2009-07-10 17:11:15 (GMT)
committer Sascha Silbe <sascha@silbe.org>2009-07-10 17:11:15 (GMT)
commit5aeb9953c1b547f8a4af76641de3659f17366540 (patch)
tree8248150117701cc7b3bfe725e370da02384284c7
parenta93f49a1faac631cdebe2d9b1ba17615ad3bcadd (diff)
change to proposed API
-rw-r--r--src/carquinyol/datastore.py202
-rw-r--r--src/carquinyol/filestore.py5
-rw-r--r--src/carquinyol/indexstore.py8
3 files changed, 166 insertions, 49 deletions
diff --git a/src/carquinyol/datastore.py b/src/carquinyol/datastore.py
index f0f51cd..0d81063 100644
--- a/src/carquinyol/datastore.py
+++ b/src/carquinyol/datastore.py
@@ -25,6 +25,7 @@ import dbus
import gobject
from sugar import mime
+import sugar.datastore
from carquinyol import trace
from carquinyol import layoutmanager
@@ -109,6 +110,7 @@ class DataStore(dbus.service.Object):
if not tvids:
logging.debug('Finished updating index.')
layoutmanager.get_instance().index_updated = True
+ self.Ready()
return False
else:
return True
@@ -131,22 +133,12 @@ class DataStore(dbus.service.Object):
byte_arrays=True)
def create(self, props, file_path, transfer_ownership,
async_cb, async_err_cb):
- tree_id = str(uuid.uuid4())
- version_id = str(uuid.uuid4()) # use fake for now
- logging.debug('datastore.create %r %r' % (tree_id, version_id))
-
- if not props.get('timestamp', ''):
- props['timestamp'] = int(time.time())
-
- self._metadata_store.store(tree_id, version_id, props)
- self._index_store.store(tree_id, version_id, props)
- self._file_store.store(tree_id, version_id, file_path, transfer_ownership,
- lambda *args: self._create_completion_cb(async_cb,
- async_err_cb,
- tree_id,
- version_id,
- *args))
- return (tree_id, version_id)
+ """
+ Short-term compatibility wrapper for save().
+ """
+ tree_id, child_id = self.save('', '', props, file_path, transfer_ownership)
+ self.Created(tree_id, child_id)
+ return (tree_id, child_id)
@dbus.service.signal(DS_DBUS_INTERFACE, signature="ss")
def Created(self, tree_id, version_id):
@@ -171,42 +163,112 @@ class DataStore(dbus.service.Object):
@trace(skip_args=[3], skip_kwargs=["props"]) # "preview" metadata will clutter logfile otherwise
def update(self, tree_id, version_id, props, file_path, transfer_ownership,
async_cb, async_err_cb):
-
- if not props.get('timestamp', ''):
- props['timestamp'] = int(time.time())
-
- # TODO: create branch if required (inside some abstraction layer)
+ """
+ Short-term compatibility wrapper for save() / change_metadata().
+ """
if file_path :
- # only for data updates
- props['parent_id'] = version_id
- version_id = str(uuid.uuid4())
+ tree_id, child_id = self.save(tree_id, version_id, props, file_path, transfer_ownership)
+ else :
+ self.change_metadata(tree_id, version_id, props)
+ child_id = version_id
- self._metadata_store.store(tree_id, version_id, props)
- self._index_store.store(tree_id, version_id, props)
-
- self._file_store.store(tree_id, version_id, file_path, transfer_ownership,
- lambda *args: self._update_completion_cb(async_cb,
- async_err_cb,
- tree_id,
- version_id,
- *args))
- return (tree_id, version_id)
+ self.Updated(tree_id, child_id)
+ return (tree_id, child_id)
@dbus.service.signal(DS_DBUS_INTERFACE, signature="ss")
def Updated(self, tree_id, version_id):
pass
@dbus.service.method(DS_DBUS_INTERFACE,
- in_signature='a{sv}as',
+ in_signature='ssa{sv}sb',
+ out_signature='ss',
+ byte_arrays=True)
+ @trace(skip_args=[3], skip_kwargs=["metadata"]) # "preview" metadata will clutter logfile otherwise
+ def save(self, tree_id, parent_id, metadata, path, delete_after):
+ # TODO: copy docstring from datastore-redesign.html
+ if (not tree_id) and parent_id :
+ raise sugar.datastore.InvalidArgumentError("tree_id is empty but parent_id is not")
+
+ if tree_id and not parent_id :
+ # TODO: check tree_id does not exist yet
+ pass
+
+ elif parent_id :
+ # TODO: check parent_id does exist
+ pass
+
+ if not tree_id :
+ tree_id = self._gen_uuid()
+
+ child_id = self._gen_uuid()
+
+ # TODO: create branch if required
+
+ metadata['ctime'] = int(time.time())
+ metadata['tree_id'] = tree_id
+ metadata['parent_id'] = parent_id
+ metadata['version_id'] = child_id
+
+ self._metadata_store.store(tree_id, child_id, metadata)
+ # TODO: async
+ self._index_store.store(tree_id, child_id, metadata)
+
+ if (not path) and self._file_store.has_data(tree_id, parent_id) :
+ # metadata-only update, reuse parent data
+ path = self._file_store.retrieve(tree_id, parent_id, os.getuid(), "foo")
+
+ if path:
+ self._file_store.store(tree_id, child_id, path, delete_after,
+ lambda *args: self._save_completion_cb(tree_id, parent_id, child_id, *args))
+
+ return (tree_id, child_id)
+
+ @trace()
+ def _save_completion_cb(self, tree_id, parent_id, child_id, exc=None):
+ if exc is not None:
+ logging.error("Error during saving of entry (%r,%r,%r):\n%s" % (
+ tree_id, parent_id, child_id, traceback.format_exc(),))
+ # FIXME: what to do on error? for the async API we already guaranteed ACID
+ return
+
+ self.Saved(tree_id, parent_id, child_id)
+ self._optimizer.optimize(tree_id, child_id)
+ logger.debug("updated %s %s" % (tree_id, child_id))
+
+ @dbus.service.signal(DS_DBUS_INTERFACE, signature="sss")
+ def Saved(self, tree_id, parent_id, child_id):
+ # TODO: copy docstring from datastore-redesign.html
+ pass
+
+ @dbus.service.method(DS_DBUS_INTERFACE,
+ in_signature='ssa{sv}',
+ out_signature='',
+ byte_arrays=True)
+ @trace(skip_args=[3], skip_kwargs=["metadata"]) # "preview" metadata will clutter logfile otherwise
+ def change_metadata(self, tree_id, version_id, metadata) :
+ # TODO: copy docstring from datastore-redesign.html
+ # TODO
+ pass
+
+ @dbus.service.method(DS_DBUS_INTERFACE,
+ in_signature='a{sv}a{sv}',
out_signature='aa{sv}u')
@trace()
- def find(self, query, properties):
+ def find(self, query, options, querystring = None):
t = time.time()
+ # don't expose internal details
+ # FIXME: short-term compatibility option
+ #if 'query' in query :
+ # del query['query']
+
+ if querystring :
+ query['query'] = querystring
+
tvids = None
if layoutmanager.get_instance().index_updated:
try:
- tvids, count = self._index_store.find(query)
+ tvids, count = self._index_store.find(query, options)
except Exception:
logging.error('Failed to query index, will rebuild\n%s' \
% traceback.format_exc())
@@ -216,11 +278,11 @@ class DataStore(dbus.service.Object):
self._index_store.open_index()
self._rebuild_index()
- if tvids is None :
+ if not layoutmanager.get_instance().index_updated:
logging.warning('Index updating, returning all entries')
tvids = layoutmanager.get_instance().find_all()
- if not query.get('all_versions', False) :
+ if not options.get('all_versions', False) :
# only return latest version for each entry
tids_vtime = {}
for (tree_id, version_id) in tvids :
@@ -231,14 +293,14 @@ class DataStore(dbus.service.Object):
count = len(tvids)
- offset = query.get('offset', 0)
- limit = query.get('limit', MAX_QUERY_LIMIT)
+ offset = options.get('offset', 0)
+ limit = options.get('limit', MAX_QUERY_LIMIT)
tvids = tvids[offset:offset + limit]
# logger.debug('tvids=%r' % (tvids,))
entries = []
for (tree_id,version_id) in tvids:
- metadata = self._metadata_store.retrieve(tree_id, version_id, properties)
+ metadata = self._metadata_store.retrieve(tree_id, version_id, options.get('metadata'))
entries.append(metadata)
logger.debug('find(): %r' % (time.time() - t))
@@ -247,14 +309,40 @@ class DataStore(dbus.service.Object):
return entries, count
@dbus.service.method(DS_DBUS_INTERFACE,
+ in_signature='sa{sv}a{sv}',
+ out_signature='aa{sv}u')
+ @trace()
+ def textsearch(self, querystring, query, options) :
+ return self.find(query, options, querystring = querystring)
+
+ @dbus.service.method(DS_DBUS_INTERFACE,
in_signature='ss',
out_signature='s',
sender_keyword='sender')
@trace()
def get_filename(self, tree_id, version_id, sender=None):
+ """
+ Short-term compatibility wrapper for get_filename().
+ """
+ return self.get_data(uid, vid, sender)
+
+ @dbus.service.method(DS_DBUS_INTERFACE,
+ in_signature='ss',
+ out_signature='s',
+ sender_keyword='sender')
+ @trace()
+ def get_data(self, tree_id, version_id, sender=None):
+ # TODO: copy docstring from datastore-redesign.html
user_id = dbus.Bus().get_unix_user(sender)
- extension = self._get_extension(tree_id,version_id)
- return self._file_store.retrieve(tree_id, version_id, user_id, extension)
+ extension = self._get_extension(tree_id, version_id)
+ # TODO: async
+ path = self._file_store.retrieve(tree_id, version_id, user_id, extension)
+ self.GotData(sender, tree_id, version_id, path)
+ return path
+
+ @dbus.service.signal(DS_DBUS_INTERFACE, signature="ssss")
+ def GotData(self, sender, tree_id, version_id, path) :
+ pass
def _get_extension(self, tree_id, version_id):
mime_type = self._metadata_store.get_property(tree_id, version_id, 'mime_type')
@@ -274,7 +362,18 @@ class DataStore(dbus.service.Object):
in_signature='sa{sv}',
out_signature='as')
def get_uniquevaluesfor(self, propertyname, query=None):
- if propertyname != 'bundle_id':
+ """
+ Short-term compatibility wrapper for find_unique_values().
+ """
+ return self.find_unique_values(query, propertyname)
+
+ @dbus.service.method(DS_DBUS_INTERFACE,
+ in_signature='sa{sv}',
+ out_signature='as')
+ def find_unique_values(self, query, metadata_name):
+ # TODO: copy docstring
+ # TODO: support for arbitrary metadata names and query
+ if metadata_name != 'bundle_id':
raise ValueError('Only ''bundle_id'' is a supported property name')
if query:
raise ValueError('The query parameter is not supported')
@@ -314,3 +413,16 @@ class DataStore(dbus.service.Object):
def Stopped(self):
pass
+ @dbus.service.method(DS_DBUS_INTERFACE,
+ in_signature='',
+ out_signature='b')
+ def check_ready(self):
+ return layoutmanager.get_instance().index_updated
+
+ @dbus.service.signal(DS_DBUS_INTERFACE)
+ def Ready(self):
+ pass
+
+ def _gen_uuid(self) :
+ return str(uuid.uuid4())
+
diff --git a/src/carquinyol/filestore.py b/src/carquinyol/filestore.py
index d34e3b1..eebec8c 100644
--- a/src/carquinyol/filestore.py
+++ b/src/carquinyol/filestore.py
@@ -75,6 +75,11 @@ class FileStore(object):
async_copy = AsyncCopy(file_path, destination_path, completion_cb)
async_copy.start()
+ def has_data(self, tree_id, version_id) :
+ dir_path = layoutmanager.get_instance().get_entry_path(tree_id, version_id)
+ file_path = os.path.join(dir_path, 'data')
+ return os.path.exists(file_path)
+
def retrieve(self, tree_id, version_id, user_id, extension):
"""Place the file associated to a given entry into a directory where the
user can read it. The caller is reponsible for deleting this file.
diff --git a/src/carquinyol/indexstore.py b/src/carquinyol/indexstore.py
index 3a00c25..387f7bb 100644
--- a/src/carquinyol/indexstore.py
+++ b/src/carquinyol/indexstore.py
@@ -127,12 +127,12 @@ class IndexStore(object):
text += value
return text
- def find(self, query):
+ def find(self, query, options):
enquire = Enquire(self._database)
- offset = query.pop('offset', 0)
- limit = query.pop('limit', MAX_QUERY_LIMIT)
- all_versions = query.pop('all_versions', False)
+ offset = options.pop('offset', 0)
+ limit = options.pop('limit', MAX_QUERY_LIMIT)
+ all_versions = options.pop('all_versions', False)
enquire.set_query(self._parse_query(query))