diff options
author | Benjamin Saller <bcsaller@objectrealms.net> | 2007-07-27 21:06:56 (GMT) |
---|---|---|
committer | Benjamin Saller <bcsaller@objectrealms.net> | 2007-07-27 21:06:56 (GMT) |
commit | 21b3150356031bfed0e833d148c4f370364c3164 (patch) | |
tree | 8029d47b603d4a5824a0685b4edcb99cfbdc72a9 /src | |
parent | ad0cad894d78da610ccdb3cea6b8df6539f3a2bf (diff) |
proposed fixes for:
#2057 #2445 #2459
Diffstat (limited to 'src')
-rw-r--r-- | src/olpc/datastore/backingstore.py | 67 | ||||
-rw-r--r-- | src/olpc/datastore/datastore.py | 90 |
2 files changed, 107 insertions, 50 deletions
diff --git a/src/olpc/datastore/backingstore.py b/src/olpc/datastore/backingstore.py index 8903df7..f163755 100644 --- a/src/olpc/datastore/backingstore.py +++ b/src/olpc/datastore/backingstore.py @@ -101,7 +101,14 @@ class BackingStore(object): @property def title(self): return self.descriptor()['title'] - + # Storage Translation + def localizedName(self, uid=None, content=None, target=None): + """taking any of uid, a content object, or a direct target + filename (which includes all of the relative components under a + store). Return the localized filename that should be used _within_ + the repository for the storage of this content object + """ + pass class FileBackingStore(BackingStore): @@ -141,18 +148,23 @@ class FileBackingStore(BackingStore): # a hidden file with a pickled dict will live in the base # directory for each storage fn = os.path.join(self.base, self.DESCRIPTOR_NAME) - if not os.path.exists(fn): + if os.path.exists(fn): + try: + fp = open(fn, 'r') + desc = pickle.load(fp) + fp.close() + except: + desc = None + if not desc: # the data isn't there, this could happen for a number of # reasons (the store isn't writeable) + # or if the information on it was corrupt + # in this case, just create a new one desc = {'id' : self.uri, 'uri' : self.uri, 'title' : self.uri } self.create_descriptor(**desc) - else: - fp = open(fn, 'r') - desc = pickle.load(fp) - fp.close() return desc @@ -166,8 +178,12 @@ class FileBackingStore(BackingStore): desc = {} if os.path.exists(fn): fp = open(fn, 'r') - desc = pickle.load(fp) - fp.close() + try: + desc = pickle.load(fp) + except: + desc = {} + finally: + fp.close() desc.update(kwargs) @@ -233,6 +249,27 @@ class FileBackingStore(BackingStore): ## signal from datastore that we are being bound to it self.datastore = datastore + def localizedName(self, uid=None, content=None, target=None): + """taking any of uid, a content object, or a direct target + filename (which includes all of the relative components under a + store). Return the localized filename that should be used _within_ + the repository for the storage of this content object + """ + if target: return os.path.join(self.base, target) + elif content: + # see if it expects a filename + fn, ext = content.suggestName() + if fn: return os.path.join(self.base, fn) + if ext: return os.path.join(self.base, "%s.%s" % + (content.id, ext)) + if not uid: uid = content.id + + if uid: + return os.path.join(self.base, uid) + else: + raise ValueError("""Nothing submitted to generate internal + storage name from""") + def _translatePath(self, uid): """translate a UID to a path name""" # paths into the datastore @@ -243,7 +280,7 @@ class FileBackingStore(BackingStore): path = self._translatePath(uid) if not os.path.exists(path): return None - + if target: targetpath = target else: targetpath = uid.replace('/', '_').replace('.', '__') @@ -301,8 +338,11 @@ class FileBackingStore(BackingStore): raise ValueError("Content for %s corrupt" % uid) return content - def _writeContent(self, uid, filelike, replace=True): - path = self._translatePath(uid) + def _writeContent(self, uid, filelike, replace=True, target=None): + if target: path = target + else: + path = self._translatePath(uid) + if replace is False and os.path.exists(path): raise KeyError("objects with path:%s for uid:%s exists" %( path, uid)) @@ -484,7 +524,7 @@ class InplaceFileBackingStore(FileBackingStore): def _translatePath(self, uid): try: content = self.indexmanager.get(uid) except KeyError: return None - return os.path.join(self.uri, content.get_property('filename')) + return os.path.join(self.uri, content.get_property('filename', uid)) ## def _targetFile(self, uid, target=None, ext=None, env=None): ## # in this case the file should really be there unless it was @@ -513,7 +553,7 @@ class InplaceFileBackingStore(FileBackingStore): proposed_name = os.path.split(filelike.name)[1] proposed_name = os.path.join(self.uri, proposed_name) if not os.path.exists(proposed_name): - self._writeContent(uid, filelike, replace=False) + self._writeContent(uid, filelike, replace=False, target=proposed_name) return uid @@ -532,6 +572,7 @@ class InplaceFileBackingStore(FileBackingStore): c = self.indexmanager.get(uid) path = c.get_property('filename', None) self.indexmanager.delete(uid) + path = os.path.join(self.uri, path) if path and os.path.exists(path): os.unlink(path) diff --git a/src/olpc/datastore/datastore.py b/src/olpc/datastore/datastore.py index 111548c..34f5ba3 100644 --- a/src/olpc/datastore/datastore.py +++ b/src/olpc/datastore/datastore.py @@ -82,6 +82,8 @@ class DataStore(dbus.service.Object): self.mountpoints[mp.id] = mp if self.root is None: self.root = mp + + self.Mounted(mp.descriptor()) return mp.id @dbus.service.method(DS_DBUS_INTERFACE, @@ -103,42 +105,52 @@ class DataStore(dbus.service.Object): def unmount(self, mountpoint_id): """Unmount a mountpoint by id""" if mountpoint_id not in self.mountpoints: return - self.mountpoints[mountpoint_id].stop() + mp = self.mountpoints[mountpoint_id] + mp.stop() + self.Unmounted(mp.descriptor()) del self.mountpoints[mountpoint_id] - ### End Mount Points - - ### Buddy Management - ## A single datastore typically refers to a single user - ## this breaks down a little in the case of things like USB - ## sticks and so on. We provide a facility for tracking - ## co-authors of content - ## there are associated changes to 'find' to resolve buddies - def addBuddy(self, id, name, fg_color, bg_color, mountpoint=None): - mp = None - if mountpoint is None: mp = self.root - else: mp = self.mountpoints.get(mountpoint) - if mp is None: raise ValueError("Invalid mountpoint") - mp.addBuddy(id, name, fg_color, bg_color) - - def getBuddy(self, bid): - """Get a buddy by its id""" - b = None - for mp in self.mountpoints.itervalues(): - b = mp.getBuddy(bid) - if b: break - return b + @dbus.service.signal(DS_DBUS_INTERFACE, signature="a{sv}") + def Mounted(self, descriptior): + """indicates that a new backingstore has been mounted by the + datastore. Returns the mount descriptor, like mounts()""" + pass + + @dbus.service.signal(DS_DBUS_INTERFACE, signature="a{sv}") + def Unmounted(self, descriptor): + """indicates that a new backingstore has been mounted by the + datastore. Returns the mount descriptor, like mounts()""" + pass - def buddies(self): - buddies = set() - for mp in self.mountpoints.itervalues(): - buddies = buddies.union(mp.getBuddies()) - return buddies - + ### End Mount Points - ## end buddy api - + ### Backup support + def pause(self, mountpoints=None): + """pause the datastore, during this time it will not process + requests. this allows the underlying stores to be backup up via + traditional mechanisms + """ + if mountpoints: + mps = [self.mountpoints[mp] for mp in mountpoints] + else: + mps = self.mountpoints.values() + + for mp in mps: + mp.stop() + + def unpause(self, mountpoints=None): + """resume the operation of a set of paused mountpoints""" + if mountpoints: + mps = [self.mountpoints[mp] for mp in mountpoints] + else: + mps = self.mountpoints.values() + + for mp in mps: + mp.initialize_and_load() + + ### End Backups + def connect_backingstore(self, uri, **kwargs): """ connect to a new backing store @@ -325,6 +337,8 @@ class DataStore(dbus.service.Object): 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) @@ -368,7 +382,9 @@ class DataStore(dbus.service.Object): out_signature='a{sv}') def get_properties(self, uid): content = self.get(uid) - return content.properties + props = content.properties + props['mountpoint'] = content.backingstore.id + return props @dbus.service.method(DS_DBUS_INTERFACE, in_signature='sa{sv}', @@ -399,9 +415,9 @@ class DataStore(dbus.service.Object): content = self.get(uid) mountpoint = props.pop('mountpoint', None) content.backingstore.update(uid, props, filelike) - if filelike: - self.Updated(content.id) - logger.debug("updated %s" % content.id) + + self.Updated(content.id) + logger.debug("updated %s" % content.id) @dbus.service.signal(DS_DBUS_INTERFACE, signature="s") def Updated(self, uid): pass @@ -414,8 +430,8 @@ class DataStore(dbus.service.Object): content = self.get(uid) if content: content.backingstore.delete(uid) - self.Deleted(uid) - logger.debug("deleted %s" % uid) + self.Deleted(uid) + logger.debug("deleted %s" % uid) @dbus.service.signal(DS_DBUS_INTERFACE, signature="s") def Deleted(self, uid): pass |