Add a cache for get_event

pull/4/merge
Mark Haines 10 years ago
parent d8324d5a2b
commit f5a70e0d2e
  1. 10
      synapse/config/_base.py
  2. 5
      synapse/config/database.py
  3. 3
      synapse/storage/__init__.py
  4. 24
      synapse/storage/_base.py
  5. 5
      tests/storage/test_base.py
  6. 1
      tests/utils.py

@ -27,6 +27,16 @@ class Config(object):
def __init__(self, args):
pass
@staticmethod
def parse_size(string):
sizes = {"K": 1024, "M": 1024 * 1024}
size = 1
suffix = string[-1]
if suffix in sizes:
string = string[:-1]
size = sizes[suffix]
return int(string) * size
@staticmethod
def abspath(file_path):
return os.path.abspath(file_path) if file_path else file_path

@ -24,6 +24,7 @@ class DatabaseConfig(Config):
self.database_path = ":memory:"
else:
self.database_path = self.abspath(args.database_path)
self.event_cache_size = self.parse_size(args.event_cache_size)
@classmethod
def add_arguments(cls, parser):
@ -33,6 +34,10 @@ class DatabaseConfig(Config):
"-d", "--database-path", default="homeserver.db",
help="The database name."
)
db_group.add_argument(
"--event-cache-size", default="100K",
help="Number of events to cache in memory."
)
@classmethod
def generate_config(cls, args, config_dir_path):

@ -164,6 +164,9 @@ class DataStore(RoomMemberStore, RoomStore,
stream_ordering=None, is_new_state=True,
current_state=None):
# Remove the any existing cache entries for the event_id
self._get_event_cache.pop(event.event_id)
# We purposefully do this first since if we include a `current_state`
# key, we *want* to update the `current_state_events` table
if current_state:

@ -19,6 +19,7 @@ from synapse.events import FrozenEvent
from synapse.events.utils import prune_event
from synapse.util.logutils import log_function
from synapse.util.logcontext import PreserveLoggingContext, LoggingContext
from synapse.util.lrucache import LruCache
from twisted.internet import defer
@ -128,6 +129,8 @@ class SQLBaseStore(object):
self._txn_perf_counters = PerformanceCounters()
self._get_event_counters = PerformanceCounters()
self._get_event_cache = LruCache(hs.config.event_cache_size)
def start_profiling(self):
self._previous_loop_ts = self._clock.time_msec()
@ -579,6 +582,20 @@ class SQLBaseStore(object):
def _get_event_txn(self, txn, event_id, check_redacted=True,
get_prev_content=False, allow_rejected=False):
start_time = time.time() * 1000
update_counter = self._get_event_counters.update
try:
cache = self._get_event_cache.setdefault(event_id, {})
# Separate cache entries for each way to invoke _get_event_txn
return cache[(check_redacted, get_prev_content, allow_rejected)]
except KeyError:
pass
finally:
start_time = update_counter("event_cache", start_time)
sql = (
"SELECT e.internal_metadata, e.json, r.event_id, rej.reason "
"FROM event_json as e "
@ -588,7 +605,6 @@ class SQLBaseStore(object):
"LIMIT 1 "
)
start_time = time.time() * 1000
txn.execute(sql, (event_id,))
@ -599,14 +615,16 @@ class SQLBaseStore(object):
internal_metadata, js, redacted, rejected_reason = res
self._get_event_counters.update("select_event", start_time)
start_time = update_counter("select_event", start_time)
if allow_rejected or not rejected_reason:
return self._get_event_from_row_txn(
result = self._get_event_from_row_txn(
txn, internal_metadata, js, redacted,
check_redacted=check_redacted,
get_prev_content=get_prev_content,
)
cache[(check_redacted, get_prev_content, allow_rejected)] = result
return result
else:
return None

@ -38,8 +38,9 @@ class SQLBaseStoreTestCase(unittest.TestCase):
return defer.succeed(func(self.mock_txn, *args, **kwargs))
self.db_pool.runInteraction = runInteraction
hs = HomeServer("test",
db_pool=self.db_pool)
config = Mock()
config.event_cache_size = 1
hs = HomeServer("test", db_pool=self.db_pool, config=config)
self.datastore = SQLBaseStore(hs)

@ -41,6 +41,7 @@ def setup_test_homeserver(name="test", datastore=None, config=None, **kargs):
if config is None:
config = Mock()
config.signing_key = [MockKey()]
config.event_cache_size = 1
if datastore is None:
db_pool = SQLiteMemoryDbPool()

Loading…
Cancel
Save