[PATCH 10/14] pytdb: Add support for tdb_check()

Kirill Smelkov kirr at landau.phys.spbu.ru
Sat Oct 2 07:43:49 MDT 2010


From: Kirill Smelkov <kirr at mns.spb.ru>

tdb_check() is needed when one wants to verify integrity of db, and
since tdb_check() is used in tdbtorture, let's add support for it.

NOTE: I've tried to reduce code duplication between __obj_traverse and
obj_check, but given these two functions sizes, deduplication only makes
things less readable and worse...

Signed-off-by: Kirill Smelkov <kirr at mns.spb.ru>
---
 lib/tdb/pytdb.c                |   62 ++++++++++++++++++++++++++++++++++++++++
 lib/tdb/python/tests/simple.py |   15 +++++++++
 2 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/lib/tdb/pytdb.c b/lib/tdb/pytdb.c
index 6d74b39..f119f5e 100644
--- a/lib/tdb/pytdb.c
+++ b/lib/tdb/pytdb.c
@@ -478,6 +478,7 @@ static int pytraverse_helper(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void
 	if (!pydata)
 		goto out;
 
+	/* fn(db, key, data) */
 	pyret = PyObject_CallFunctionObjArgs(pystate->pyfn, pystate->self, pykey, pydata, NULL);
 	if (!pyret)
 		goto out;
@@ -530,6 +531,64 @@ static PyObject *obj_traverse_read(PyTdbObject *self, PyObject *args)
 	return __obj_traverse(self, args, tdb_traverse_read);
 }
 
+/* check is like traverse, but differs in signature, sigh... */
+static int pycheck_helper(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;
+
+	/* check(key, data) */
+	pyret = PyObject_CallFunctionObjArgs(pystate->pyfn, 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_check(PyTdbObject *self, PyObject *args)
+{
+	struct pytraverse_state st;
+	int ret;
+
+	st.self = self;
+	if (!PyArg_ParseTuple(args, "O", &st.pyfn))
+		return NULL;
+
+	ret = tdb_check(self->ctx,
+			(st.pyfn != Py_None ? pycheck_helper : NULL),
+			&st);
+
+	/* check for py exceptions raised from-inside pycheck_helper, and
+	 * re-raise it if needed */
+	if (PyErr_Occurred())
+		return NULL;
+
+	if (ret == -1) {
+		PyErr_SetTDBError(self->ctx);
+		return NULL;
+	}
+
+	Py_RETURN_NONE;
+}
 
 static PyMethodDef tdb_object_methods[] = {
 	{ "transaction_cancel", (PyCFunction)obj_transaction_cancel, METH_NOARGS, 
@@ -590,6 +649,9 @@ static PyMethodDef tdb_object_methods[] = {
 		"Wipe the entire database." },
 	{ "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n"
 		"Repack the entire database." },
+	{ "check", (PyCFunction)obj_check, METH_VARARGS,
+		"S.check(check|None) -> None\n"
+		"check(key, data) -> ok?" },
 	{ "enable_seqnum", (PyCFunction)obj_enable_seqnum, METH_NOARGS,
 		"S.enable_seqnum() -> None" },
 	{ "increment_seqnum_nonblock", (PyCFunction)obj_increment_seqnum_nonblock, METH_NOARGS,
diff --git a/lib/tdb/python/tests/simple.py b/lib/tdb/python/tests/simple.py
index cd65b22..d0abaad 100644
--- a/lib/tdb/python/tests/simple.py
+++ b/lib/tdb/python/tests/simple.py
@@ -207,6 +207,21 @@ class SimpleTdbTests(TestCase):
 
         # the rest is the same as in .traverse
 
+    def test_check(self):
+        self.tdb["foo"] = "1"
+        self.tdb["zzzz"]= "123"
+        self.tdb.check(None)
+
+        def check(key, data):
+            return True # checked ok
+        self.tdb.check(check)
+
+        def check(key, data):
+            if key=="zzzz" and data != "1234":
+                1/0
+            return True
+        self.assertRaises(ZeroDivisionError, self.tdb.check, check)
+
 
     def test_iterkeys(self):
         self.tdb["bloe"] = "2"
-- 
1.7.3.1.50.g1e633


More information about the samba-technical mailing list