summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul "LeoNerd" Evans <paul@matrix.org>2015-03-20 17:08:15 +0000
committerPaul "LeoNerd" Evans <paul@matrix.org>2015-03-20 18:25:49 +0000
commita63b4f71013f6a4e96b2b703c3a469fc8a9a5d57 (patch)
tree3e5b8927c4114d3d7b3c7020068aea7697f70086
parentPull out the cache logic from the @cached wrapper into its own class we can r... (diff)
downloadsynapse-a63b4f71013f6a4e96b2b703c3a469fc8a9a5d57.tar.xz
Remember the 'last seen' time for a given user/IP/device combination and only bother INSERTing another if it's stale
-rw-r--r--synapse/storage/__init__.py32
1 files changed, 30 insertions, 2 deletions
diff --git a/synapse/storage/__init__.py b/synapse/storage/__init__.py
index 76e7bdfaed..c69d11261c 100644
--- a/synapse/storage/__init__.py
+++ b/synapse/storage/__init__.py
@@ -13,6 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from twisted.internet import defer
+
+from ._base import Cache
 from .appservice import ApplicationServiceStore
 from .directory import DirectoryStore
 from .events import EventsStore
@@ -51,6 +54,11 @@ SCHEMA_VERSION = 14
 
 dir_path = os.path.abspath(os.path.dirname(__file__))
 
+# Number of msec of granularity to store the user IP 'last seen' time. Smaller
+# times give more inserts into the database even for readonly API hits
+# 120 seconds == 2 minutes
+LAST_SEEN_GRANULARITY = 120*1000
+
 
 class DataStore(RoomMemberStore, RoomStore,
                 RegistrationStore, StreamStore, ProfileStore,
@@ -73,8 +81,28 @@ class DataStore(RoomMemberStore, RoomStore,
         self.min_token_deferred = self._get_min_token()
         self.min_token = None
 
+        self.client_ip_last_seen = Cache(
+            name="client_ip_last_seen",
+            keylen=4,
+        )
+
+    @defer.inlineCallbacks
     def insert_client_ip(self, user, access_token, device_id, ip, user_agent):
-        return self._simple_insert(
+        now = int(self._clock.time_msec())
+        key = (user.to_string(), access_token, device_id, ip)
+
+        try:
+            last_seen = self.client_ip_last_seen.get(*key)
+        except KeyError:
+            last_seen = None
+
+        # Rate-limited inserts
+        if last_seen is not None and (now - last_seen) < LAST_SEEN_GRANULARITY:
+            defer.returnValue(None)
+
+        self.client_ip_last_seen.prefill(*key + (now,))
+
+        yield self._simple_insert(
             "user_ips",
             {
                 "user": user.to_string(),
@@ -82,7 +110,7 @@ class DataStore(RoomMemberStore, RoomStore,
                 "device_id": device_id,
                 "ip": ip,
                 "user_agent": user_agent,
-                "last_seen": int(self._clock.time_msec()),
+                "last_seen": now,
             },
             desc="insert_client_ip",
         )