notmuch/test/atomicity.py
David Bremner 45a0ab9e84 test/atomicity: guard chert-only optimization
This should potentially be updated to have an equivalent optimization
for the glass backend, but it in my unscientific tests, the glass backend
without the optimization is faster then the chert backend with.
2016-04-12 20:11:53 -03:00

74 lines
2.8 KiB
Python

# This gdb Python script runs notmuch new and simulates killing and
# restarting notmuch new after every Xapian commit. To simulate this
# more efficiently, this script runs notmuch new and, immediately
# after every Xapian commit, it *pauses* the running notmuch new,
# copies the entire database and maildir to a snapshot directory, and
# executes a full notmuch new on that snapshot, comparing the final
# results with the expected output. It can then resume the paused
# notmuch new, which is still running on the original maildir, and
# repeat this process.
import gdb
import os
import glob
import shutil
import subprocess
gdb.execute('set args new')
# Make Xapian commit after every operation instead of batching
gdb.execute('set environment XAPIAN_FLUSH_THRESHOLD = 1')
maildir = os.environ['MAIL_DIR']
# Trap calls to rename, which happens just before Xapian commits
class RenameBreakpoint(gdb.Breakpoint):
def __init__(self, *args, **kwargs):
super(RenameBreakpoint, self).__init__(*args, **kwargs)
self.last_inodes = {}
self.n = 0
def stop(self):
xapiandir = '%s/.notmuch/xapian' % maildir
if os.path.isfile('%s/iamchert' % xapiandir):
# As an optimization, only consider snapshots after a
# Xapian has really committed. The chert backend
# overwrites record.base? as the last step in the commit,
# so keep an eye on their inumbers.
inodes = {}
for path in glob.glob('%s/record.base*' % xapiandir):
inodes[path] = os.stat(path).st_ino
if inodes == self.last_inodes:
# Continue
return False
self.last_inodes = inodes
# Save a backtrace in case the test does fail
backtrace = gdb.execute('backtrace', to_string=True)
open('backtrace.%d' % self.n, 'w').write(backtrace)
# Snapshot the database
shutil.rmtree('%s.snap/.notmuch' % maildir)
shutil.copytree('%s/.notmuch' % maildir, '%s.snap/.notmuch' % maildir)
# Restore the mtime of $MAIL_DIR.snap/
shutil.copystat('%s/.notmuch' % maildir, '%s.snap/.notmuch' % maildir)
# Run notmuch new to completion on the snapshot
env = os.environ.copy()
env.update(NOTMUCH_CONFIG=os.environ['NOTMUCH_CONFIG'] + '.snap',
XAPIAN_FLUSH_THRESHOLD='1000')
subprocess.check_call(
['notmuch', 'new'], env=env, stdout=open('/dev/null', 'w'))
subprocess.check_call(
['notmuch', 'search', '*'], env=env,
stdout=open('search.%d' % self.n, 'w'))
# Tell the shell how far we've gotten
open('outcount', 'w').write(str(self.n + 1))
# Continue
self.n += 1
return False
RenameBreakpoint('rename')
gdb.execute('run')