From 5045ee68b6caf8b51121f6f85e4dfcae5e5a0ba0 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 13 May 2021 15:53:02 +0200 Subject: db: implement an email message cache Not in master because it doesn't seem to be the bottleneck, didn't check whether the difference is measurable. --- alot/db/manager.py | 31 +++++++++++++++++++++++++++++++ alot/db/message.py | 3 +-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/alot/db/manager.py b/alot/db/manager.py index efd70e70..9d76ddeb 100644 --- a/alot/db/manager.py +++ b/alot/db/manager.py @@ -3,8 +3,10 @@ # For further details see the COPYING file import asyncio +from collections import OrderedDict from concurrent.futures import ThreadPoolExecutor from contextlib import closing +import email from functools import partial, partialmethod import logging import os @@ -112,6 +114,31 @@ class _DBWriteList: def __str__(self): return '%s:%s' % (self.__class__.__name__, self._ops) +class _EmailCache: + _cache = None + + def __init__(self, max_size = 128): + self._cache = OrderedDict() + self._max_size = max_size + + def get(self, path): + with open(path, 'rb') as f: + mtime = os.stat(f.fileno()).st_mtime + + mtime_cached, mail = self._cache.pop(path, (None, None)) + if mtime_cached != mtime: + mail = email.message_from_bytes(f.read(), policy = email.policy.SMTP) + logging.info('loading from disk') + else: + logging.info('reading from cache') + + # update the cache + if len(self._cache) >= self._max_size: + self._cache.popitem(last = False) + self._cache[path] = (mtime, mail) + + return mail + class DBManager: """ Keeps track of your index parameters, maintains a write-queue and @@ -130,6 +157,8 @@ class DBManager: _write_task = None _write_queue = None + _email_cache = None + def __init__(self, loop, path=None, ro=False): """ :param path: absolute path to the notmuch index @@ -148,6 +177,8 @@ class DBManager: self._exclude_tags = frozenset(settings.get('exclude_tags')) self._property_tags = frozenset(settings.get('property_tags')) + self._email_cache = _EmailCache() + def _db_ro(self): return closing(Database(path = self.path, mode = Database.MODE.READ_ONLY)) diff --git a/alot/db/message.py b/alot/db/message.py index 74139315..f7aea829 100644 --- a/alot/db/message.py +++ b/alot/db/message.py @@ -459,8 +459,7 @@ class Message: @cached_property def _email(self): try: - with open(self.filename, 'rb') as f: - mail = email.message_from_bytes(f.read(), policy = email.policy.SMTP) + mail = self._dbman._email_cache.get(self.filename) except IOError: warning = b"Subject: Caution!\n"\ b"Message file is no longer accessible:\n%s" % self.filename -- cgit v1.2.3