Skip to content

Commit 0cec424

Browse files
gh-66234: Add flag to disable the use of mmap in dbm.gnu (GH-135005)
This may harm performance, but improve crash tolerance.
1 parent 44fb7c3 commit 0cec424

File tree

5 files changed

+43
-2
lines changed

5 files changed

+43
-2
lines changed

Doc/library/dbm.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,9 @@ functionality like crash tolerance.
254254
* ``'s'``: Synchronized mode.
255255
Changes to the database will be written immediately to the file.
256256
* ``'u'``: Do not lock database.
257+
* ``'m'``: Do not use :manpage:`mmap(2)`.
258+
This may harm performance, but improve crash tolerance.
259+
.. versionadded:: next
257260

258261
Not all flags are valid for all versions of GDBM.
259262
See the :data:`open_flags` member for a list of supported flag characters.

Doc/whatsnew/3.15.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ dbm
9696
which allow to recover unused free space previously occupied by deleted entries.
9797
(Contributed by Andrea Oliveri in :gh:`134004`.)
9898

99+
* Add the ``'m'`` flag for :func:`dbm.gnu.open` which allows to disable
100+
the use of :manpage:`mmap(2)`.
101+
This may harm performance, but improve crash tolerance.
102+
(Contributed by Serhiy Storchaka in :gh:`66234`.)
99103

100104
difflib
101105
-------

Lib/test/test_dbm_gnu.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,12 @@ def test_flags(self):
7474
# Test the flag parameter open() by trying all supported flag modes.
7575
all = set(gdbm.open_flags)
7676
# Test standard flags (presumably "crwn").
77-
modes = all - set('fsu')
77+
modes = all - set('fsum')
7878
for mode in sorted(modes): # put "c" mode first
7979
self.g = gdbm.open(filename, mode)
8080
self.g.close()
8181

82-
# Test additional flags (presumably "fsu").
82+
# Test additional flags (presumably "fsum").
8383
flags = all - set('crwn')
8484
for mode in modes:
8585
for flag in flags:
@@ -217,6 +217,29 @@ def test_localized_error(self):
217217
create_empty_file(os.path.join(d, 'test'))
218218
self.assertRaises(gdbm.error, gdbm.open, filename, 'r')
219219

220+
@unittest.skipUnless('m' in gdbm.open_flags, "requires 'm' in open_flags")
221+
def test_nommap_no_crash(self):
222+
self.g = g = gdbm.open(filename, 'nm')
223+
os.truncate(filename, 0)
224+
225+
g.get(b'a', b'c')
226+
g.keys()
227+
g.firstkey()
228+
g.nextkey(b'a')
229+
with self.assertRaises(KeyError):
230+
g[b'a']
231+
with self.assertRaises(gdbm.error):
232+
len(g)
233+
234+
with self.assertRaises(gdbm.error):
235+
g[b'a'] = b'c'
236+
with self.assertRaises(gdbm.error):
237+
del g[b'a']
238+
with self.assertRaises(gdbm.error):
239+
g.setdefault(b'a', b'c')
240+
with self.assertRaises(gdbm.error):
241+
g.reorganize()
242+
220243

221244
if __name__ == '__main__':
222245
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add the ``'m'`` flag for :func:`dbm.gnu.open` which allows to disable the
2+
use of :manpage:`mmap(2)`. This may harm performance, but improve crash
3+
tolerance.

Modules/_gdbmmodule.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,11 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
813813
case 'u':
814814
iflags |= GDBM_NOLOCK;
815815
break;
816+
#endif
817+
#ifdef GDBM_NOMMAP
818+
case 'm':
819+
iflags |= GDBM_NOMMAP;
820+
break;
816821
#endif
817822
default:
818823
PyErr_Format(state->gdbm_error,
@@ -846,6 +851,9 @@ static const char gdbmmodule_open_flags[] = "rwcn"
846851
#endif
847852
#ifdef GDBM_NOLOCK
848853
"u"
854+
#endif
855+
#ifdef GDBM_NOMMAP
856+
"m"
849857
#endif
850858
;
851859

0 commit comments

Comments
 (0)