#1607951: Make mailbox.Maildir re-read the directories less frequently.
This is done by recording the current time -1sec, and not re-reading unless the directory mod. times are >= the recorded time.
This commit is contained in:
parent
6e7bdde2c8
commit
420d4eb1f3
|
@ -237,6 +237,7 @@ class Maildir(Mailbox):
|
||||||
else:
|
else:
|
||||||
raise NoSuchMailboxError(self._path)
|
raise NoSuchMailboxError(self._path)
|
||||||
self._toc = {}
|
self._toc = {}
|
||||||
|
self._last_read = None # Records last time we read cur/new
|
||||||
|
|
||||||
def add(self, message):
|
def add(self, message):
|
||||||
"""Add message and return assigned key."""
|
"""Add message and return assigned key."""
|
||||||
|
@ -461,16 +462,35 @@ class Maildir(Mailbox):
|
||||||
|
|
||||||
def _refresh(self):
|
def _refresh(self):
|
||||||
"""Update table of contents mapping."""
|
"""Update table of contents mapping."""
|
||||||
|
new_mtime = os.path.getmtime(os.path.join(self._path, 'new'))
|
||||||
|
cur_mtime = os.path.getmtime(os.path.join(self._path, 'cur'))
|
||||||
|
|
||||||
|
if (self._last_read is not None and
|
||||||
|
new_mtime <= self._last_read and cur_mtime <= self._last_read):
|
||||||
|
return
|
||||||
|
|
||||||
self._toc = {}
|
self._toc = {}
|
||||||
for subdir in ('new', 'cur'):
|
def update_dir (subdir):
|
||||||
subdir_path = os.path.join(self._path, subdir)
|
path = os.path.join(self._path, subdir)
|
||||||
for entry in os.listdir(subdir_path):
|
for entry in os.listdir(path):
|
||||||
p = os.path.join(subdir_path, entry)
|
p = os.path.join(path, entry)
|
||||||
if os.path.isdir(p):
|
if os.path.isdir(p):
|
||||||
continue
|
continue
|
||||||
uniq = entry.split(self.colon)[0]
|
uniq = entry.split(self.colon)[0]
|
||||||
self._toc[uniq] = os.path.join(subdir, entry)
|
self._toc[uniq] = os.path.join(subdir, entry)
|
||||||
|
|
||||||
|
update_dir('new')
|
||||||
|
update_dir('cur')
|
||||||
|
|
||||||
|
# We record the current time - 1sec so that, if _refresh() is called
|
||||||
|
# again in the same second, we will always re-read the mailbox
|
||||||
|
# just in case it's been modified. (os.path.mtime() only has
|
||||||
|
# 1sec resolution.) This results in a few unnecessary re-reads
|
||||||
|
# when _refresh() is called multiple times in the same second,
|
||||||
|
# but once the clock ticks over, we will only re-read as needed.
|
||||||
|
now = int(time.time() - 1)
|
||||||
|
self._last_read = time.time() - 1
|
||||||
|
|
||||||
def _lookup(self, key):
|
def _lookup(self, key):
|
||||||
"""Use TOC to return subpath for given key, or raise a KeyError."""
|
"""Use TOC to return subpath for given key, or raise a KeyError."""
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -747,6 +747,37 @@ class TestMaildir(TestMailbox):
|
||||||
perms = st.st_mode
|
perms = st.st_mode
|
||||||
self.assertFalse((perms & 0111)) # Execute bits should all be off.
|
self.assertFalse((perms & 0111)) # Execute bits should all be off.
|
||||||
|
|
||||||
|
def test_reread(self):
|
||||||
|
# Wait for 2 seconds
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
# Initially, the mailbox has not been read and the time is null.
|
||||||
|
assert getattr(self._box, '_last_read', None) is None
|
||||||
|
|
||||||
|
# Refresh mailbox; the times should now be set to something.
|
||||||
|
self._box._refresh()
|
||||||
|
assert getattr(self._box, '_last_read', None) is not None
|
||||||
|
|
||||||
|
# Try calling _refresh() again; the modification times shouldn't have
|
||||||
|
# changed, so the mailbox should not be re-reading. Re-reading causes
|
||||||
|
# the ._toc attribute to be assigned a new dictionary object, so
|
||||||
|
# we'll check that the ._toc attribute isn't a different object.
|
||||||
|
orig_toc = self._box._toc
|
||||||
|
def refreshed():
|
||||||
|
return self._box._toc is not orig_toc
|
||||||
|
|
||||||
|
time.sleep(1) # Wait 1sec to ensure time.time()'s value changes
|
||||||
|
self._box._refresh()
|
||||||
|
assert not refreshed()
|
||||||
|
|
||||||
|
# Now, write something into cur and remove it. This changes
|
||||||
|
# the mtime and should cause a re-read.
|
||||||
|
filename = os.path.join(self._path, 'cur', 'stray-file')
|
||||||
|
f = open(filename, 'w')
|
||||||
|
f.close()
|
||||||
|
os.unlink(filename)
|
||||||
|
self._box._refresh()
|
||||||
|
assert refreshed()
|
||||||
|
|
||||||
class _TestMboxMMDF(TestMailbox):
|
class _TestMboxMMDF(TestMailbox):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue