# KVS.py 27/05/2016 D.J.Whale # # A generic key value store from lifecycle import * class KVSFile(): """A persistent key value store""" def __init__(self, filename=None): self.filename = filename self.store = {} @unimplemented def load(self, create_cb): """Load the whole file into an in-memory cache""" # The 'callback' is called to process each record as it is read in. # for the Registry, this is a way that it can create the class and also add receive routing pass #TODO # open file for read # for each line read # if in command mode # if blank line, ignore it # else not blank line # split line, first word is command, second word is the key # remember both # change to data mode # else in data mode # if not blank line # grab key=value # add to temporary object # else blank line # process command,key,values # now eof # process command,key,values, if it command is not empty # close file @unimplemented def process(self, command, key, values): """Process the temporary object""" pass #TODO # getattr method associated with the command name, error if no method # pass the key,values to that method to let it be processed @unimplemented def ADD(self, key, values): """Add a new item to the kvs""" # The ADD command process the next type= parameter as the class name in context # all other parameters are read as strings and passed to class constructor as kwargs pass #TODO # add key=values to the in memory object store # open file for append # write ADD command with key # for all keys in value # write k=v # close file @unimplemented def IGN(self, key, values=None): """Ignore the whole record""" # The IGN command is the same length as ADD, allowing a seek/write to change any # command into IGN without changing the file size, effectively patching the file # so that the record is deleted. pass # There is nothing to do with this command @unimplemented def DEL(self, key, values=None): """Delete the key from the store""" # The DEL command deletes the rec from the store. # This is useful to build temporary objects and delete them later. # There is no need to write this to the file copy, we're processing the file pass #TODO # find key in object store, delete it @untested def __getitem__(self, key): return self.store[key] @untested def __setitem__(self, key, value): self.store[key] = value self.append(key, value) @untested def __delitem__(self, key): del self.store[key] self.remove(key) @untested def keys(self): return self.store.keys() @untested def size(self): return len(self.store) def append(self, key, values): """Append a new record to the persistent file""" with open(self.filename, 'a') as f: f.write("ADD %s\n" % key) for k in values: v = values[k] f.write("%s=%s\n" % (k, v)) f.write("\n") @unimplemented def remove(self, key): """Remove reference to this key in the file, and remove from in memory store""" pass #TODO # open file for read write # search line at a time, process each command # when we find the command 'ADD key' # reseek to start of line # write overwrite ADD with IGN # keep going in case of duplicates # close file @unimplemented def write(self, filename=None): """Rewrite the whole in memory cache over the top of the external file""" # useful if you have updated the in memory copy only and want to completely regenerate pass #TODO # create file new, for write only # for all objects in the store by key # get value # write ADD command key # for all values # write k=v # write blank line # close file # END