TODO

(A)synchronicity of API calls

Notes

Requirements

ID / metadata definitions

Used by datastore:
tree_id
Identifies the ancestry graph (i.e. all versions) of an entry. Should be treated as an opaque string by API consumers. Potentially unique across systems (UUID).
version_id
Identifies a specific version of an object. Should be treated as an opaque string by API consumers. Usually combined with tree_id but unique on its own, potentially across systems (UUID).
parent_id
The version_id of the parent of an object, set by datastore. Empty for the root of the ancestry graph.
ctime
Unix timestamp of creation time of an entry, set by datastore. Not updated on changes of the version-specific metadata.
Not used by datastore:
bundle_id
bundle_id of the Activity template associated with the entry. Only set for session continuation objects. Will be used for resuming the session.
entry_type
Valid values are action and object. Intended for use by Journal for implementing action-oriented view.
creator
bundle_id of the Activity template the entry has been created by (e.g. org.laptop.WebActivity for downloaded files).
mime_type
MIME type of data, used for determining compatible Activity templates.

Workflows

data+metadata creates / updates

metadata changes (to existing versions)

crash recovery

checkout

search

delete

API

Current datastore DBus API

Functions and signals

create(properties, filename, transfer_ownership)
Create new journal object with metadata given in properties, returns uid / object_id. If transfer_ownership is False the data store will make a copy of the file. Metadata storage and index update is synchronous and while file storage and optimizer run in a separate thread, the API call actually only returns after everything is done (including emitting a Created(uid) signal) and thus is fully synchronous. Returns uid (object_id).
update(uid, properties, filename, transfer_ownership)
Submit new version (currently replacing the old version) and/or new metadata of the object identified by uid (object_id). Similar to create() Metadata storage and index update is synchronous, file storage and optimizer run in a separate thread, but the API call only returns after everything is done, including emitting an Updated(uid) signal. Doesn't return anything.
delete(uid)
Remove given object from data store. Fully synchronous. Doesn't return anything, emits signal Deleted(uid).
get_properties(uid)
Returns (full) metadata for given object. Fully synchronous.
get_filename(uid)
Hardlinks or symlinks the given object into a global directory and returns the filename. Fully synchronous.
find(query, properties)
Finds entries matching query in the index, returning the values of the requested properties. If the index is unavailable, all entries are returned (but taking limit and offset into account). query is a dictionary and may contain propertyname=value mappings (that are directly matched against metadata - only timestamp (with a range), uid, activity, activity_id, keep and mime_type are supported so far) in addition to values for limit (max. number of results), offset (skip given number of results) and query ("full-text" search in all properties). Returns estimated number of matching entries (not affected by limit and offset) and requested metadata for matching entries.

Journal passes sort=-mtime in query; datastore currently ignores it (but sorts by timestamp anyway).

get_uniquevaluesfor(propertyname, query)
Supposedly would returns a list of all (unique) values associated with given property (metadata) name for all datastore entries matching query. Only supports propertyname='activity' and query=None, so a list of all activities (activity / bundle_id) is returned.
mount(uri, options)
Compat only. Noop, returns ''.
unmount(mount_point_id)
Compat only. Noop, doesn't return anything.
mounts()
Compat only. Noop, returns [{'id': 1}].
Stopped()
Signal emitted after datastore has been shut down.

Proposed datastore DBus API

Functions and signals

save(tree_id, parent_id, metadata, path, delete_after)

Submit new version (data and/or metadata) of the given object, returns tree_id, child_id. parent_id and child_id are the version_id of the predecessor resp. the to-be-saved entry.

If tree_id is empty parent_id must be empty as well and both will be newly allocated (equivalent to create() in previous API). If only parent_id is empty there must not be any entry with the same tree_id already in datastore.

Actual file storage and index update happen asynchronously, emitting the signal Saved(tree_id, parent_id, child_id) on completion.

If path is non-empty it designates a file or directory containing the data and the parent must contain of the same type (file / directory; not metadata-only), if a parent exists at all. If path is empty and the parent contained data then a metadata-only update is performed, reusing the data of the parent. If both parent_id and path are empty a metadata-only entry is created.

If delete_after is True the contents of path are deleted after they have been committed, but before sending the signal.

change_metadata(tree_id, version_id, metadata)
Changes the (unversioned/version-specific) metadata of the given object to match metadata. Fully synchronous, no return value. Emits signal ChangedMetadata(tree_id, version_id, metadata).
delete(tree_id)
Remove (all versions of) given object from data store. Fully synchronous. Doesn't return anything, emits signal Deleted(tree_id).
get_data(tree_id, version_id)
Hardlinks the given object into a global directory, making it readable (directories also writable) to the caller. Returns the path after checking the entry for validity; actual data is written asynchronously. Emits signal GotData(sender, tree_id, version_id, path) where sender is the bus name of the sender.
find(query, options)
Finds entries matching query and returns output according to options, including the number of matches (unaffected by limit) and the tree_id / version_id of each entry.

query is a dictionary with metadata names as keys and either basic types (exact/wildcard match), 2-tuples (range) or a list (multiple exact/wildcard matches) as values. Prefixing a key name with '!' inverts the sense of matching, OPTIONAL: prefixing it with '*' enables regular expression search (slow). An empty dictionary matches everything. Arbitrary key names are allowed, but speed may vary (i.e. not everything is indexed).

options is a dictionary which may contain values for the following keys:

metadata
gives a list of metadata names that should be returned for each entry; default is everything
all_versions
if True returns all matching versions of an object instead of only the latest one
sort
sort by given metadata name (does not need to be listed in metadata); prefix '+' for ascending order, prefix '-' for descending order; default is undefined, potentially by relevance
limit
only return the given number of results (starting at first match in sort order, subject to offset
offset
skip the given number of results

textsearch(querystring, query, options)
Preliminary API call for IR search using Xapian. Likely to be replaced for next version. querystring is passed to Xapians query parser; query and options are interpreted like for find(). Returns the same format as find().
find_unique_values(query, metadata_name)
Similar find(...), but returns the set of unique values for the requested metadata name.
check_ready()
Returns True if datastore is ready for processing (regular) API calls. False during startup / recovery.
Ready()
Signal emitted after datastore is ready for processing API calls.
Stopped()
Signal emitted after datastore has been shut down.

Exceptions

sugar.datastore.NoSpaceLeftError
There's not enough space left on disk to safely store data and/or metadata. Operation aborted, everything still at the previous state.
sugar.datastore.InvalidArgumentError
One or several of the passed parameters (or the combination thereof) were invalid. See formatted string for details. This should only happen if the caller is buggy.
sugar.datastore.CorruptionError
The internal data structures of datastore or one of its backends are corrupted. Should only happen in case of hardware defects or OS bugs.
sugar.datastore.BusyError
Datastore is busy recovering from a crash. Please wait for Ready() before starting to issue any API call (except check_ready()).