Skip to content

Commit 8f9ba45

Browse files
committed
Set all sqlite db's to WAL mode on creation
Complete work done on 6917:fba76e0bba98. WAL journaling mode now enabled on primary db as well as session db's when using sqlite for session databases. Made change to WAL mode more robust for testing by bracketing `pragma journal_mode=wal` with commit() calls. Normally the conversion would occur when a new session was opened, but this commits the changes explicitly to make all the tests stable. Also added doc on this.
1 parent b0f21a4 commit 8f9ba45

File tree

5 files changed

+78
-3
lines changed

5 files changed

+78
-3
lines changed

CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ Features:
5959
- sqlite native-fts backend now uses the stopwords list in config.ini
6060
to filter words from queries. (Stopwords are still indexed so that
6161
phrase/proximity searches still work.) (John Rouillard)
62+
- sqlite databases use WAL mode when *created* to improve read
63+
concurrency. Existing sqlite database still use rollback journal
64+
mode. See upgrading.txt for details. (John Rouillard)
6265

6366
2022-07-13 2.2.0
6467

doc/upgrading.txt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,51 @@ Session Databases`_ in the `administration guide`_
124124
.. _Using Redis for Session Databases:
125125
admin_guide.html#using-redis-for-session-databases
126126

127+
New SQLite databases created with WAL mode journaling (optional)
128+
----------------------------------------------------------------
129+
130+
By default, SQLite databases use a rollback journal when
131+
writing an update. The rollback journal stores a copy of the
132+
data from before the update. One downside of this is that
133+
all reads have to be suspended while a write is
134+
occurring. SQLite has an alternate way of insuring ACID
135+
compliance by using a WAL (write ahead log) journal.
136+
137+
Version 2.3.0 of Roundup, creates new SQLite databases using
138+
WAL journaling. With WAL, a writer does not block readers
139+
and readers do not block writing an update. This keeps
140+
Roundup accessible even under a heavy write load (e.g. when
141+
bulk loading data or automated updates via REST).
142+
143+
If you want to convert your existing SQLite db to WAL mode:
144+
145+
1. check the current journal mode on your database
146+
using::
147+
148+
sqlite3 <tracker_home>/db/db "pragma journal_mode;"
149+
150+
2. If it returns ``delete``, change it to WAL mode using::
151+
152+
sqlite3 <tracker_home>/db/db "pragma journal_mode=WAL;"
153+
154+
3. verify by running the command in step 1 again and you
155+
should get ``wal``.
156+
157+
If you are using SQLite for session and otk databases,
158+
perform the same steps replacing ``db`` with ``db-session``
159+
and ``db-otk``.
160+
161+
If you find WAL mode is not working for you, you can set the
162+
journal method to a rollback journal (``delete`` mode) by
163+
using step 2 and replacing ``wal`` with ``delete``. (Note:
164+
SQLite supports other journaling modes, but only ``wal`` and
165+
``delete`` persist. Roundup doesn't set a journaling mode
166+
when it opens the database, so options such as ``truncate``
167+
are not used.)
168+
169+
For details on WAL mode see `<https://www.sqlite.org/wal.html>`_
170+
and `<https://www.sqlite.org/pragma.html#pragma_journal_mode>`_.
171+
127172
.. index:: Upgrading; 2.1.0 to 2.2.0
128173

129174
Migrating from 2.1.0 to 2.2.0

roundup/backends/back_sqlite.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,9 @@ def open_connection(self):
204204
self.create_version_2_tables()
205205
self._add_fts5_table()
206206
# Set journal mode to WAL.
207-
self.conn.execute('pragma journal_mode=wal')
207+
self.sql_commit() # close out rollback journal/transaction
208+
self.sql('pragma journal_mode=wal') # set wal
209+
self.sql_commit() # close out rollback and commit wal change
208210

209211
def create_version_2_tables(self):
210212
self.sql('create table otks (otk_key varchar, '

roundup/backends/sessions_sqlite.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ def __init__(self, db):
3636
%(name)s_value TEXT, %(name)s_time REAL)''' % {"name": self.name})
3737
self.sql('CREATE INDEX %(name)s_key_idx ON '
3838
'%(name)ss(%(name)s_key)' % {"name": self.name})
39-
self.commit()
39+
# Set journal mode to WAL.
40+
self.commit() # close out rollback journal/transaction
41+
self.sql('pragma journal_mode=wal') # set wal
42+
self.commit() # close out rollback and commit wal change
4043

4144
def sql(self, sql, args=None, cursor=None):
4245
""" Execute the sql with the optional args.

test/test_sqlite.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ class sqliteOpener:
3333
def nuke_database(self):
3434
shutil.rmtree(config.DATABASE)
3535

36+
def testWalMode(self):
37+
"""verify that all sqlite db's are in WAL mode
38+
and not journal mode
39+
"""
40+
if not hasattr(self, 'db'):
41+
self.skipTest("test has no database open")
42+
43+
for db in [self.db]:
44+
print("testing db", str(db))
45+
db.sql('pragma journal_mode;')
46+
self.assertEqual(db.cursor.fetchone()['journal_mode'], 'wal')
47+
3648

3749
class sqliteDBTest(sqliteOpener, DBTest, unittest.TestCase):
3850

@@ -198,6 +210,15 @@ def testDbType(self):
198210
self.assertIn("roundlite", repr(self.db))
199211
self.assertIn("roundup.backends.sessions_sqlite.Sessions", repr(self.db.Session))
200212

213+
def testWalMode(self):
214+
"""verify that all sqlite db's are in WAL mode
215+
and not Rollback mode
216+
"""
217+
for db in [self.db, self.db.Session, self.db.Otk]:
218+
print("testing db", str(db))
219+
db.sql('pragma journal_mode;')
220+
self.assertEqual(db.cursor.fetchone()['journal_mode'], 'wal')
221+
201222
class anydbmSessionTest(sqliteOpener, SessionTest, unittest.TestCase):
202223
s2b = lambda x,y : y
203224

@@ -227,6 +248,7 @@ def get_ts(self):
227248
def testDbType(self):
228249
self.assertIn("roundlite", repr(self.db))
229250
self.assertIn("roundup.backends.sessions_dbm.Sessions", repr(self.db.Session))
230-
251+
252+
231253
class sqliteRestTest (RestTestCase, unittest.TestCase):
232254
backend = 'sqlite'

0 commit comments

Comments
 (0)