diff options
author | David Baker <dbkr@users.noreply.github.com> | 2016-01-22 14:47:48 +0000 |
---|---|---|
committer | David Baker <dbkr@users.noreply.github.com> | 2016-01-22 14:47:48 +0000 |
commit | 7a3fe48ba48d99f02b4bfd556199571f95fc8e1c (patch) | |
tree | 740e160954c47d5362c22661bb141c31cdfbf118 /synapse/util/caches/treecache.py | |
parent | Merge pull request #517 from matrix-org/erikj/push_only_room (diff) | |
parent | Don't add the member functiopn if we're not using treecache (diff) | |
download | synapse-7a3fe48ba48d99f02b4bfd556199571f95fc8e1c.tar.xz |
Merge pull request #519 from matrix-org/dbkr/treecache
Make LRU caching tree-based so subtrees of the cache can be invalidated cheaply.
Diffstat (limited to 'synapse/util/caches/treecache.py')
-rw-r--r-- | synapse/util/caches/treecache.py | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/synapse/util/caches/treecache.py b/synapse/util/caches/treecache.py new file mode 100644 index 0000000000..3b58860910 --- /dev/null +++ b/synapse/util/caches/treecache.py @@ -0,0 +1,60 @@ +SENTINEL = object() + + +class TreeCache(object): + """ + Tree-based backing store for LruCache. Allows subtrees of data to be deleted + efficiently. + Keys must be tuples. + """ + def __init__(self): + self.root = {} + + def __setitem__(self, key, value): + return self.set(key, value) + + def __contains__(self, key): + return self.get(key, SENTINEL) is not SENTINEL + + def set(self, key, value): + node = self.root + for k in key[:-1]: + node = node.setdefault(k, {}) + node[key[-1]] = value + + def get(self, key, default=None): + node = self.root + for k in key[:-1]: + node = node.get(k, None) + if node is None: + return default + return node.get(key[-1], default) + + def clear(self): + self.root = {} + + def pop(self, key, default=None): + nodes = [] + + node = self.root + for k in key[:-1]: + node = node.get(k, None) + nodes.append(node) # don't add the root node + if node is None: + return default + popped = node.pop(key[-1], SENTINEL) + if popped is SENTINEL: + return default + + node_and_keys = zip(nodes, key) + node_and_keys.reverse() + node_and_keys.append((self.root, None)) + + for i in range(len(node_and_keys) - 1): + n, k = node_and_keys[i] + + if n: + break + node_and_keys[i+1][0].pop(k) + + return popped |