Skip to content

Commit

Permalink
Merge pull request #89 from twisted/76-journal-mode
Browse files Browse the repository at this point in the history
Allow configuring the SQLite journal mode.
  • Loading branch information
mithrandi committed Aug 27, 2018
2 parents 3dc4ba5 + 6a3c1ed commit 3366072
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 17 deletions.
9 changes: 8 additions & 1 deletion axiom/scripts/axiomatic.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ def getArguments(self, store, args):
if not platform.isWindows() and handlePidfile:
args.extend(["--pidfile", run.child("axiomatic.pid").path])
args.extend(["axiomatic-start", "--dbdir", store.dbdir.path])
if store.journalMode is not None:
args.extend(['--journal-mode', store.journalMode.encode('ascii')])
return args


Expand Down Expand Up @@ -168,6 +170,7 @@ def get(self):

optParameters = [
('dbdir', 'd', None, 'Path containing axiom database to configure/create'),
('journal-mode', None, None, 'SQLite journal mode to set'),
]

optFlags = [
Expand Down Expand Up @@ -197,8 +200,12 @@ def getStoreDirectory(self):

def getStore(self):
from axiom.store import Store
jm = self['journal-mode']
if jm is not None:
jm = jm.decode('ascii')
if self.store is None:
self.store = Store(self.getStoreDirectory(), debug=self['debug'])
self.store = Store(
self.getStoreDirectory(), debug=self['debug'], journalMode=jm)
return self.store


Expand Down
7 changes: 6 additions & 1 deletion axiom/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,8 @@ def _currentlyValidAsReferentFor(self, store):
storeID = STORE_SELF_ID


def __init__(self, dbdir=None, filesdir=None, debug=False, parent=None, idInParent=None):
def __init__(self, dbdir=None, filesdir=None, debug=False, parent=None,
idInParent=None, journalMode=None):
"""
Create a store.
Expand Down Expand Up @@ -1147,6 +1148,7 @@ def __init__(self, dbdir=None, filesdir=None, debug=False, parent=None, idInPare
self.idInParent = idInParent
self.debug = debug
self.autocommit = True
self.journalMode = journalMode
self.queryTimes = []
self.execTimes = []

Expand Down Expand Up @@ -1373,6 +1375,9 @@ def _loadExistingIndexes(self):
def _initdb(self, dbfname):
self.connection = Connection.fromDatabaseName(dbfname)
self.cursor = self.connection.cursor()
if self.journalMode is not None:
self.querySchemaSQL(
'PRAGMA *DATABASE*.journal_mode = {}'.format(self.journalMode))


def __repr__(self):
Expand Down
14 changes: 9 additions & 5 deletions axiom/substore.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,19 @@ def close(self):
del self.substore


def open(self, debug=False):
def open(self, debug=None):
if hasattr(self, 'substore'):
return self.substore
else:
s = self.substore = self.createStore(debug)
if debug is None:
debug = self.store.debug
s = self.substore = self.createStore(debug, self.store.journalMode)
s._openSubStore = self # don't fall out of cache as long as the
# store is alive!
return s


def createStore(self, debug):
def createStore(self, debug, journalMode=None):
"""
Create the actual Store this Substore represents.
"""
Expand All @@ -72,12 +74,14 @@ def createStore(self, debug):
return Store(parent=self.store,
filesdir=filesdir,
idInParent=self.storeID,
debug=debug)
debug=debug,
journalMode=journalMode)
else:
return Store(self.storepath.path,
parent=self.store,
idInParent=self.storeID,
debug=debug)
debug=debug,
journalMode=journalMode)


def __conform__(self, interface):
Expand Down
39 changes: 31 additions & 8 deletions axiom/test/test_axiomatic.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class StartTests(TestCase):
"""
Test the axiomatic start sub-command.
"""
maxDiff = None
def setUp(self):
"""
Work around Twisted #3178 by tricking trial into thinking something
Expand All @@ -95,10 +96,10 @@ def test_getArguments(self):
L{Start.getArguments} adds a I{--pidfile} argument if one is not
present and a I{--logfile} argument if one is not present and
daemonization is enabled and adds a I{--dbdir} argument pointing at the
store it is passed.
store it is passed. It also adds I{--journal-mode} if this is passed.
"""
dbdir = FilePath(self.mktemp())
store = Store(dbdir)
store = Store(dbdir, journalMode=u'WAL')
run = self._getRunDir(dbdir)
logs = self._getLogDir(dbdir)
start = axiomatic.Start()
Expand All @@ -111,7 +112,8 @@ def test_getArguments(self):
pidfileArg = []
else:
pidfileArg = ["--pidfile", run.child("axiomatic.pid").path]
restArg = ["axiomatic-start", "--dbdir", dbdir.path]
restArg = [
"axiomatic-start", "--dbdir", dbdir.path, "--journal-mode", "WAL"]

self.assertEqual(
start.getArguments(store, []),
Expand Down Expand Up @@ -221,7 +223,8 @@ def test_checkSystemVersion(self):
"""
dbdir = self.mktemp()
store = Store(dbdir)
service = AxiomaticStart.makeService({'dbdir': dbdir, 'debug': False})
service = AxiomaticStart.makeService(
{'dbdir': dbdir, 'debug': False, 'journal-mode': None})
self.assertEqual(store.query(SystemVersion).count(), 0)
service.startService()
self.assertEqual(store.query(SystemVersion).count(), 1)
Expand All @@ -230,16 +233,19 @@ def test_checkSystemVersion(self):

def test_axiomOptions(self):
"""
L{AxiomaticStart.options} takes database location and debug setting
parameters.
L{AxiomaticStart.options} takes database location, debug, and
journal mode setting parameters.
"""
options = AxiomaticStart.options()
options.parseOptions([])
self.assertEqual(options['dbdir'], None)
self.assertFalse(options['debug'])
options.parseOptions(["--dbdir", "foo", "--debug"])
self.assertEqual(options['journal-mode'], None)
options.parseOptions(
["--dbdir", "foo", "--debug", "--journal-mode", "WAL"])
self.assertEqual(options['dbdir'], 'foo')
self.assertTrue(options['debug'])
self.assertEqual(options['journal-mode'], 'WAL')


def test_makeService(self):
Expand All @@ -254,7 +260,8 @@ def test_makeService(self):
store.powerUp(recorder, IService)
store.close()

service = AxiomaticStart.makeService({"dbdir": dbdir, "debug": False})
service = AxiomaticStart.makeService(
{'dbdir': dbdir, 'debug': False, 'journal-mode': None})
service.startService()
service.stopService()

Expand Down Expand Up @@ -489,3 +496,19 @@ class _TestSubClass(axiomatic.AxiomaticCommand):

self.failUnless(IAxiomaticCommand.providedBy(_TestSubClass), 'IAxiomaticCommand not provided')
self.failUnless(IPlugin.providedBy(_TestSubClass), 'IPlugin not provided')



class AxiomaticTests(TestCase):
"""
Test things relating to the I{axiomatic} command itself.
"""
def test_journalMode(self):
"""
I{axiomatic} sets the journal mode of the store according to
I{--journal-mode}.
"""
options = axiomatic.Options()
options['dbdir'] = self.mktemp()
options['journal-mode'] = 'WAL'
self.assertEqual(options.getStore().journalMode, u'WAL')
12 changes: 12 additions & 0 deletions axiom/test/test_substore.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,18 @@ def test_createNewStringPath(self):
e.args[0], "Received 'notasequence' instead of a sequence")


def test_inheritParentConfiguration(self):
"""
Substores use the debug and journal configuration of the parent store.
"""
filesdir = filepath.FilePath(self.mktemp())
s = Store(filesdir=filesdir, debug=True, journalMode=u'MEMORY')
ss = SubStore.createNew(s, ['account', 'bob@divmod.com'])
s2 = ss.open()
self.assertEqual(s2.debug, True)
self.assertEqual(s2.journalMode, u'MEMORY')



class SubStoreStartupSemantics(unittest.TestCase):
"""
Expand Down
24 changes: 24 additions & 0 deletions axiom/test/test_xatop.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,30 @@ def test_closing(self):
self.assertTrue(cursor.closed, 'Cursor should be closed')


def test_journalMode(self):
"""
Passing a journalling mode sets that mode on open.
"""
dbdir = filepath.FilePath(self.mktemp())
s = store.Store(dbdir, journalMode=u'MEMORY')
self.assertEquals(
s.querySchemaSQL('PRAGMA *DATABASE*.journal_mode'),
[(u'memory',)])


def test_journalModeNone(self):
"""
Passing a journalling mode of C{None} sets no mode.
"""
dbdir = filepath.FilePath(self.mktemp())
s = store.Store(dbdir, journalMode=u'WAL')
s.close()
s = store.Store(dbdir, journalMode=None)
self.assertEquals(
s.querySchemaSQL('PRAGMA *DATABASE*.journal_mode'),
[(u'wal',)])



class FailurePathTests(unittest.TestCase):

Expand Down
9 changes: 7 additions & 2 deletions twisted/plugins/axiom_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ class AxiomaticStart(object):

class options(Options):
optParameters = [
('dbdir', 'd', None, 'Path containing Axiom database to start')]
('dbdir', 'd', None, 'Path containing Axiom database to start'),
('journal-mode', None, None, 'SQLite journal mode to set'),
]

optFlags = [('debug', 'b', 'Enable Axiom-level debug logging')]

Expand All @@ -50,7 +52,10 @@ def makeService(cls, options):
configuration.
"""
from axiom.store import Store
store = Store(options['dbdir'], debug=options['debug'])
jm = options['journal-mode']
if jm is not None:
jm = jm.decode('ascii')
store = Store(options['dbdir'], debug=options['debug'], journalMode=jm)
service = IService(store)
_CheckSystemVersion(store).setServiceParent(service)
return service
Expand Down

0 comments on commit 3366072

Please sign in to comment.