summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Shyba <victor.shyba@gmail.com>2015-09-07 03:56:02 -0300
committerVictor Shyba <victor.shyba@gmail.com>2015-09-24 19:39:56 -0300
commit14300959a12e4908df7b00281d2590e627a47ba9 (patch)
treedf05a8a0a9999c7fc1cf7fdd04e4b9d8435ca742
parentf9faa007bc0d5d681f85aa246ea05ec5fe35ccc5 (diff)
[feat] full caching for each sync_id session
The CouchDB backend implementation was accessing CouchDB too many times for the same values. Those values are known inside the same sync_id, which is the id of current sync session. This commit adds caching for all redundant calls to Couch inside the same sync_id for each replica. Refactoring is still needed, but for now couch.py works normally as if caching is not present, while sync.py injects the cache as a attribute to enable it. This needs a simpler implementation.
-rw-r--r--common/src/leap/soledad/common/couch.py27
-rw-r--r--server/src/leap/soledad/server/__init__.py4
-rw-r--r--server/src/leap/soledad/server/sync.py3
3 files changed, 27 insertions, 7 deletions
diff --git a/common/src/leap/soledad/common/couch.py b/common/src/leap/soledad/common/couch.py
index 3b120cd1..8c152353 100644
--- a/common/src/leap/soledad/common/couch.py
+++ b/common/src/leap/soledad/common/couch.py
@@ -434,7 +434,14 @@ class CouchDatabase(CommonBackend):
self._set_replica_uid(replica_uid)
if ensure_ddocs:
self.ensure_ddocs_on_db()
- self.cache = {}
+ self._cache = None
+
+ @property
+ def cache(self):
+ if self._cache is not None:
+ return self._cache
+ else:
+ return {}
def ensure_ddocs_on_db(self):
"""
@@ -513,7 +520,10 @@ class CouchDatabase(CommonBackend):
:rtype: str
"""
if self._real_replica_uid is not None:
+ self.cache[self._url] = {'replica_uid': self._real_replica_uid}
return self._real_replica_uid
+ if self._url in self.cache:
+ return self.cache[self._url]['replica_uid']
try:
# grab replica_uid from server
doc = self._database['u1db_config']
@@ -551,10 +561,13 @@ class CouchDatabase(CommonBackend):
unknown reason.
"""
# query a couch list function
+ if self.replica_uid + '_gen' in self.cache:
+ return self.cache[self.replica_uid + '_gen']['generation']
ddoc_path = ['_design', 'transactions', '_list', 'generation', 'log']
res = self._database.resource(*ddoc_path)
try:
response = res.get_json()
+ self.cache[self.replica_uid + '_gen'] = response[2]
return response[2]['generation']
except ResourceNotFound as e:
raise_missing_design_doc_error(e, ddoc_path)
@@ -582,11 +595,15 @@ class CouchDatabase(CommonBackend):
design document for an yet
unknown reason.
"""
+ if self.replica_uid + '_gen' in self.cache:
+ response = self.cache[self.replica_uid + '_gen']
+ return (response['generation'], response['transaction_id'])
# query a couch list function
ddoc_path = ['_design', 'transactions', '_list', 'generation', 'log']
res = self._database.resource(*ddoc_path)
try:
response = res.get_json()
+ self.cache[self.replica_uid + '_gen'] = response[2]
return (response[2]['generation'], response[2]['transaction_id'])
except ResourceNotFound as e:
raise_missing_design_doc_error(e, ddoc_path)
@@ -846,6 +863,10 @@ class CouchDatabase(CommonBackend):
doc.doc_id, body=buf.getvalue(), headers=envelope.headers)
except ResourceConflict:
raise RevisionConflict()
+ if self.replica_uid + '_gen' in self.cache:
+ gen_info = self.cache[self.replica_uid + '_gen']
+ gen_info['generation'] += 1
+ gen_info['transaction_id'] = transactions[-1][1]
def put_doc(self, doc):
"""
@@ -1366,7 +1387,7 @@ class CouchServerState(ServerState):
Inteface of the WSGI server with the CouchDB backend.
"""
- def __init__(self, couch_url, cache=None):
+ def __init__(self, couch_url):
"""
Initialize the couch server state.
@@ -1374,7 +1395,6 @@ class CouchServerState(ServerState):
:type couch_url: str
"""
self.couch_url = couch_url
- self.cache = cache or {}
def open_database(self, dbname):
"""
@@ -1390,7 +1410,6 @@ class CouchServerState(ServerState):
self.couch_url,
dbname,
ensure_ddocs=False)
- db.cache = self.cache
return db
def ensure_database(self, dbname):
diff --git a/server/src/leap/soledad/server/__init__.py b/server/src/leap/soledad/server/__init__.py
index 58f2b0b1..1b795016 100644
--- a/server/src/leap/soledad/server/__init__.py
+++ b/server/src/leap/soledad/server/__init__.py
@@ -111,7 +111,6 @@ from leap.soledad.server.sync import (
from leap.soledad.common import SHARED_DB_NAME
from leap.soledad.common.couch import CouchServerState
-from leap.soledad.server.caching import get_cache_for
old_tsafe = tsafe
@@ -304,8 +303,7 @@ def load_configuration(file_path):
def application(environ, start_response):
conf = load_configuration('/etc/leap/soledad-server.conf')
- cache = get_cache_for('replica_cache')
- state = CouchServerState(conf['couch_url'], cache=cache)
+ state = CouchServerState(conf['couch_url'])
# WSGI application that may be used by `twistd -web`
application = GzipMiddleware(
SoledadTokenAuthMiddleware(SoledadApp(state)))
diff --git a/server/src/leap/soledad/server/sync.py b/server/src/leap/soledad/server/sync.py
index 64f7e4e7..262b6769 100644
--- a/server/src/leap/soledad/server/sync.py
+++ b/server/src/leap/soledad/server/sync.py
@@ -20,6 +20,7 @@ Server side synchronization infrastructure.
from u1db import sync, Document
from u1db.remote import http_app
from leap.soledad.server.state import ServerSyncState
+from leap.soledad.server.caching import get_cache_for
MAX_REQUEST_SIZE = 200 # in Mb
@@ -188,6 +189,8 @@ class SyncResource(http_app.SyncResource):
db, self.replica_uid = self.state.ensure_database(self.dbname)
else:
db = self.state.open_database(self.dbname)
+ cache = get_cache_for('db-' + sync_id + db.replica_uid)
+ db._cache = cache
# validate the information the client has about server replica
db.validate_gen_and_trans_id(
last_known_generation, last_known_trans_id)