Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Doc/library/dbm.rst
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ functionality like crash tolerance.
* ``'s'``: Synchronized mode.
Changes to the database will be written immediately to the file.
* ``'u'``: Do not lock database.
* ``'m'``: Do not use :man:`mmap(2)`.
This may harm performance, but improve crash tolerance.
.. versionadded:: next

Not all flags are valid for all versions of GDBM.
See the :data:`open_flags` member for a list of supported flag characters.
Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ New modules
Improved modules
================

dbm
---

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

difflib
-------

Expand Down
27 changes: 25 additions & 2 deletions Lib/test/test_dbm_gnu.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ def test_flags(self):
# Test the flag parameter open() by trying all supported flag modes.
all = set(gdbm.open_flags)
# Test standard flags (presumably "crwn").
modes = all - set('fsu')
modes = all - set('fsum')
for mode in sorted(modes): # put "c" mode first
self.g = gdbm.open(filename, mode)
self.g.close()

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

@unittest.skipUnless('m' in gdbm.open_flags, "requires 'm' in open_flags")
def test_nommap_no_crash(self):
self.g = g = gdbm.open(filename, 'nm')
os.truncate(filename, 0)

g.get(b'a', b'c')
g.keys()
g.firstkey()
g.nextkey(b'a')
with self.assertRaises(KeyError):
g[b'a']
with self.assertRaises(gdbm.error):
len(g)

with self.assertRaises(gdbm.error):
g[b'a'] = b'c'
with self.assertRaises(gdbm.error):
del g[b'a']
with self.assertRaises(gdbm.error):
g.setdefault(b'a', b'c')
with self.assertRaises(gdbm.error):
g.reorganize()


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add the ``'m'`` flag for :func:`dbm.gnu.open` which allows to disable the
use of :man:`mmap(2)`. This may harm performance, but improve crash
tolerance.
8 changes: 8 additions & 0 deletions Modules/_gdbmmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,11 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
case 'u':
iflags |= GDBM_NOLOCK;
break;
#endif
#ifdef GDBM_NOMMAP
case 'm':
iflags |= GDBM_NOMMAP;
break;
#endif
default:
PyErr_Format(state->gdbm_error,
Expand Down Expand Up @@ -846,6 +851,9 @@ static const char gdbmmodule_open_flags[] = "rwcn"
#endif
#ifdef GDBM_NOLOCK
"u"
#endif
#ifdef GDBM_NOMMAP
"m"
#endif
;

Expand Down
Loading