From a4352e318460e2a505ef65437a92042c3eac80c7 Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Mon, 28 Oct 2024 17:11:55 +0100 Subject: [PATCH] BIG speedup by caching the *set* of edge targets for a given key --- services/bottom/V0.py | 12 ++++++++++++ state/pystate.py | 26 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/services/bottom/V0.py b/services/bottom/V0.py index 4d1bf86..43ab3fc 100644 --- a/services/bottom/V0.py +++ b/services/bottom/V0.py @@ -122,6 +122,15 @@ class Bottom: Returns: List of UUIDs of outgoing edges """ + + ### PERFORMANCE OPTIMIZATION ### + if label != None: + fast_result = self.state.read_dict_edge_all(source, label) + # if set(alt) != set(edges): + # raise Exception("WRONG", alt, edges) + return fast_result + ### PERFORMANCE OPTIMIZATION ### + def read_label(_edge: UUID): try: label_edge, = self.state.read_outgoing(_edge) @@ -136,6 +145,9 @@ class Bottom: return [] if label != None: edges = [e for e in edges if read_label(e) == label] + + + return edges def read_incoming_elements(self, target: UUID, label=None) -> List[UUID]: diff --git a/state/pystate.py b/state/pystate.py index 5bfc398..3afc130 100644 --- a/state/pystate.py +++ b/state/pystate.py @@ -23,6 +23,8 @@ class PyState(State): self.cache = {} self.cache_node = {} + self.cache_all = {} + self.root = self.create_node() def create_node(self) -> Node: @@ -46,6 +48,7 @@ class PyState(State): dict_source, dict_target = self.edges[source] if target in self.values: self.cache.setdefault(dict_source, {})[self.values[target]] = source + self.cache_all.setdefault(dict_source, {}).setdefault(self.values[target], set()).add(source) self.cache_node.setdefault(dict_source, {})[target] = source return new_id @@ -70,6 +73,7 @@ class PyState(State): assert n != None and e != None e2 = self.create_edge(e, n) self.cache.setdefault(source, {})[value] = e + self.cache_all.setdefault(source, {}).setdefault(value, set()).add(e) self.cache_node.setdefault(source, {})[n] = e def read_root(self) -> Node: @@ -139,10 +143,31 @@ class PyState(State): return first # Hit but invalid now del self.cache[elem][value] + self.cache_all[elem][value].remove(first) return None except KeyError: return None + def read_dict_edge_all(self, elem: Element, value: Any) -> List[Edge]: + result = [] + try: + all_ = self.cache_all[elem][value] + for a in all_: + try: + if ((self.edges[a][0] == elem) and (value in [self.values[self.edges[i][1]] + for i in self.outgoing[a] + if self.edges[i][1] in self.values])): + result.append(a) + continue + except KeyError: + pass + + if len(result) != len(all_): + self.cache_all[elem][value] = set(result) + except KeyError: + pass + return result + def read_dict_node(self, elem: Element, value_node: Node) -> Optional[Element]: e = self.read_dict_node_edge(elem, value_node) if e == None: @@ -273,6 +298,7 @@ class PyState(State): dset.add(key) for key in dset: del self.cache[key] + del self.cache_all[key] dset = set() for key in self.cache_node: