Context
# Every mapping has a parent whose path is a prefix with one less element; the exception to this rule is root ("/") which has no parent.
# Unlike a regular file system, all these mappings can have both data (so it acts like a file) and children (so it acts like a directory)
# The data structure used is a dictionary called store. Values are arbitrary, by default there is an initial key of "/".
# All keys start with the absolute path, for example "/dir1/file1".
# Its not able to create a key if its parent key does not exist.
# For example, it cannot create "/app1/p1" if dictionary only has the "/" key. It has to create an "/app1" key first, then call create on "/app1/p1"
# (tree visualization example)
# "/"
# / \
# "/app1" "/app2" ...
# / / \
# "/app1/p1" "/app1/p2" "/app1/p3" ...
class Zookeeper():
store = {"/":None}
def create(self, path, value):
if self.validate(path):
self.store[path] = value
else:
pass
#raise KeyError("create error: {} invalid".format(path))
def read(self, path):
if path in self.store.keys():
return self.store[path]
else:
return "read error: {} does not exist".format(path)
def update(self, path, value):
if path in self.store.keys():
self.store[path] = value
else:
return "update error: {} does not exist".format(path)
def validate(self, path):
if path is None:
return False
if len(path.strip()) == 0:
return False
if path[0] != "/":
return False
if path.rindex("/") == path.index("/"):
return True
if path[0:path.rindex("/")] not in self.store:
return False
if path in self.store:
return False
return True
zk = Zookeeper()
zk.create("/app1", "/app1 value")
print(zk.read("/app1"))
zk.create("/app1/p1", "/app1/p1 value")
print(zk.read("/app1/p1"))
zk.create("/p1/p1", "/p1/p1 value")
print(zk.read("/p1/p1"))
zk.create("/p1", "/p1 value")
print(zk.read("/p1"))
zk.create("/p1/p1", "/p1/p1 value")
print(zk.read("/p1/p1"))
More context
The question is to implement a watch method
watch(path, watcher)
- Sets a watcher that will be called whenever the watched path or any of its descendants are updated by a call to update or create
- watch accepts path and some sort of listener object (depending on the language this can be a function, pointer, object, or something else)
- Whenever the value of path or that of any of its descendants are set, the callback registered for the path must be called
- The watcher should accept two arguments - the path that was changed and the value that was set
How do you implement watch?
The fact your paths are all implemented as strings in a flat dictionary simplifies some things, and complicates others.
If upon installing a watcher you want to look just at that level of the path, and not on sub-levels, it is super-simple.
As all accesses are either through the "create" or "update" methods, all you have to do is to check in these methods if there is a "watcher" for the path that is being fiddled with. The watchers registry can be a simple dictionary, as is ".store" - and you can even have several listeners for each key by having the values of the store being sequences.
The "watch" functionality can even be implemented in a subclass of your original class with no hassles: