Hello community, here is the log from the commit of package tdb for openSUSE:Factory checked in at 2015-07-27 09:09:33 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/tdb (Old) and /work/SRC/openSUSE:Factory/.tdb.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "tdb" Changes: -------- --- /work/SRC/openSUSE:Factory/tdb/tdb.changes 2015-07-05 17:53:14.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.tdb.new/tdb.changes 2015-07-27 09:09:34.000000000 +0200 @@ -1,0 +2,8 @@ +Wed Jul 22 07:37:56 UTC 2015 - [email protected] + +- Update to version 1.3.7. + + first fix deadlock in the interaction between fcntl and mutex locking; + (bso#11381) + + improved python3 bindings + +------------------------------------------------------------------- Old: ---- tdb-1.3.6.tar.asc tdb-1.3.6.tar.gz New: ---- tdb-1.3.7.tar.asc tdb-1.3.7.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ tdb.spec ++++++ --- /var/tmp/diff_new_pack.TvP3Xg/_old 2015-07-27 09:09:35.000000000 +0200 +++ /var/tmp/diff_new_pack.TvP3Xg/_new 2015-07-27 09:09:35.000000000 +0200 @@ -34,7 +34,7 @@ %endif BuildRequires: python-devel Url: http://tdb.samba.org/ -Version: 1.3.6 +Version: 1.3.7 Release: 0 Summary: Samba Trivial Database License: GPL-3.0+ @@ -178,5 +178,6 @@ %files -n python-tdb %defattr(-,root,root,-) %{python_sitearch}/tdb.so +%{python_sitearch}/_tdb_text.py* %changelog ++++++ tdb-1.3.6.tar.gz -> tdb-1.3.7.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/ABI/tdb-1.3.7.sigs new/tdb-1.3.7/ABI/tdb-1.3.7.sigs --- old/tdb-1.3.6/ABI/tdb-1.3.7.sigs 1970-01-01 01:00:00.000000000 +0100 +++ new/tdb-1.3.7/ABI/tdb-1.3.7.sigs 2015-07-21 22:35:18.000000000 +0200 @@ -0,0 +1,69 @@ +tdb_add_flags: void (struct tdb_context *, unsigned int) +tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) +tdb_chainlock: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) +tdb_chainunlock: int (struct tdb_context *, TDB_DATA) +tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) +tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) +tdb_close: int (struct tdb_context *) +tdb_delete: int (struct tdb_context *, TDB_DATA) +tdb_dump_all: void (struct tdb_context *) +tdb_enable_seqnum: void (struct tdb_context *) +tdb_error: enum TDB_ERROR (struct tdb_context *) +tdb_errorstr: const char *(struct tdb_context *) +tdb_exists: int (struct tdb_context *, TDB_DATA) +tdb_fd: int (struct tdb_context *) +tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) +tdb_firstkey: TDB_DATA (struct tdb_context *) +tdb_freelist_size: int (struct tdb_context *) +tdb_get_flags: int (struct tdb_context *) +tdb_get_logging_private: void *(struct tdb_context *) +tdb_get_seqnum: int (struct tdb_context *) +tdb_hash_size: int (struct tdb_context *) +tdb_increment_seqnum_nonblock: void (struct tdb_context *) +tdb_jenkins_hash: unsigned int (TDB_DATA *) +tdb_lock_nonblock: int (struct tdb_context *, int, int) +tdb_lockall: int (struct tdb_context *) +tdb_lockall_mark: int (struct tdb_context *) +tdb_lockall_nonblock: int (struct tdb_context *) +tdb_lockall_read: int (struct tdb_context *) +tdb_lockall_read_nonblock: int (struct tdb_context *) +tdb_lockall_unmark: int (struct tdb_context *) +tdb_log_fn: tdb_log_func (struct tdb_context *) +tdb_map_size: size_t (struct tdb_context *) +tdb_name: const char *(struct tdb_context *) +tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) +tdb_null: dptr = 0xXXXX, dsize = 0 +tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) +tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) +tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) +tdb_printfreelist: int (struct tdb_context *) +tdb_remove_flags: void (struct tdb_context *, unsigned int) +tdb_reopen: int (struct tdb_context *) +tdb_reopen_all: int (int) +tdb_repack: int (struct tdb_context *) +tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *) +tdb_runtime_check_for_robust_mutexes: bool (void) +tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) +tdb_set_max_dead: void (struct tdb_context *, int) +tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) +tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) +tdb_summary: char *(struct tdb_context *) +tdb_transaction_cancel: int (struct tdb_context *) +tdb_transaction_commit: int (struct tdb_context *) +tdb_transaction_prepare_commit: int (struct tdb_context *) +tdb_transaction_start: int (struct tdb_context *) +tdb_transaction_start_nonblock: int (struct tdb_context *) +tdb_transaction_write_lock_mark: int (struct tdb_context *) +tdb_transaction_write_lock_unmark: int (struct tdb_context *) +tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) +tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) +tdb_unlock: int (struct tdb_context *, int, int) +tdb_unlockall: int (struct tdb_context *) +tdb_unlockall_read: int (struct tdb_context *) +tdb_validate_freelist: int (struct tdb_context *, int *) +tdb_wipe_all: int (struct tdb_context *) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/_tdb_text.py new/tdb-1.3.7/_tdb_text.py --- old/tdb-1.3.6/_tdb_text.py 1970-01-01 01:00:00.000000000 +0100 +++ new/tdb-1.3.7/_tdb_text.py 2015-07-21 22:32:32.000000000 +0200 @@ -0,0 +1,138 @@ +# Text wrapper for tdb bindings +# +# Copyright (C) 2015 Petr Viktorin <[email protected]> +# Published under the GNU LGPLv3 or later + +import sys +import functools + +import tdb + + +class TdbTextWrapper(object): + """Text interface for a TDB file""" + + def __init__(self, tdb): + self._tdb = tdb + + @property + def raw(self): + return self._tdb + + def get(self, key): + key = key.encode('utf-8') + result = self._tdb.get(key) + if result is not None: + return result.decode('utf-8') + + def append(self, key, value): + key = key.encode('utf-8') + value = value.encode('utf-8') + self._tdb.append(key, value) + + def firstkey(self): + result = self._tdb.firstkey() + if result: + return result.decode('utf-8') + + def nextkey(self, key): + key = key.encode('utf-8') + result = self._tdb.nextkey(key) + if result is not None: + return result.decode('utf-8') + + def delete(self, key): + key = key.encode('utf-8') + self._tdb.delete(key) + + def store(self, key, value): + key = key.encode('utf-8') + value = value.encode('utf-8') + self._tdb.store(key, value) + + def __iter__(self): + for key in iter(self._tdb): + yield key.decode('utf-8') + + def __getitem__(self, key): + key = key.encode('utf-8') + result = self._tdb[key] + return result.decode('utf-8') + + def __contains__(self, key): + key = key.encode('utf-8') + return key in self._tdb + + def __repr__(self): + return '<TdbTextWrapper for %r>' % self._tdb + + def __setitem__(self, key, value): + key = key.encode('utf-8') + value = value.encode('utf-8') + self._tdb[key] = value + + def __delitem__(self, key): + key = key.encode('utf-8') + del self._tdb[key] + + if sys.version_info > (3, 0): + keys = __iter__ + else: + iterkeys = __iter__ + has_key = __contains__ + + +## Add wrappers for functions and getters that don't deal with text + +def _add_wrapper(name): + orig = getattr(tdb.Tdb, name) + + def wrapper(self, *args, **kwargs): + return orig(self._tdb, *args, **kwargs) + wrapper.__name__ = orig.__name__ + wrapper.__doc__ = orig.__doc__ + + setattr(TdbTextWrapper, name, wrapper) + +for name in ("transaction_cancel", + "transaction_commit", + "transaction_prepare_commit", + "transaction_start", + "reopen", + "lock_all", + "unlock_all", + "read_lock_all", + "read_unlock_all", + "close", + "add_flags", + "remove_flags", + "clear", + "repack", + "enable_seqnum", + "increment_seqnum_nonblock", + ): + _add_wrapper(name) + + +def _add_getter(name): + orig = getattr(tdb.Tdb, name) + doc = orig.__doc__ + + def getter(self): + return getattr(self._tdb, name) + + def setter(self, value): + return setattr(self._tdb, name, value) + + setattr(TdbTextWrapper, name, property(getter, setter, doc=doc)) + +for name in ("hash_size", + "map_size", + "freelist_size", + "flags", + "max_dead", + "filename", + "seqnum", + "text", + ): + _add_getter(name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/buildtools/wafsamba/samba_bundled.py new/tdb-1.3.7/buildtools/wafsamba/samba_bundled.py --- old/tdb-1.3.6/buildtools/wafsamba/samba_bundled.py 2014-12-22 09:17:09.000000000 +0100 +++ new/tdb-1.3.7/buildtools/wafsamba/samba_bundled.py 2015-07-21 22:32:32.000000000 +0200 @@ -190,7 +190,7 @@ pkg = libname # try pkgconfig first - if (conf.check_cfg(package=pkg, + if (conf.CHECK_CFG(package=pkg, args='"%s >= %s" --cflags --libs' % (pkg, minversion), msg=msg, uselib_store=uselib_store) and check_functions_headers_code()): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/buildtools/wafsamba/samba_deps.py new/tdb-1.3.7/buildtools/wafsamba/samba_deps.py --- old/tdb-1.3.6/buildtools/wafsamba/samba_deps.py 2014-11-29 11:30:57.000000000 +0100 +++ new/tdb-1.3.7/buildtools/wafsamba/samba_deps.py 2015-07-21 22:32:32.000000000 +0200 @@ -964,7 +964,8 @@ savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags', 'source', 'grouping_library', 'samba_ldflags', 'allow_undefined_symbols', 'use_global_deps', 'global_include' ] -savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags', 'ldflags', 'samba_deps_extended'] +savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', + 'ccflags', 'ldflags', 'samba_deps_extended', 'final_libs'] savedeps_outenv = ['INC_PATHS'] savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES', 'EXTRA_CFLAGS', 'EXTRA_LDFLAGS', 'EXTRA_INCLUDES' ] savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/buildtools/wafsamba/samba_python.py new/tdb-1.3.7/buildtools/wafsamba/samba_python.py --- old/tdb-1.3.6/buildtools/wafsamba/samba_python.py 2015-06-13 03:01:31.000000000 +0200 +++ new/tdb-1.3.7/buildtools/wafsamba/samba_python.py 2015-07-21 22:32:32.000000000 +0200 @@ -9,6 +9,10 @@ @conf def SAMBA_CHECK_PYTHON(conf, mandatory=True, version=(2,4,2)): # enable tool to build python extensions + if conf.env.HAVE_PYTHON_H: + conf.check_python_version(version) + return + interpreters = [] if conf.env['EXTRA_PYTHON']: @@ -21,7 +25,7 @@ try: conf.check_python_version((3, 3, 0)) except Exception: - warn('extra-python needs to be Python 3.3 or later') + Logs.warn('extra-python needs to be Python 3.3 or later') raise interpreters.append(conf.env['PYTHON']) conf.setenv('default') @@ -55,6 +59,10 @@ else: conf.msg("python headers", "using cache") + # we don't want PYTHONDIR in config.h, as otherwise changing + # --prefix causes a complete rebuild + del(conf.env.defines['PYTHONDIR']) + del(conf.env.defines['PYTHONARCHDIR']) def _check_python_headers(conf, mandatory): conf.check_python_headers(mandatory=mandatory) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/buildtools/wafsamba/wafsamba.py new/tdb-1.3.7/buildtools/wafsamba/wafsamba.py --- old/tdb-1.3.6/buildtools/wafsamba/wafsamba.py 2015-06-13 03:00:10.000000000 +0200 +++ new/tdb-1.3.7/buildtools/wafsamba/wafsamba.py 2015-07-21 22:32:32.000000000 +0200 @@ -242,6 +242,8 @@ bundled_extension, private_library) ldflags = TO_LIST(ldflags) + if bld.env['ENABLE_RELRO'] is True: + ldflags.extend(TO_LIST('-Wl,-z,relro,-z,now')) features = 'cc cshlib symlink_lib install_lib' if pyext: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/common/traverse.c new/tdb-1.3.7/common/traverse.c --- old/tdb-1.3.6/common/traverse.c 2014-10-01 11:22:21.000000000 +0200 +++ new/tdb-1.3.7/common/traverse.c 2015-07-21 22:32:32.000000000 +0200 @@ -245,13 +245,25 @@ tdb_traverse_func fn, void *private_data) { struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK }; + enum tdb_lock_flags lock_flags; int ret; if (tdb->read_only || tdb->traverse_read) { return tdb_traverse_read(tdb, fn, private_data); } - if (tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_WAIT)) { + lock_flags = TDB_LOCK_WAIT; + + if (tdb->allrecord_lock.count != 0) { + /* + * This avoids a deadlock between tdb_lockall() and + * tdb_traverse(). See + * https://bugzilla.samba.org/show_bug.cgi?id=11381 + */ + lock_flags = TDB_LOCK_NOWAIT; + } + + if (tdb_transaction_lock(tdb, F_WRLCK, lock_flags)) { return -1; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/lib/replace/replace.c new/tdb-1.3.7/lib/replace/replace.c --- old/tdb-1.3.6/lib/replace/replace.c 2015-04-29 11:20:16.000000000 +0200 +++ new/tdb-1.3.7/lib/replace/replace.c 2015-07-21 22:32:32.000000000 +0200 @@ -518,11 +518,10 @@ } #else #ifdef HAVE_BSD_STRTOLL -#ifdef HAVE_STRTOQ long long int rep_strtoll(const char *str, char **endptr, int base) { - long long int nb = strtoq(str, endptr, base); - /* In linux EINVAL is only returned if base is not ok */ + long long int nb = strtoll(str, endptr, base); + /* With glibc EINVAL is only returned if base is not ok */ if (errno == EINVAL) { if (base == 0 || (base >1 && base <37)) { /* Base was ok so it's because we were not @@ -534,9 +533,6 @@ } return nb; } -#else -#error "You need the strtoq function" -#endif /* HAVE_STRTOQ */ #endif /* HAVE_BSD_STRTOLL */ #endif /* HAVE_STRTOLL */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/pytdb.c new/tdb-1.3.7/pytdb.c --- old/tdb-1.3.6/pytdb.c 2014-09-16 20:04:31.000000000 +0200 +++ new/tdb-1.3.7/pytdb.c 2015-07-21 22:32:32.000000000 +0200 @@ -31,13 +31,25 @@ /* Include tdb headers */ #include <tdb.h> +#if PY_MAJOR_VERSION >= 3 +#define PyStr_FromString PyUnicode_FromString +#define PyStr_FromFormat PyUnicode_FromFormat +#define PyInt_FromLong PyLong_FromLong +#define PyInt_Check PyLong_Check +#define PyInt_AsLong PyLong_AsLong +#define Py_TPFLAGS_HAVE_ITER 0 +#else +#define PyStr_FromString PyString_FromString +#define PyStr_FromFormat PyString_FromFormat +#endif + typedef struct { PyObject_HEAD TDB_CONTEXT *ctx; bool closed; } PyTdbObject; -staticforward PyTypeObject PyTdb; +static PyTypeObject PyTdb; static void PyErr_SetTDBError(TDB_CONTEXT *tdb) { @@ -45,21 +57,21 @@ Py_BuildValue("(i,s)", tdb_error(tdb), tdb_errorstr(tdb))); } -static TDB_DATA PyString_AsTDB_DATA(PyObject *data) +static TDB_DATA PyBytes_AsTDB_DATA(PyObject *data) { TDB_DATA ret; - ret.dptr = (unsigned char *)PyString_AsString(data); - ret.dsize = PyString_Size(data); + ret.dptr = (unsigned char *)PyBytes_AsString(data); + ret.dsize = PyBytes_Size(data); return ret; } -static PyObject *PyString_FromTDB_DATA(TDB_DATA data) +static PyObject *PyBytes_FromTDB_DATA(TDB_DATA data) { if (data.dptr == NULL && data.dsize == 0) { Py_RETURN_NONE; } else { - PyObject *ret = PyString_FromStringAndSize((const char *)data.dptr, - data.dsize); + PyObject *ret = PyBytes_FromStringAndSize((const char *)data.dptr, + data.dsize); free(data.dptr); return ret; } @@ -233,11 +245,11 @@ if (!PyArg_ParseTuple(args, "O", &py_key)) return NULL; - key = PyString_AsTDB_DATA(py_key); + key = PyBytes_AsTDB_DATA(py_key); if (!key.dptr) return NULL; - return PyString_FromTDB_DATA(tdb_fetch(self->ctx, key)); + return PyBytes_FromTDB_DATA(tdb_fetch(self->ctx, key)); } static PyObject *obj_append(PyTdbObject *self, PyObject *args) @@ -251,10 +263,10 @@ if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data)) return NULL; - key = PyString_AsTDB_DATA(py_key); + key = PyBytes_AsTDB_DATA(py_key); if (!key.dptr) return NULL; - data = PyString_AsTDB_DATA(py_data); + data = PyBytes_AsTDB_DATA(py_data); if (!data.dptr) return NULL; @@ -267,7 +279,7 @@ { PyErr_TDB_RAISE_IF_CLOSED(self); - return PyString_FromTDB_DATA(tdb_firstkey(self->ctx)); + return PyBytes_FromTDB_DATA(tdb_firstkey(self->ctx)); } static PyObject *obj_nextkey(PyTdbObject *self, PyObject *args) @@ -279,11 +291,11 @@ if (!PyArg_ParseTuple(args, "O", &py_key)) return NULL; - key = PyString_AsTDB_DATA(py_key); + key = PyBytes_AsTDB_DATA(py_key); if (!key.dptr) return NULL; - return PyString_FromTDB_DATA(tdb_nextkey(self->ctx, key)); + return PyBytes_FromTDB_DATA(tdb_nextkey(self->ctx, key)); } static PyObject *obj_delete(PyTdbObject *self, PyObject *args) @@ -296,7 +308,7 @@ if (!PyArg_ParseTuple(args, "O", &py_key)) return NULL; - key = PyString_AsTDB_DATA(py_key); + key = PyBytes_AsTDB_DATA(py_key); if (!key.dptr) return NULL; ret = tdb_delete(self->ctx, key); @@ -304,26 +316,42 @@ Py_RETURN_NONE; } -static PyObject *obj_has_key(PyTdbObject *self, PyObject *args) +static int obj_contains(PyTdbObject *self, PyObject *py_key) { TDB_DATA key; int ret; + PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self); + + key = PyBytes_AsTDB_DATA(py_key); + if (!key.dptr) { + PyErr_BadArgument(); + return -1; + } + ret = tdb_exists(self->ctx, key); + if (ret) + return 1; + return 0; +} + +#if PY_MAJOR_VERSION < 3 +static PyObject *obj_has_key(PyTdbObject *self, PyObject *args) +{ + int ret; PyObject *py_key; PyErr_TDB_RAISE_IF_CLOSED(self); if (!PyArg_ParseTuple(args, "O", &py_key)) return NULL; - key = PyString_AsTDB_DATA(py_key); - if (!key.dptr) + ret = obj_contains(self, py_key); + if (ret == -1) return NULL; - ret = tdb_exists(self->ctx, key); - if (ret != TDB_ERR_NOEXIST) { - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - } + if (ret) + Py_RETURN_TRUE; + Py_RETURN_FALSE; - return (ret == TDB_ERR_NOEXIST)?Py_False:Py_True; } +#endif static PyObject *obj_store(PyTdbObject *self, PyObject *args) { @@ -337,10 +365,10 @@ if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag)) return NULL; - key = PyString_AsTDB_DATA(py_key); + key = PyBytes_AsTDB_DATA(py_key); if (!key.dptr) return NULL; - value = PyString_AsTDB_DATA(py_value); + value = PyBytes_AsTDB_DATA(py_value); if (!value.dptr) return NULL; @@ -389,7 +417,7 @@ return NULL; current = self->current; self->current = tdb_nextkey(self->iteratee->ctx, self->current); - ret = PyString_FromTDB_DATA(current); + ret = PyBytes_FromTDB_DATA(current); return ret; } @@ -480,17 +508,23 @@ "Append data to an existing key." }, { "firstkey", (PyCFunction)obj_firstkey, METH_NOARGS, "S.firstkey() -> data\n" "Return the first key in this database." }, - { "nextkey", (PyCFunction)obj_nextkey, METH_NOARGS, "S.nextkey(key) -> data\n" + { "nextkey", (PyCFunction)obj_nextkey, METH_VARARGS, "S.nextkey(key) -> data\n" "Return the next key in this database." }, { "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> None\n" "Delete an entry." }, +#if PY_MAJOR_VERSION < 3 { "has_key", (PyCFunction)obj_has_key, METH_VARARGS, "S.has_key(key) -> None\n" "Check whether key exists in this database." }, +#endif { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None" "Store data." }, { "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, "S.add_flags(flags) -> None" }, { "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, "S.remove_flags(flags) -> None" }, +#if PY_MAJOR_VERSION >= 3 + { "keys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" }, +#else { "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" }, +#endif { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n" "Wipe the entire database." }, { "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n" @@ -538,7 +572,7 @@ static PyObject *obj_get_filename(PyTdbObject *self, void *closure) { PyErr_TDB_RAISE_IF_CLOSED(self); - return PyString_FromString(tdb_name(self->ctx)); + return PyBytes_FromString(tdb_name(self->ctx)); } static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure) @@ -547,6 +581,22 @@ return PyInt_FromLong(tdb_get_seqnum(self->ctx)); } +static PyObject *obj_get_text(PyTdbObject *self, void *closure) +{ + PyObject *mod, *cls, *inst; + mod = PyImport_ImportModule("_tdb_text"); + if (mod == NULL) + return NULL; + cls = PyObject_GetAttrString(mod, "TdbTextWrapper"); + if (cls == NULL) { + Py_DECREF(mod); + return NULL; + } + inst = PyObject_CallFunction(cls, discard_const_p(char, "O"), self); + Py_DECREF(mod); + Py_DECREF(cls); + return inst; +} static PyGetSetDef tdb_object_getsetters[] = { { discard_const_p(char, "hash_size"), @@ -564,6 +614,8 @@ discard_const_p(char, "The filename of this TDB file.") }, { discard_const_p(char, "seqnum"), (getter)obj_get_seqnum, NULL, NULL }, + { discard_const_p(char, "text"), + (getter)obj_get_text, NULL, NULL }, { NULL } }; @@ -571,9 +623,9 @@ { PyErr_TDB_RAISE_IF_CLOSED(self); if (tdb_get_flags(self->ctx) & TDB_INTERNAL) { - return PyString_FromString("Tdb(<internal>)"); + return PyStr_FromString("Tdb(<internal>)"); } else { - return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx)); + return PyStr_FromFormat("Tdb('%s')", tdb_name(self->ctx)); } } @@ -581,27 +633,31 @@ { if (!self->closed) tdb_close(self->ctx); - self->ob_type->tp_free(self); + Py_TYPE(self)->tp_free(self); } static PyObject *obj_getitem(PyTdbObject *self, PyObject *key) { TDB_DATA tkey, val; PyErr_TDB_RAISE_IF_CLOSED(self); - if (!PyString_Check(key)) { - PyErr_SetString(PyExc_TypeError, "Expected string as key"); + if (!PyBytes_Check(key)) { + PyErr_SetString(PyExc_TypeError, "Expected bytestring as key"); return NULL; } - tkey.dptr = (unsigned char *)PyString_AsString(key); - tkey.dsize = PyString_Size(key); + tkey.dptr = (unsigned char *)PyBytes_AsString(key); + tkey.dsize = PyBytes_Size(key); val = tdb_fetch(self->ctx, tkey); if (val.dptr == NULL) { - PyErr_SetString(PyExc_KeyError, "No such TDB entry"); + /* + * if the key doesn't exist raise KeyError(key) to be + * consistent with python dict + */ + PyErr_SetObject(PyExc_KeyError, key); return NULL; } else { - return PyString_FromTDB_DATA(val); + return PyBytes_FromTDB_DATA(val); } } @@ -610,22 +666,22 @@ TDB_DATA tkey, tval; int ret; PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self); - if (!PyString_Check(key)) { - PyErr_SetString(PyExc_TypeError, "Expected string as key"); + if (!PyBytes_Check(key)) { + PyErr_SetString(PyExc_TypeError, "Expected bytestring as key"); return -1; } - tkey = PyString_AsTDB_DATA(key); + tkey = PyBytes_AsTDB_DATA(key); if (value == NULL) { ret = tdb_delete(self->ctx, tkey); } else { - if (!PyString_Check(value)) { + if (!PyBytes_Check(value)) { PyErr_SetString(PyExc_TypeError, "Expected string as value"); return -1; } - tval = PyString_AsTDB_DATA(value); + tval = PyBytes_AsTDB_DATA(value); ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE); } @@ -642,6 +698,9 @@ .mp_subscript = (binaryfunc)obj_getitem, .mp_ass_subscript = (objobjargproc)obj_setitem, }; +static PySequenceMethods tdb_object_seq = { + .sq_contains = (objobjproc)obj_contains, +}; static PyTypeObject PyTdb = { .tp_name = "tdb.Tdb", .tp_basicsize = sizeof(PyTdbObject), @@ -652,6 +711,7 @@ .tp_repr = (reprfunc)tdb_object_repr, .tp_dealloc = (destructor)tdb_object_dealloc, .tp_as_mapping = &tdb_object_mapping, + .tp_as_sequence = &tdb_object_seq, .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_ITER, .tp_iter = (getiterfunc)tdb_object_iter, }; @@ -662,46 +722,78 @@ { NULL } }; -void inittdb(void); -void inittdb(void) +#define MODULE_DOC "simple key-value database that supports multiple writers." + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + .m_name = "tdb", + .m_doc = MODULE_DOC, + .m_size = -1, + .m_methods = tdb_methods, +}; +#endif + +PyObject* module_init(void); +PyObject* module_init(void) { PyObject *m; if (PyType_Ready(&PyTdb) < 0) - return; + return NULL; if (PyType_Ready(&PyTdbIterator) < 0) - return; + return NULL; - m = Py_InitModule3("tdb", tdb_methods, - "simple key-value database that supports multiple writers."); +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule3("tdb", tdb_methods, MODULE_DOC); +#endif if (m == NULL) - return; + return NULL; - PyModule_AddObject(m, "REPLACE", PyInt_FromLong(TDB_REPLACE)); - PyModule_AddObject(m, "INSERT", PyInt_FromLong(TDB_INSERT)); - PyModule_AddObject(m, "MODIFY", PyInt_FromLong(TDB_MODIFY)); - - PyModule_AddObject(m, "DEFAULT", PyInt_FromLong(TDB_DEFAULT)); - PyModule_AddObject(m, "CLEAR_IF_FIRST", PyInt_FromLong(TDB_CLEAR_IF_FIRST)); - PyModule_AddObject(m, "INTERNAL", PyInt_FromLong(TDB_INTERNAL)); - PyModule_AddObject(m, "NOLOCK", PyInt_FromLong(TDB_NOLOCK)); - PyModule_AddObject(m, "NOMMAP", PyInt_FromLong(TDB_NOMMAP)); - PyModule_AddObject(m, "CONVERT", PyInt_FromLong(TDB_CONVERT)); - PyModule_AddObject(m, "BIGENDIAN", PyInt_FromLong(TDB_BIGENDIAN)); - PyModule_AddObject(m, "NOSYNC", PyInt_FromLong(TDB_NOSYNC)); - PyModule_AddObject(m, "SEQNUM", PyInt_FromLong(TDB_SEQNUM)); - PyModule_AddObject(m, "VOLATILE", PyInt_FromLong(TDB_VOLATILE)); - PyModule_AddObject(m, "ALLOW_NESTING", PyInt_FromLong(TDB_ALLOW_NESTING)); - PyModule_AddObject(m, "DISALLOW_NESTING", PyInt_FromLong(TDB_DISALLOW_NESTING)); - PyModule_AddObject(m, "INCOMPATIBLE_HASH", PyInt_FromLong(TDB_INCOMPATIBLE_HASH)); + PyModule_AddIntConstant(m, "REPLACE", TDB_REPLACE); + PyModule_AddIntConstant(m, "INSERT", TDB_INSERT); + PyModule_AddIntConstant(m, "MODIFY", TDB_MODIFY); + + PyModule_AddIntConstant(m, "DEFAULT", TDB_DEFAULT); + PyModule_AddIntConstant(m, "CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST); + PyModule_AddIntConstant(m, "INTERNAL", TDB_INTERNAL); + PyModule_AddIntConstant(m, "NOLOCK", TDB_NOLOCK); + PyModule_AddIntConstant(m, "NOMMAP", TDB_NOMMAP); + PyModule_AddIntConstant(m, "CONVERT", TDB_CONVERT); + PyModule_AddIntConstant(m, "BIGENDIAN", TDB_BIGENDIAN); + PyModule_AddIntConstant(m, "NOSYNC", TDB_NOSYNC); + PyModule_AddIntConstant(m, "SEQNUM", TDB_SEQNUM); + PyModule_AddIntConstant(m, "VOLATILE", TDB_VOLATILE); + PyModule_AddIntConstant(m, "ALLOW_NESTING", TDB_ALLOW_NESTING); + PyModule_AddIntConstant(m, "DISALLOW_NESTING", TDB_DISALLOW_NESTING); + PyModule_AddIntConstant(m, "INCOMPATIBLE_HASH", TDB_INCOMPATIBLE_HASH); - PyModule_AddObject(m, "__docformat__", PyString_FromString("restructuredText")); + PyModule_AddStringConstant(m, "__docformat__", "restructuredText"); - PyModule_AddObject(m, "__version__", PyString_FromString(PACKAGE_VERSION)); + PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION); Py_INCREF(&PyTdb); PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb); Py_INCREF(&PyTdbIterator); + + return m; +} + + +#if PY_MAJOR_VERSION >= 3 +PyMODINIT_FUNC PyInit_tdb(void); +PyMODINIT_FUNC PyInit_tdb(void) +{ + return module_init(); +} +#else +void inittdb(void); +void inittdb(void) +{ + module_init(); } +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/python/tests/simple.py new/tdb-1.3.7/python/tests/simple.py --- old/tdb-1.3.6/python/tests/simple.py 2014-09-16 20:04:31.000000000 +0200 +++ new/tdb-1.3.7/python/tests/simple.py 2015-07-21 22:32:32.000000000 +0200 @@ -6,9 +6,12 @@ # Copyright (C) 2007-2008 Jelmer Vernooij <[email protected]> # Published under the GNU LGPLv3 or later -import tdb +import sys +import os +import tempfile from unittest import TestCase -import os, tempfile + +import tdb class OpenTdbTests(TestCase): @@ -43,19 +46,18 @@ self.assertEquals(repr(self.tdb), "Tdb(<internal>)") -class SimpleTdbTests(TestCase): +class CommonTdbTests(TestCase): + """Tests common to both the text & bytes interfaces""" + + use_text = False def setUp(self): - super(SimpleTdbTests, self).setUp() + super(CommonTdbTests, self).setUp() self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT, os.O_CREAT|os.O_RDWR) self.assertNotEqual(None, self.tdb) - - def tearDown(self): - del self.tdb - - def test_repr(self): - self.assertTrue(repr(self.tdb).startswith("Tdb('")) + if self.use_text: + self.tdb = self.tdb.text def test_lockall(self): self.tdb.lock_all() @@ -74,27 +76,6 @@ def test_reopen(self): self.tdb.reopen() - def test_store(self): - self.tdb.store("bar", "bla") - self.assertEquals("bla", self.tdb.get("bar")) - - def test_getitem(self): - self.tdb["bar"] = "foo" - self.tdb.reopen() - self.assertEquals("foo", self.tdb["bar"]) - - def test_delete(self): - self.tdb["bar"] = "foo" - del self.tdb["bar"] - self.assertRaises(KeyError, lambda: self.tdb["bar"]) - - def test_contains(self): - self.tdb["bla"] = "bloe" - self.assertTrue("bla" in self.tdb) - - def test_keyerror(self): - self.assertRaises(KeyError, lambda: self.tdb["bla"]) - def test_hash_size(self): self.tdb.hash_size @@ -107,52 +88,101 @@ def test_name(self): self.tdb.filename + def test_add_flags(self): + self.tdb.add_flags(tdb.NOMMAP) + self.tdb.remove_flags(tdb.NOMMAP) + + +class TextCommonTdbTests(CommonTdbTests): + + use_text = True + + +class SimpleTdbTests(TestCase): + + def setUp(self): + super(SimpleTdbTests, self).setUp() + self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT, + os.O_CREAT|os.O_RDWR) + self.assertNotEqual(None, self.tdb) + + def test_repr(self): + self.assertTrue(repr(self.tdb).startswith("Tdb('")) + + def test_store(self): + self.tdb.store(b"bar", b"bla") + self.assertEquals(b"bla", self.tdb.get(b"bar")) + + def test_getitem(self): + self.tdb[b"bar"] = b"foo" + self.tdb.reopen() + self.assertEquals(b"foo", self.tdb[b"bar"]) + + def test_delete(self): + self.tdb[b"bar"] = b"foo" + del self.tdb[b"bar"] + self.assertRaises(KeyError, lambda: self.tdb[b"bar"]) + + def test_contains(self): + self.tdb[b"bla"] = b"bloe" + self.assertTrue(b"bla" in self.tdb) + self.assertFalse(b"qwertyuiop" in self.tdb) + if sys.version_info < (3, 0): + self.assertTrue(self.tdb.has_key(b"bla")) + self.assertFalse(self.tdb.has_key(b"qwertyuiop")) + + def test_keyerror(self): + self.assertRaises(KeyError, lambda: self.tdb[b"bla"]) + def test_iterator(self): - self.tdb["bla"] = "1" - self.tdb["brainslug"] = "2" + self.tdb[b"bla"] = b"1" + self.tdb[b"brainslug"] = b"2" l = list(self.tdb) l.sort() - self.assertEquals(["bla", "brainslug"], l) + self.assertEquals([b"bla", b"brainslug"], l) def test_transaction_cancel(self): - self.tdb["bloe"] = "2" + self.tdb[b"bloe"] = b"2" self.tdb.transaction_start() - self.tdb["bloe"] = "1" + self.tdb[b"bloe"] = b"1" self.tdb.transaction_cancel() - self.assertEquals("2", self.tdb["bloe"]) + self.assertEquals(b"2", self.tdb[b"bloe"]) def test_transaction_commit(self): - self.tdb["bloe"] = "2" + self.tdb[b"bloe"] = b"2" self.tdb.transaction_start() - self.tdb["bloe"] = "1" + self.tdb[b"bloe"] = b"1" self.tdb.transaction_commit() - self.assertEquals("1", self.tdb["bloe"]) + self.assertEquals(b"1", self.tdb[b"bloe"]) def test_transaction_prepare_commit(self): - self.tdb["bloe"] = "2" + self.tdb[b"bloe"] = b"2" self.tdb.transaction_start() - self.tdb["bloe"] = "1" + self.tdb[b"bloe"] = b"1" self.tdb.transaction_prepare_commit() self.tdb.transaction_commit() - self.assertEquals("1", self.tdb["bloe"]) + self.assertEquals(b"1", self.tdb[b"bloe"]) def test_iterkeys(self): - self.tdb["bloe"] = "2" - self.tdb["bla"] = "25" - i = self.tdb.iterkeys() - self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()])) + self.tdb[b"bloe"] = b"2" + self.tdb[b"bla"] = b"25" + if sys.version_info >= (3, 0): + i = self.tdb.keys() + else: + i = self.tdb.iterkeys() + self.assertEquals(set([b"bloe", b"bla"]), set([next(i), next(i)])) def test_clear(self): - self.tdb["bloe"] = "2" - self.tdb["bla"] = "25" + self.tdb[b"bloe"] = b"2" + self.tdb[b"bla"] = b"25" self.assertEquals(2, len(list(self.tdb))) self.tdb.clear() self.assertEquals(0, len(list(self.tdb))) def test_repack(self): - self.tdb["foo"] = "abc" - self.tdb["bar"] = "def" - del self.tdb["foo"] + self.tdb[b"foo"] = b"abc" + self.tdb[b"bar"] = b"def" + del self.tdb[b"foo"] self.tdb.repack() def test_seqnum(self): @@ -164,12 +194,110 @@ def test_len(self): self.assertEquals(0, len(list(self.tdb))) - self.tdb["entry"] = "value" + self.tdb[b"entry"] = b"value" self.assertEquals(1, len(list(self.tdb))) - def test_add_flags(self): - self.tdb.add_flags(tdb.NOMMAP) - self.tdb.remove_flags(tdb.NOMMAP) + +class TdbTextTests(TestCase): + + def setUp(self): + super(TdbTextTests, self).setUp() + self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT, + os.O_CREAT|os.O_RDWR) + self.assertNotEqual(None, self.tdb) + + def test_repr(self): + self.assertTrue(repr(self.tdb).startswith("Tdb('")) + + def test_store(self): + self.tdb.text.store("bar", "bla") + self.assertEquals("bla", self.tdb.text.get("bar")) + + def test_getitem(self): + self.tdb.text["bar"] = "foo" + self.tdb.reopen() + self.assertEquals("foo", self.tdb.text["bar"]) + + def test_delete(self): + self.tdb.text["bar"] = "foo" + del self.tdb.text["bar"] + self.assertRaises(KeyError, lambda: self.tdb.text["bar"]) + + def test_contains(self): + self.tdb.text["bla"] = "bloe" + self.assertTrue("bla" in self.tdb.text) + self.assertFalse("qwertyuiop" in self.tdb.text) + if sys.version_info < (3, 0): + self.assertTrue(self.tdb.text.has_key("bla")) + self.assertFalse(self.tdb.text.has_key("qwertyuiop")) + + def test_keyerror(self): + self.assertRaises(KeyError, lambda: self.tdb.text["bla"]) + + def test_iterator(self): + self.tdb.text["bla"] = "1" + self.tdb.text["brainslug"] = "2" + l = list(self.tdb.text) + l.sort() + self.assertEquals(["bla", "brainslug"], l) + + def test_transaction_cancel(self): + self.tdb.text["bloe"] = "2" + self.tdb.transaction_start() + self.tdb.text["bloe"] = "1" + self.tdb.transaction_cancel() + self.assertEquals("2", self.tdb.text["bloe"]) + + def test_transaction_commit(self): + self.tdb.text["bloe"] = "2" + self.tdb.transaction_start() + self.tdb.text["bloe"] = "1" + self.tdb.transaction_commit() + self.assertEquals("1", self.tdb.text["bloe"]) + + def test_transaction_prepare_commit(self): + self.tdb.text["bloe"] = "2" + self.tdb.transaction_start() + self.tdb.text["bloe"] = "1" + self.tdb.transaction_prepare_commit() + self.tdb.transaction_commit() + self.assertEquals("1", self.tdb.text["bloe"]) + + def test_iterkeys(self): + self.tdb.text["bloe"] = "2" + self.tdb.text["bla"] = "25" + if sys.version_info >= (3, 0): + i = self.tdb.text.keys() + else: + i = self.tdb.text.iterkeys() + self.assertEquals(set(["bloe", "bla"]), set([next(i), next(i)])) + + def test_clear(self): + self.tdb.text["bloe"] = "2" + self.tdb.text["bla"] = "25" + self.assertEquals(2, len(list(self.tdb))) + self.tdb.clear() + self.assertEquals(0, len(list(self.tdb))) + + def test_repack(self): + self.tdb.text["foo"] = "abc" + self.tdb.text["bar"] = "def" + del self.tdb.text["foo"] + self.tdb.repack() + + def test_len(self): + self.assertEquals(0, len(list(self.tdb.text))) + self.tdb.text["entry"] = "value" + self.assertEquals(1, len(list(self.tdb.text))) + + def test_text_and_binary(self): + text = u'\xfa\u0148\xef\xe7\xf8\xf0\xea' + bytestr = text.encode('utf-8') + self.tdb[b"entry"] = bytestr + self.tdb.text[u"entry2"] = text + self.assertEquals(self.tdb.text["entry"], text) + self.assertEquals(self.tdb[b"entry2"], bytestr) + assert self.tdb.text.raw == self.tdb class VersionTests(TestCase): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/test/run-allrecord-traverse-deadlock.c new/tdb-1.3.7/test/run-allrecord-traverse-deadlock.c --- old/tdb-1.3.6/test/run-allrecord-traverse-deadlock.c 1970-01-01 01:00:00.000000000 +0100 +++ new/tdb-1.3.7/test/run-allrecord-traverse-deadlock.c 2015-07-21 22:32:32.000000000 +0200 @@ -0,0 +1,203 @@ +#include "../common/tdb_private.h" +#include "../common/io.c" +#include "../common/tdb.c" +#include "../common/lock.c" +#include "../common/freelist.c" +#include "../common/traverse.c" +#include "../common/transaction.c" +#include "../common/error.c" +#include "../common/open.c" +#include "../common/check.c" +#include "../common/hash.c" +#include "../common/mutex.c" +#include "tap-interface.h" +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdarg.h> +#include "logging.h" + +static void do_allrecord_lock(const char *name, int tdb_flags, int up, + int down) +{ + struct tdb_context *tdb; + int ret; + ssize_t nread, nwritten; + char c = 0; + + tdb = tdb_open_ex(name, 3, tdb_flags, + O_RDWR|O_CREAT, 0755, &taplogctx, NULL); + ok(tdb, "tdb_open_ex should succeed"); + + ret = tdb_lockall(tdb); + ok(ret == 0, "tdb_lockall should succeed"); + + nwritten = write(up, &c, sizeof(c)); + ok(nwritten == sizeof(c), "write should succeed"); + + nread = read(down, &c, sizeof(c)); + ok(nread == sizeof(c), "read should succeed"); + + ret = tdb_traverse(tdb, NULL, NULL); + ok(ret == -1, "do_allrecord_lock: traverse should fail"); + + nwritten = write(up, &c, sizeof(c)); + ok(nwritten == sizeof(c), "write should succeed"); + + exit(0); +} + +static void do_traverse(const char *name, int tdb_flags, int up, int down) +{ + struct tdb_context *tdb; + int ret; + ssize_t nread, nwritten; + char c = 0; + + tdb = tdb_open_ex(name, 3, tdb_flags, + O_RDWR|O_CREAT, 0755, &taplogctx, NULL); + ok(tdb, "tdb_open_ex should succeed"); + + ret = tdb_traverse(tdb, NULL, NULL); + ok(ret == 1, "do_traverse: tdb_traverse should return 1 record"); + + nwritten = write(up, &c, sizeof(c)); + ok(nwritten == sizeof(c), "write should succeed"); + + nread = read(down, &c, sizeof(c)); + ok(nread == sizeof(c), "read should succeed"); + + exit(0); +} + +/* + * Process 1: get the allrecord_lock on a tdb. + * Process 2: start a traverse, this will stall waiting for the + * first chainlock: That is taken by the allrecord_lock + * Process 1: start a traverse: This will get EDEADLK in trying to + * get the TRANSACTION_LOCK. It will deadlock for mutexes, + * which don't have built-in deadlock detection. + */ + +static int do_tests(const char *name, int tdb_flags) +{ + struct tdb_context *tdb; + int ret; + pid_t traverse_child, allrecord_child; + int traverse_down[2]; + int traverse_up[2]; + int allrecord_down[2]; + int allrecord_up[2]; + char c; + ssize_t nread, nwritten; + TDB_DATA key, data; + + key.dsize = strlen("hi"); + key.dptr = discard_const_p(uint8_t, "hi"); + data.dsize = strlen("world"); + data.dptr = discard_const_p(uint8_t, "world"); + + tdb = tdb_open_ex(name, 3, tdb_flags, + O_RDWR|O_CREAT, 0755, &taplogctx, NULL); + ok(tdb, "tdb_open_ex should succeed"); + + ret = tdb_store(tdb, key, data, TDB_INSERT); + ok(ret == 0, "tdb_store should succeed"); + + ret = pipe(traverse_down); + ok(ret == 0, "pipe should succeed"); + + ret = pipe(traverse_up); + ok(ret == 0, "pipe should succeed"); + + ret = pipe(allrecord_down); + ok(ret == 0, "pipe should succeed"); + + ret = pipe(allrecord_up); + ok(ret == 0, "pipe should succeed"); + + allrecord_child = fork(); + ok(allrecord_child != -1, "fork should succeed"); + + if (allrecord_child == 0) { + tdb_close(tdb); + close(traverse_up[0]); + close(traverse_up[1]); + close(traverse_down[0]); + close(traverse_down[1]); + close(allrecord_up[0]); + close(allrecord_down[1]); + do_allrecord_lock(name, tdb_flags, + allrecord_up[1], allrecord_down[0]); + exit(0); + } + close(allrecord_up[1]); + close(allrecord_down[0]); + + nread = read(allrecord_up[0], &c, sizeof(c)); + ok(nread == sizeof(c), "read should succeed"); + + traverse_child = fork(); + ok(traverse_child != -1, "fork should succeed"); + + if (traverse_child == 0) { + tdb_close(tdb); + close(traverse_up[0]); + close(traverse_down[1]); + close(allrecord_up[0]); + close(allrecord_down[1]); + do_traverse(name, tdb_flags, + traverse_up[1], traverse_down[0]); + exit(0); + } + close(traverse_up[1]); + close(traverse_down[0]); + + poll(NULL, 0, 1000); + + nwritten = write(allrecord_down[1], &c, sizeof(c)); + ok(nwritten == sizeof(c), "write should succeed"); + + nread = read(traverse_up[0], &c, sizeof(c)); + ok(nread == sizeof(c), "read should succeed"); + + nwritten = write(traverse_down[1], &c, sizeof(c)); + ok(nwritten == sizeof(c), "write should succeed"); + + nread = read(allrecord_up[0], &c, sizeof(c)); + ok(nread == sizeof(c), "ret should succeed"); + + close(traverse_up[0]); + close(traverse_down[1]); + close(allrecord_up[0]); + close(allrecord_down[1]); + diag("%s tests done", name); + return exit_status(); +} + +int main(int argc, char *argv[]) +{ + int ret; + bool mutex_support; + + mutex_support = tdb_runtime_check_for_robust_mutexes(); + + ret = do_tests("marklock-deadlock-fcntl.tdb", + TDB_CLEAR_IF_FIRST | + TDB_INCOMPATIBLE_HASH); + ok(ret == 0, "marklock-deadlock-fcntl.tdb tests should succeed"); + + if (!mutex_support) { + skip(1, "No robust mutex support, " + "skipping marklock-deadlock-mutex.tdb tests"); + return exit_status(); + } + + ret = do_tests("marklock-deadlock-mutex.tdb", + TDB_CLEAR_IF_FIRST | + TDB_MUTEX_LOCKING | + TDB_INCOMPATIBLE_HASH); + ok(ret == 0, "marklock-deadlock-mutex.tdb tests should succeed"); + + return exit_status(); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/tools/tdbrestore.c new/tdb-1.3.7/tools/tdbrestore.c --- old/tdb-1.3.6/tools/tdbrestore.c 2014-09-16 20:04:31.000000000 +0200 +++ new/tdb-1.3.7/tools/tdbrestore.c 2015-07-21 22:32:32.000000000 +0200 @@ -17,8 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <assert.h> #include "replace.h" +#include <assert.h> #include "system/locale.h" #include "system/time.h" #include "system/filesys.h" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tdb-1.3.6/wscript new/tdb-1.3.7/wscript --- old/tdb-1.3.6/wscript 2015-06-13 03:01:31.000000000 +0200 +++ new/tdb-1.3.7/wscript 2015-07-21 22:35:18.000000000 +0200 @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'tdb' -VERSION = '1.3.6' +VERSION = '1.3.7' blddir = 'bin' @@ -41,6 +41,7 @@ 'run-wronghash-fail', 'run-zero-append', 'run-marklock-deadlock', + 'run-allrecord-traverse-deadlock', 'run-mutex-openflags2', 'run-mutex-trylock', 'run-mutex-allrecord-bench', @@ -95,8 +96,7 @@ if not conf.env.disable_python: # also disable if we don't have the python libs installed - conf.find_program('python', var='PYTHON') - conf.check_tool('python') + conf.SAMBA_CHECK_PYTHON(mandatory=False) conf.check_python_version((2,4,2)) conf.SAMBA_CHECK_PYTHON_HEADERS(mandatory=False) if not conf.env.HAVE_PYTHON_H: @@ -179,12 +179,20 @@ includes='include', install=False) if not bld.CONFIG_SET('USING_SYSTEM_PYTDB'): - bld.SAMBA_PYTHON('pytdb', - 'pytdb.c', - deps='tdb', - enabled=not bld.env.disable_python, - realname='tdb.so', - cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION) + for env in bld.gen_python_environments(['PKGCONFIGDIR']): + bld.SAMBA_PYTHON('pytdb', + 'pytdb.c', + deps='tdb', + enabled=not bld.env.disable_python, + realname='tdb.so', + cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION) + + for env in bld.gen_python_environments(['PKGCONFIGDIR']): + bld.SAMBA_SCRIPT('_tdb_text.py', + pattern='_tdb_text.py', + installdir='python') + + bld.INSTALL_FILES('${PYTHONARCHDIR}', '_tdb_text.py') def testonly(ctx): '''run tdb testsuite''' @@ -224,7 +232,10 @@ print("testsuite returned %d" % ret) if ret != 0: ecode = ret - sys.exit(ecode) + + pyret = samba_utils.RUN_PYTHON_TESTS(['python/tests/simple.py']) + print("python testsuite returned %d" % pyret) + sys.exit(ecode or pyret) # WAF doesn't build the unit tests for this, maybe because they don't link with tdb? # This forces it
