def fetch(self): self.logger.debug("redis_ns_entry.fetch %s" % self.path) path = self.path try: self.node = self.cache.get(NODE + ':' + path) self.data = self.cache.get(DATA + ':' + path) if self.node[TYPE] == DIR: self.kids = self.cache.get(KIDS + ':' + path) self.valid = True return except Exception: # some cache ops failed, so we need to properly fetch data. We # simply fetch all of it pass try: p = self.r.pipeline() p.hgetall(NODE + ':' + path) p.hgetall(DATA + ':' + path) p.smembers(KIDS + ':' + path) values = p.execute() if len(values) != 3: self.valid = False return self.valid = True # FIXME: check val types self.node = values[0] self.data = values[1] self.kids = values[2] # will be 'None' for non-DIR entries if len(self.node) == 0: self.valid = False raise rse.IncorrectState("backend entry gone or corrupted") # cache our newly found entries self.cache.set(NODE + ':' + path, self.node) self.cache.set(DATA + ':' + path, self.data) self.cache.set(KIDS + ':' + path, self.kids) # fetched from redis ok self.valid = True except Exception as e: self.valid = False raise rse.IncorrectState("backend entry gone or corrupted: %s" % str(e))
def list(self): if not self.node[TYPE] == DIR: raise rse.IncorrectState("list() only supported on directories") self.fetch() return self.kids
def create(self, flags=0): """ This assumes that the target entry does not exist. If flags contains CREATE though, we should not raise an exception if it in fact does not. """ path = self.path if self.valid: raise rse.IncorrectState( "mkdir on %s fails, entry already exists" % path) # FIXME: need to ensure this via a WATCH call. self.logger.debug("redis_ns_entry.create %s" % path) name = redis_ns_name(path) parent = redis_ns_parent(path) now = time.time() self.node['mtime'] = now self.node['ctime'] = now p = self.r.pipeline() # FIXME: add guard if len(self.node): p.hmset(NODE + ':' + path, self.node) if len(self.data): p.hmset(DATA + ':' + path, self.data) if len(self.kids): p.hmset(KIDS + ':' + path, self.kids) # add entry as kid to parent # FIXME: avoid duplicated entries! if path != '/': p.sadd(KIDS + ':' + parent, path) # add new index entries for key in self.data: val = self.data[key] p.sadd(KEYS + ':' + str(key), path) p.sadd(VALS + ':' + str(val), path) # FIXME: eval vals p.execute() # issue notification about entry creation to parent dir self.logger.debug("pub CREATE %s [%s]" % (parent, name)) self.r.publish(MON, "CREATE %s [%s]" % (parent, name)) # refresh cache state self.cache.set(NODE + ':' + path, self.node) self.cache.set(DATA + ':' + path, self.data) self.cache.set(KIDS + ':' + path, self.kids) self.valid = True
def mkdir(self, flags): """ Don't call this directly -- to create a dir, call opendir with 'create'/'create_parents' and 'exclusive'. If called, assumes that entry is invalid (and thus does not yet exist). """ path = self.path if self.valid: raise rse.IncorrectState("mkdir %s failed, entry exists" % path) self.logger.debug("redis_ns_entry.mkdir %s" % path) # if / does not exist, we always create it - no need for checks if path != '/': # if CREATE_PARENTS is set, we need to check all parents, and need # to create them as needed. We go top down, and terminate once # a parent is found if c.CREATE_PARENTS & flags: # this will recursively travel down the chimney hole, and stop # whenever it finds an existing directory parent = redis_ns_parent(path) pe = redis_ns_entry.opendir(self.r, parent, c.CREATE_PARENTS) else: # if 'CREATE_PARENTS is not set, parent must exist. parent = redis_ns_parent(path) pe = None try: pe = redis_ns_entry(self.r, parent) pe.fetch() except Exception as e: raise rse.BadParameter( "mkdir %s fails, parent does not exist: %s" % (path, e)) if not pe.is_dir(): raise rse.BadParameter( "mkdir %s fails, parent is no directory: %s" % (path, parent)) self.node[TYPE] = DIR self.create(flags)