GH-46412: More efficient bool() for ndbm/_gdbmmodule by gvanrossum · Pull Request #96692 · python/cpython · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
14 changes: 14 additions & 0 deletions Lib/test/test_dbm_gnu.py
14 changes: 14 additions & 0 deletions Lib/test/test_dbm_ndbm.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,20 @@ def test_open_with_bytes_path(self):
def test_open_with_pathlib_bytes_path(self):
dbm.ndbm.open(os_helper.FakePath(os.fsencode(self.filename)), "c").close()

def test_bool_empty(self):
with dbm.ndbm.open(self.filename, 'c') as db:
self.assertFalse(bool(db))

def test_bool_not_empty(self):
with dbm.ndbm.open(self.filename, 'c') as db:
db['a'] = 'b'
self.assertTrue(bool(db))

def test_bool_on_closed_db_raises(self):
with dbm.ndbm.open(self.filename, 'c') as db:
db['a'] = 'b'
self.assertRaises(dbm.ndbm.error, bool, db)


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve performance of ``bool(db)`` for large ndb/gdb databases. Previously this would call ``len(db)`` which would iterate over all keys -- the answer (empty or not) is known after the first key.
32 changes: 32 additions & 0 deletions Modules/_dbmmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,37 @@ dbm_length(dbmobject *dp)
return dp->di_size;
}

static int
dbm_bool(dbmobject *dp)
{
_dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
assert(state != NULL);

if (dp->di_dbm == NULL) {
PyErr_SetString(state->dbm_error, "DBM object has already been closed");
return -1;
}

if (dp->di_size > 0) {
/* Known non-zero size. */
return 1;
}
if (dp->di_size == 0) {
/* Known zero size. */
return 0;
}

/* Unknown size. Ensure DBM object has an entry. */
datum key = dbm_firstkey(dp->di_dbm);
if (key.dptr == NULL) {
/* Empty. Cache this fact. */
dp->di_size = 0;
return 0;
}
/* Non-empty. Don't cache the length since we don't know. */
return 1;
}

static PyObject *
dbm_subscript(dbmobject *dp, PyObject *key)
{
Expand Down Expand Up @@ -416,6 +447,7 @@ static PyType_Slot dbmtype_spec_slots[] = {
{Py_mp_length, dbm_length},
{Py_mp_subscript, dbm_subscript},
{Py_mp_ass_subscript, dbm_ass_sub},
{Py_nb_bool, dbm_bool},
{0, 0}
};

Expand Down
30 changes: 30 additions & 0 deletions Modules/_gdbmmodule.c