summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xjenkins.sh2
-rw-r--r--synapse/api/filtering.py5
-rw-r--r--synapse/python_dependencies.py2
-rw-r--r--synapse/storage/filtering.py3
-rw-r--r--synapse/util/caches/lrucache.py10
-rw-r--r--synapse/util/caches/treecache.py36
-rw-r--r--tests/api/test_filtering.py7
-rw-r--r--tests/util/test_lrucache.py7
-rw-r--r--tests/util/test_treecache.py12
9 files changed, 70 insertions, 14 deletions
diff --git a/jenkins.sh b/jenkins.sh
index 804bbd49f1..ed3bdf80fa 100755
--- a/jenkins.sh
+++ b/jenkins.sh
@@ -26,7 +26,7 @@ TOX_BIN=$WORKSPACE/.tox/py27/bin
 if [[ ! -e .sytest-base ]]; then
   git clone https://github.com/matrix-org/sytest.git .sytest-base --mirror
 else
-  (cd .sytest-base; git fetch)
+  (cd .sytest-base; git fetch -p)
 fi
 
 rm -rf sytest
diff --git a/synapse/api/filtering.py b/synapse/api/filtering.py
index 6c13ada5df..6eff83e5f8 100644
--- a/synapse/api/filtering.py
+++ b/synapse/api/filtering.py
@@ -15,6 +15,8 @@
 from synapse.api.errors import SynapseError
 from synapse.types import UserID, RoomID
 
+import ujson as json
+
 
 class Filtering(object):
 
@@ -149,6 +151,9 @@ class FilterCollection(object):
             "include_leave", False
         )
 
+    def __repr__(self):
+        return "<FilterCollection %s>" % (json.dumps(self._filter_json),)
+
     def get_filter_json(self):
         return self._filter_json
 
diff --git a/synapse/python_dependencies.py b/synapse/python_dependencies.py
index d37dc11470..a87628ed85 100644
--- a/synapse/python_dependencies.py
+++ b/synapse/python_dependencies.py
@@ -22,7 +22,7 @@ REQUIREMENTS = {
     "unpaddedbase64>=1.0.1": ["unpaddedbase64>=1.0.1"],
     "canonicaljson>=1.0.0": ["canonicaljson>=1.0.0"],
     "signedjson>=1.0.0": ["signedjson>=1.0.0"],
-    "pynacl>=0.3.0": ["nacl>=0.3.0", "nacl.bindings"],
+    "pynacl==0.3.0": ["nacl==0.3.0", "nacl.bindings"],
     "service_identity>=1.0.0": ["service_identity>=1.0.0"],
     "Twisted>=15.1.0": ["twisted>=15.1.0"],
     "pyopenssl>=0.14": ["OpenSSL>=0.14"],
diff --git a/synapse/storage/filtering.py b/synapse/storage/filtering.py
index f8fc9bdddc..5248736816 100644
--- a/synapse/storage/filtering.py
+++ b/synapse/storage/filtering.py
@@ -16,12 +16,13 @@
 from twisted.internet import defer
 
 from ._base import SQLBaseStore
+from synapse.util.caches.descriptors import cachedInlineCallbacks
 
 import simplejson as json
 
 
 class FilteringStore(SQLBaseStore):
-    @defer.inlineCallbacks
+    @cachedInlineCallbacks(num_args=2)
     def get_user_filter(self, user_localpart, filter_id):
         def_json = yield self._simple_select_one_onecol(
             table="user_filters",
diff --git a/synapse/util/caches/lrucache.py b/synapse/util/caches/lrucache.py
index e6a66dc041..f7423f2fab 100644
--- a/synapse/util/caches/lrucache.py
+++ b/synapse/util/caches/lrucache.py
@@ -37,7 +37,7 @@ class LruCache(object):
     """
     def __init__(self, max_size, keylen=1, cache_type=dict):
         cache = cache_type()
-        self.size = 0
+        self.cache = cache  # Used for introspection.
         list_root = []
         list_root[:] = [list_root, list_root, None, None]
 
@@ -60,7 +60,6 @@ class LruCache(object):
             prev_node[NEXT] = node
             next_node[PREV] = node
             cache[key] = node
-            self.size += 1
 
         def move_node_to_front(node):
             prev_node = node[PREV]
@@ -79,7 +78,6 @@ class LruCache(object):
             next_node = node[NEXT]
             prev_node[NEXT] = next_node
             next_node[PREV] = prev_node
-            self.size -= 1
 
         @synchronized
         def cache_get(key, default=None):
@@ -98,7 +96,7 @@ class LruCache(object):
                 node[VALUE] = value
             else:
                 add_node(key, value)
-                if self.size > max_size:
+                if len(cache) > max_size:
                     todelete = list_root[PREV]
                     delete_node(todelete)
                     cache.pop(todelete[KEY], None)
@@ -110,7 +108,7 @@ class LruCache(object):
                 return node[VALUE]
             else:
                 add_node(key, value)
-                if self.size > max_size:
+                if len(cache) > max_size:
                     todelete = list_root[PREV]
                     delete_node(todelete)
                     cache.pop(todelete[KEY], None)
@@ -145,7 +143,7 @@ class LruCache(object):
 
         @synchronized
         def cache_len():
-            return self.size
+            return len(cache)
 
         @synchronized
         def cache_contains(key):
diff --git a/synapse/util/caches/treecache.py b/synapse/util/caches/treecache.py
index 3b58860910..29d02f7e95 100644
--- a/synapse/util/caches/treecache.py
+++ b/synapse/util/caches/treecache.py
@@ -8,6 +8,7 @@ class TreeCache(object):
     Keys must be tuples.
     """
     def __init__(self):
+        self.size = 0
         self.root = {}
 
     def __setitem__(self, key, value):
@@ -20,7 +21,8 @@ class TreeCache(object):
         node = self.root
         for k in key[:-1]:
             node = node.setdefault(k, {})
-        node[key[-1]] = value
+        node[key[-1]] = _Entry(value)
+        self.size += 1
 
     def get(self, key, default=None):
         node = self.root
@@ -28,9 +30,10 @@ class TreeCache(object):
             node = node.get(k, None)
             if node is None:
                 return default
-        return node.get(key[-1], default)
+        return node.get(key[-1], _Entry(default)).value
 
     def clear(self):
+        self.size = 0
         self.root = {}
 
     def pop(self, key, default=None):
@@ -57,4 +60,33 @@ class TreeCache(object):
                 break
             node_and_keys[i+1][0].pop(k)
 
+        popped, cnt = _strip_and_count_entires(popped)
+        self.size -= cnt
         return popped
+
+    def __len__(self):
+        return self.size
+
+
+class _Entry(object):
+    __slots__ = ["value"]
+
+    def __init__(self, value):
+        self.value = value
+
+
+def _strip_and_count_entires(d):
+    """Takes an _Entry or dict with leaves of _Entry's, and either returns the
+    value or a dictionary with _Entry's replaced by their values.
+
+    Also returns the count of _Entry's
+    """
+    if isinstance(d, dict):
+        cnt = 0
+        for key, value in d.items():
+            v, n = _strip_and_count_entires(value)
+            d[key] = v
+            cnt += n
+        return d, cnt
+    else:
+        return d.value, 1
diff --git a/tests/api/test_filtering.py b/tests/api/test_filtering.py
index 1a4e439d30..ceb0089268 100644
--- a/tests/api/test_filtering.py
+++ b/tests/api/test_filtering.py
@@ -382,19 +382,20 @@ class FilteringTestCase(unittest.TestCase):
                 "types": ["m.*"]
             }
         }
-        user = UserID.from_string("@" + user_localpart + ":test")
+
         filter_id = yield self.datastore.add_user_filter(
-            user_localpart=user_localpart,
+            user_localpart=user_localpart + "2",
             user_filter=user_filter_json,
         )
         event = MockEvent(
+            event_id="$asdasd:localhost",
             sender="@foo:bar",
             type="custom.avatar.3d.crazy",
         )
         events = [event]
 
         user_filter = yield self.filtering.get_user_filter(
-            user_localpart=user_localpart,
+            user_localpart=user_localpart + "2",
             filter_id=filter_id,
         )
 
diff --git a/tests/util/test_lrucache.py b/tests/util/test_lrucache.py
index 2cd3d26454..bab366fb7f 100644
--- a/tests/util/test_lrucache.py
+++ b/tests/util/test_lrucache.py
@@ -19,6 +19,7 @@ from .. import unittest
 from synapse.util.caches.lrucache import LruCache
 from synapse.util.caches.treecache import TreeCache
 
+
 class LruCacheTestCase(unittest.TestCase):
 
     def test_get_set(self):
@@ -72,3 +73,9 @@ class LruCacheTestCase(unittest.TestCase):
         self.assertEquals(cache.get(("vehicles", "car")), "vroom")
         self.assertEquals(cache.get(("vehicles", "train")), "chuff")
         # Man from del_multi say "Yes".
+
+    def test_clear(self):
+        cache = LruCache(1)
+        cache["key"] = 1
+        cache.clear()
+        self.assertEquals(len(cache), 0)
diff --git a/tests/util/test_treecache.py b/tests/util/test_treecache.py
index 9946ceb3f1..1efbeb6b33 100644
--- a/tests/util/test_treecache.py
+++ b/tests/util/test_treecache.py
@@ -25,6 +25,7 @@ class TreeCacheTestCase(unittest.TestCase):
         cache[("b",)] = "B"
         self.assertEquals(cache.get(("a",)), "A")
         self.assertEquals(cache.get(("b",)), "B")
+        self.assertEquals(len(cache), 2)
 
     def test_pop_onelevel(self):
         cache = TreeCache()
@@ -33,6 +34,7 @@ class TreeCacheTestCase(unittest.TestCase):
         self.assertEquals(cache.pop(("a",)), "A")
         self.assertEquals(cache.pop(("a",)), None)
         self.assertEquals(cache.get(("b",)), "B")
+        self.assertEquals(len(cache), 1)
 
     def test_get_set_twolevel(self):
         cache = TreeCache()
@@ -42,6 +44,7 @@ class TreeCacheTestCase(unittest.TestCase):
         self.assertEquals(cache.get(("a", "a")), "AA")
         self.assertEquals(cache.get(("a", "b")), "AB")
         self.assertEquals(cache.get(("b", "a")), "BA")
+        self.assertEquals(len(cache), 3)
 
     def test_pop_twolevel(self):
         cache = TreeCache()
@@ -53,6 +56,7 @@ class TreeCacheTestCase(unittest.TestCase):
         self.assertEquals(cache.get(("a", "b")), "AB")
         self.assertEquals(cache.pop(("b", "a")), "BA")
         self.assertEquals(cache.pop(("b", "a")), None)
+        self.assertEquals(len(cache), 1)
 
     def test_pop_mixedlevel(self):
         cache = TreeCache()
@@ -64,3 +68,11 @@ class TreeCacheTestCase(unittest.TestCase):
         self.assertEquals(cache.get(("a", "a")), None)
         self.assertEquals(cache.get(("a", "b")), None)
         self.assertEquals(cache.get(("b", "a")), "BA")
+        self.assertEquals(len(cache), 1)
+
+    def test_clear(self):
+        cache = TreeCache()
+        cache[("a",)] = "A"
+        cache[("b",)] = "B"
+        cache.clear()
+        self.assertEquals(len(cache), 0)