[PATCH 09/14] pytdb: Add support for tdb_traverse & tdb_traverse_read
Kirill Smelkov
kirr at landau.phys.spbu.ru
Sat Oct 2 07:43:48 MDT 2010
From: Kirill Smelkov <kirr at mns.spb.ru>
This functions are sometimes needed for making more controlled db
traversal compared to firstkey/nextkey, and also they are used in
tdbtorture, so add support for them.
Signed-off-by: Kirill Smelkov <kirr at mns.spb.ru>
---
lib/tdb/pytdb.c | 81 ++++++++++++++++++++++++++++++++++++++++
lib/tdb/python/tests/simple.py | 38 +++++++++++++++++++
2 files changed, 119 insertions(+), 0 deletions(-)
diff --git a/lib/tdb/pytdb.c b/lib/tdb/pytdb.c
index 2f54fcf..6d74b39 100644
--- a/lib/tdb/pytdb.c
+++ b/lib/tdb/pytdb.c
@@ -456,6 +456,81 @@ static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self)
Py_RETURN_NONE;
}
+/* traverse */
+struct pytraverse_state {
+ PyTdbObject *self;
+ PyObject *pyfn;
+};
+
+static int pytraverse_helper(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ struct pytraverse_state *pystate = state;
+
+ PyObject *pykey=NULL, *pydata=NULL;
+ PyObject *pyret=NULL;
+ int ret=-1;
+
+ pykey = __PyString_FromTDB_DATA(key, /*release=*/false);
+ if (!pykey)
+ goto out;
+
+ pydata = __PyString_FromTDB_DATA(dbuf, /*release=*/false);
+ if (!pydata)
+ goto out;
+
+ pyret = PyObject_CallFunctionObjArgs(pystate->pyfn, pystate->self, pykey, pydata, NULL);
+ if (!pyret)
+ goto out;
+
+ if (PyObject_IsTrue(pyret))
+ ret = 0; /* tell tdb to continue traversal */
+
+out:
+ Py_XDECREF(pykey);
+ Py_XDECREF(pydata);
+ Py_XDECREF(pyret);
+
+ return ret;
+}
+
+static PyObject *__obj_traverse(PyTdbObject *self, PyObject *args,
+ int (*traverse)(struct tdb_context *, tdb_traverse_func, void *))
+{
+ struct pytraverse_state st;
+ int ret;
+
+ st.self = self;
+ if (!PyArg_ParseTuple(args, "O", &st.pyfn))
+ return NULL;
+
+ ret = traverse(self->ctx,
+ (st.pyfn != Py_None ? pytraverse_helper : NULL),
+ &st);
+
+ /* check for py exceptions raised from-inside pytraverse_helper, and
+ * re-raise it if needed */
+ if (PyErr_Occurred())
+ return NULL;
+
+ if (ret == -1) {
+ PyErr_SetTDBError(self->ctx);
+ return NULL;
+ }
+
+ return PyInt_FromLong(ret);
+}
+
+static PyObject *obj_traverse(PyTdbObject *self, PyObject *args)
+{
+ return __obj_traverse(self, args, tdb_traverse);
+}
+
+static PyObject *obj_traverse_read(PyTdbObject *self, PyObject *args)
+{
+ return __obj_traverse(self, args, tdb_traverse_read);
+}
+
+
static PyMethodDef tdb_object_methods[] = {
{ "transaction_cancel", (PyCFunction)obj_transaction_cancel, METH_NOARGS,
"S.transaction_cancel() -> None\n"
@@ -519,6 +594,12 @@ static PyMethodDef tdb_object_methods[] = {
"S.enable_seqnum() -> None" },
{ "increment_seqnum_nonblock", (PyCFunction)obj_increment_seqnum_nonblock, METH_NOARGS,
"S.increment_seqnum_nonblock() -> None" },
+ { "traverse", (PyCFunction)obj_traverse, METH_VARARGS,
+ "S.traverse(fn|None) -> ntraversed\n"
+ "fn(key, data) -> continue?" },
+ { "traverse_read", (PyCFunction)obj_traverse_read, METH_VARARGS,
+ "S.traverse_read(fn|None) -> ntraversed\n"
+ "fn(key, data) -> continue?" },
{ NULL }
};
diff --git a/lib/tdb/python/tests/simple.py b/lib/tdb/python/tests/simple.py
index 4fe5008..cd65b22 100644
--- a/lib/tdb/python/tests/simple.py
+++ b/lib/tdb/python/tests/simple.py
@@ -170,6 +170,44 @@ class SimpleTdbTests(TestCase):
self.tdb.transaction_commit()
self.assertEquals("1", self.tdb["bloe"])
+ def test_traverse(self):
+ self.tdb["a"] = "1"
+ self.tdb["b"] = "2"
+ self.tdb["c"] = "3"
+
+ n = self.tdb.traverse(None)
+ self.assertEquals(n, 3)
+
+ v = []
+ def fn(db, key, data):
+ v.append( (key, data) )
+ return True
+ n = self.tdb.traverse(fn)
+ self.assertEquals(n, 3)
+ self.assertEquals(set(v), set([("a","1"), ("b","2"), ("c","3")]))
+
+ v = []
+ def fn(db, key, data):
+ return False
+ n = self.tdb.traverse(fn)
+ self.assertEquals(n, 1)
+
+ v = []
+ def fn(db, key, data):
+ 1/0
+ self.assertRaises(ZeroDivisionError, self.tdb.traverse, fn)
+
+ def test_traverse_read(self):
+ self.tdb["a"] = "1"
+ self.tdb["b"] = "2"
+ self.tdb["c"] = "3"
+
+ n = self.tdb.traverse_read(None)
+ self.assertEquals(n, 3)
+
+ # the rest is the same as in .traverse
+
+
def test_iterkeys(self):
self.tdb["bloe"] = "2"
self.tdb["bla"] = "25"
--
1.7.3.1.50.g1e633
More information about the samba-technical
mailing list