def _delete(self, path, tega_id=None, version=None): qname = None if not tega_id: tega_id = self.tega_id if isinstance(path, Cont): qname = path.qname_() else: qname = path2qname(path) if version and _collision_check(qname, version): raise ValueError('collision detected') else: # # DELETE OPERATION # # _idb _idb # / copy (D) / / (E) # o root(A) o o O ..> [Old roots] # / \ ..> \ ..> \ # o o (B) o o (C) del the attribute # / \ / \ \ # o o o o X o # ^ # | # delete operation # root_oid = qname[0] prev_version, new_version, new_root, above_tail = self._copy_on_write( qname, above_tail=True) if above_tail: oid = qname[-1] instance = above_tail[oid] #del above_tail[oid] del above_tail.__dict__[oid] if above_tail.is_empty_(): above_tail.delete_() else: instance = _idb[path] if not root_oid in self.candidate: self.candidate[root_oid] = (prev_version, new_version, new_root) # Commit queue ephemeral = instance.is_ephemeral_() if ephemeral: remove_ephemeral_node(tega_id, path) self._enqueue_commit(OPE.DELETE, path, tega_id, instance, ephemeral)
def _notify_append(self, log): ''' Appends a CRUD operation as notifications to subscribers ''' path = log['path'] instance = log['instance'] qname = path2qname(path) # Searches "path" in "channels". # Example: # regex_path = 'a\.b.\c' for regex_path in channels: nested = nested_regex_path(regex_path) are_parents_or_me = re.match(nested + '$', path) # (A)a.b or (B)a.b.c are_children = re.match(regex_path + '\.', path) # (C)a.b.c.d if are_parents_or_me: #print(are_parents_or_me.groups()) idx = 1 for elm in are_parents_or_me.groups(): if elm: idx += 1 else: break sub_qname = regex_path.split('\.')[idx:] #print(are_parents_or_me.groups()) #print(sub_qname) for regex_oid in sub_qname: for oid in instance: # TODO: regex matching multiple children if re.match(regex_oid, oid): instance = instance[oid] path += '.' + oid else: break log['path'] = path log['instance'] = instance if are_parents_or_me or are_children: for subscriber in channels[regex_path]: try: if not subscriber in self.notify_batch: self.notify_batch[subscriber] = [] self.notify_batch[subscriber].append(log) except: traceback.print_exc() logging.warn( 'subscriber removed - {}'.format(subscriber)) channels[_path].remove(subscriber)
def _notify_append(self, log): ''' Appends a CRUD operation as notifications to subscribers ''' path = log['path'] instance = log['instance'] qname = path2qname(path) # Searches "path" in "channels". # Example: # regex_path = 'a\.b.\c' for regex_path in channels: nested = nested_regex_path(regex_path) are_parents_or_me = re.match(nested+'$', path) # (A)a.b or (B)a.b.c are_children = re.match(regex_path+'\.', path) # (C)a.b.c.d if are_parents_or_me: #print(are_parents_or_me.groups()) idx = 1 for elm in are_parents_or_me.groups(): if elm: idx += 1 else: break sub_qname = regex_path.split('\.')[idx:] #print(are_parents_or_me.groups()) #print(sub_qname) for regex_oid in sub_qname: for oid in instance: # TODO: regex matching multiple children if re.match(regex_oid, oid): instance = instance[oid] path += '.' + oid else: break log['path'] = path log['instance'] = instance if are_parents_or_me or are_children: for subscriber in channels[regex_path]: try: if not subscriber in self.notify_batch: self.notify_batch[subscriber] = [] self.notify_batch[subscriber].append(log) except: traceback.print_exc() logging.warn('subscriber removed - {}'. format(subscriber)) channels[_path].remove(subscriber)
def _delete(self, path, tega_id=None, version=None): qname = None if not tega_id: tega_id = self.tega_id if isinstance(path, Cont): qname = path.qname_() else: qname = path2qname(path) if version and _collision_check(qname, version): raise ValueError('collision detected') else: # # DELETE OPERATION # # _idb _idb # / copy (D) / / (E) # o root(A) o o O ..> [Old roots] # / \ ..> \ ..> \ # o o (B) o o (C) del the attribute # / \ / \ \ # o o o o X o # ^ # | # delete operation # root_oid = qname[0] prev_version, new_version, new_root, above_tail = self._copy_on_write(qname, above_tail=True) if above_tail: oid = qname[-1] instance = above_tail[oid] #del above_tail[oid] del above_tail.__dict__[oid] if above_tail.is_empty_(): above_tail.delete_() else: instance = _idb[path] if not root_oid in self.candidate: self.candidate[root_oid] = (prev_version, new_version, new_root) # Commit queue ephemeral = instance.is_ephemeral_() if ephemeral: remove_ephemeral_node(tega_id, path) self._enqueue_commit(OPE.DELETE, path, tega_id, instance, ephemeral)
def rpc(path, args=None, kwargs=None): ''' RPC (Remote Procedure Call). Raises KeyError if path is not found in idb. ''' try: qname = path2qname(path) f = get(path) if type(f) == RPC: func = get(path)._get_func() if args and kwargs: return func(*args, **kwargs) elif args: return func(*args) elif kwargs: return func(**kwargs) else: return func() else: raise NonLocalRPC('path exists but not for local RPC') except KeyError: raise
def get(path, version=None, regex_flag=False): ''' GET operation. Raises KeyError if path is not found in idb. ''' try: if regex_flag: regex_qname = path.split('\.') regex_oid = regex_qname[0] instances = [] for root_oid in _idb: m = re.match(regex_oid, root_oid) if m: regex_groups = [] g = m.groups() if g: regex_groups.append(g) instance = _fetch_root_with_version(root_oid, version) if len(regex_qname) > 1: g = _select(instance, regex_qname[1:], regex_groups) for match in g: instances.append(match) else: instances.append((root_oid, instance, regex_groups)) return instances else: qname = path2qname(path) root_oid = qname[0] instance = _fetch_root_with_version(root_oid, version) if len(qname) > 1: for oid in qname[1:]: instance = instance.__dict__[oid] return instance except KeyError: raise