From 83c8af688f54638724c38972d99e62b306165369 Mon Sep 17 00:00:00 2001 From: dmalcolm Date: Dec 18 2009 03:20:50 +0000 Subject: - automatically disable arena allocator when run under valgrind (upstream issue 2422; patch 52) - add patch from Josh Boyer containing diff against upstream PyBSDDB to make the bsddb module compile against db-4.8 (patch 53, #544275); bump the necessary version of db4-devel to 4.8 - patch setup.py so that it searches for db-4.8, and enable debug output for said search; make Setup.dist use db-4.8 (patch 54) --- diff --git a/disable-pymalloc-on-valgrind-py26.patch b/disable-pymalloc-on-valgrind-py26.patch new file mode 100644 index 0000000..de56bdc --- /dev/null +++ b/disable-pymalloc-on-valgrind-py26.patch @@ -0,0 +1,135 @@ +Index: configure.in +=================================================================== +--- configure.in (revision 61828) ++++ configure.in (working copy) +@@ -2232,6 +2232,19 @@ then + fi + AC_MSG_RESULT($with_pymalloc) + ++# Check for Valgrind support ++AC_MSG_CHECKING([for --with-valgrind]) ++AC_ARG_WITH([valgrind], ++ AC_HELP_STRING([--with-valgrind], [Enable Valgrind support]),, ++ with_valgrind=no) ++AC_MSG_RESULT([$with_valgrind]) ++if test "$with_valgrind" != no; then ++ AC_CHECK_HEADER([valgrind/valgrind.h], ++ [AC_DEFINE([WITH_VALGRIND], 1, [Define if you want pymalloc to be disabled when running under valgrind])], ++ [AC_MSG_ERROR([Valgrind support requested but headers not available])] ++ ) ++fi ++ + # Check for --with-wctype-functions + AC_MSG_CHECKING(for --with-wctype-functions) + AC_ARG_WITH(wctype-functions, +Index: Objects/obmalloc.c +=================================================================== +--- Objects/obmalloc.c (revision 61828) ++++ Objects/obmalloc.c (working copy) +@@ -2,6 +2,21 @@ + + #ifdef WITH_PYMALLOC + ++#ifdef WITH_VALGRIND ++#include ++ ++/* If we're using GCC, use __builtin_expect() to reduce overhead of ++ the valgrind checks */ ++#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) ++# define UNLIKELY(value) __builtin_expect((value), 0) ++#else ++# define UNLIKELY(value) (value) ++#endif ++ ++/* -1 indicates that we haven't checked that we're running on valgrind yet. */ ++static int running_on_valgrind = -1; ++#endif ++ + /* An object allocator for Python. + + Here is an introduction to the layers of the Python memory architecture, +@@ -726,6 +741,13 @@ PyObject_Malloc(size_t nbytes) + poolp next; + uint size; + ++#ifdef WITH_VALGRIND ++ if (UNLIKELY(running_on_valgrind == -1)) ++ running_on_valgrind = RUNNING_ON_VALGRIND; ++ if (UNLIKELY(running_on_valgrind)) ++ goto redirect; ++#endif ++ + /* + * This implicitly redirects malloc(0). + */ +@@ -916,6 +938,11 @@ PyObject_Free(void *p) + if (p == NULL) /* free(NULL) has no effect */ + return; + ++#ifdef WITH_VALGRIND ++ if (UNLIKELY(running_on_valgrind > 0)) ++ goto redirect; ++#endif ++ + pool = POOL_ADDR(p); + if (Py_ADDRESS_IN_RANGE(p, pool)) { + /* We allocated this address. */ +@@ -1110,6 +1137,7 @@ PyObject_Free(void *p) + return; + } + ++redirect: + /* We didn't allocate this address. */ + free(p); + } +@@ -1130,6 +1158,12 @@ PyObject_Realloc(void *p, size_t nbytes) + if (p == NULL) + return PyObject_Malloc(nbytes); + ++#ifdef WITH_VALGRIND ++ /* Treat running_on_valgrind == -1 the same as 0 */ ++ if (UNLIKELY(running_on_valgrind > 0)) ++ goto redirect; ++#endif ++ + pool = POOL_ADDR(p); + if (Py_ADDRESS_IN_RANGE(p, pool)) { + /* We're in charge of this block */ +@@ -1157,6 +1191,7 @@ PyObject_Realloc(void *p, size_t nbytes) + } + return bp; + } ++ redirect: + /* We're not managing this block. If nbytes <= + * SMALL_REQUEST_THRESHOLD, it's tempting to try to take over this + * block. However, if we do, we need to copy the valid data from +Index: Misc/NEWS +=================================================================== +--- Misc/NEWS (revision 61828) ++++ Misc/NEWS (working copy) +@@ -60,6 +60,11 @@ Core and builtins + + - Issue #2143: Fix embedded readline() hang on SSL socket EOF. + ++- Issue #2422: When compiled with the ``--with-valgrind`` option, the ++ pymalloc allocator will be automatically disabled when running under ++ Valgrind. This gives improved memory leak detection when running ++ under Valgrind, while taking advantage of pymalloc at other times. ++ + Library + ------- + +Index: pyconfig.h.in +=================================================================== +--- pyconfig.h.in (revision 61828) ++++ pyconfig.h.in (working copy) +@@ -958,6 +958,9 @@ + /* Define to profile with the Pentium timestamp counter */ + #undef WITH_TSC + ++/* Define if you want pymalloc to be disabled when running under valgrind */ ++#undef WITH_VALGRIND ++ + + /* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). diff --git a/python-2.6-update-bsddb3-4.8.patch b/python-2.6-update-bsddb3-4.8.patch new file mode 100644 index 0000000..ec1898f --- /dev/null +++ b/python-2.6-update-bsddb3-4.8.patch @@ -0,0 +1,3446 @@ +diff -Nupr Python-2.6.4.orig/Lib/bsddb/dbobj.py Python-2.6.4/Lib/bsddb/dbobj.py +--- Python-2.6.4.orig/Lib/bsddb/dbobj.py 2008-07-23 07:38:42.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/dbobj.py 2009-12-04 07:36:00.000000000 -0500 +@@ -110,15 +110,17 @@ class DBEnv: + def log_stat(self, *args, **kwargs): + return apply(self._cobj.log_stat, args, kwargs) + +- if db.version() >= (4,1): +- def dbremove(self, *args, **kwargs): +- return apply(self._cobj.dbremove, args, kwargs) +- def dbrename(self, *args, **kwargs): +- return apply(self._cobj.dbrename, args, kwargs) +- def set_encrypt(self, *args, **kwargs): +- return apply(self._cobj.set_encrypt, args, kwargs) ++ def dbremove(self, *args, **kwargs): ++ return apply(self._cobj.dbremove, args, kwargs) ++ def dbrename(self, *args, **kwargs): ++ return apply(self._cobj.dbrename, args, kwargs) ++ def set_encrypt(self, *args, **kwargs): ++ return apply(self._cobj.set_encrypt, args, kwargs) + + if db.version() >= (4,4): ++ def fileid_reset(self, *args, **kwargs): ++ return self._cobj.fileid_reset(*args, **kwargs) ++ + def lsn_reset(self, *args, **kwargs): + return apply(self._cobj.lsn_reset, args, kwargs) + +@@ -229,9 +231,8 @@ class DB(MutableMapping): + def set_get_returns_none(self, *args, **kwargs): + return apply(self._cobj.set_get_returns_none, args, kwargs) + +- if db.version() >= (4,1): +- def set_encrypt(self, *args, **kwargs): +- return apply(self._cobj.set_encrypt, args, kwargs) ++ def set_encrypt(self, *args, **kwargs): ++ return apply(self._cobj.set_encrypt, args, kwargs) + + + class DBSequence: +diff -Nupr Python-2.6.4.orig/Lib/bsddb/dbtables.py Python-2.6.4/Lib/bsddb/dbtables.py +--- Python-2.6.4.orig/Lib/bsddb/dbtables.py 2008-08-31 10:00:51.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/dbtables.py 2009-12-04 07:36:00.000000000 -0500 +@@ -15,7 +15,7 @@ + # This provides a simple database table interface built on top of + # the Python Berkeley DB 3 interface. + # +-_cvsid = '$Id: python-2.6-update-bsddb3-4.8.patch,v 1.1 2009/12/18 03:20:50 dmalcolm Exp $' ++_cvsid = '$Id: python-2.6-update-bsddb3-4.8.patch,v 1.1 2009/12/18 03:20:50 dmalcolm Exp $' + + import re + import sys +@@ -659,6 +659,13 @@ class bsdTableDB : + a = atuple[1] + b = btuple[1] + if type(a) is type(b): ++ ++ # Needed for python 3. "cmp" vanished in 3.0.1 ++ def cmp(a, b) : ++ if a==b : return 0 ++ if a= 3) + +-if sys.py3kwarning: +- import warnings +- warnings.warnpy3k("in 3.x, bsddb has been removed; " +- "please use the pybsddb project instead", +- DeprecationWarning, 2) +- + try: + if __name__ == 'bsddb3': + # import _pybsddb binary as it should be the more recent version from +@@ -442,8 +436,10 @@ def _checkflag(flag, file): + # Berkeley DB was too. + + try: +- import thread +- del thread ++ # 2to3 automatically changes "import thread" to "import _thread" ++ import thread as T ++ del T ++ + except ImportError: + db.DB_THREAD = 0 + +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_all.py Python-2.6.4/Lib/bsddb/test/test_all.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_all.py 2008-09-03 18:07:11.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_all.py 2009-12-04 07:36:00.000000000 -0500 +@@ -203,6 +203,16 @@ if sys.version_info[0] >= 3 : + k = bytes(k, charset) + return self._db.has_key(k, txn=txn) + ++ def set_re_delim(self, c) : ++ if isinstance(c, str) : # We can use a numeric value byte too ++ c = bytes(c, charset) ++ return self._db.set_re_delim(c) ++ ++ def set_re_pad(self, c) : ++ if isinstance(c, str) : # We can use a numeric value byte too ++ c = bytes(c, charset) ++ return self._db.set_re_pad(c) ++ + def put(self, key, value, txn=None, flags=0, dlen=-1, doff=-1) : + if isinstance(key, str) : + key = bytes(key, charset) +@@ -221,6 +231,11 @@ if sys.version_info[0] >= 3 : + key = bytes(key, charset) + return self._db.get_size(key) + ++ def exists(self, key, *args, **kwargs) : ++ if isinstance(key, str) : ++ key = bytes(key, charset) ++ return self._db.exists(key, *args, **kwargs) ++ + def get(self, key, default="MagicCookie", txn=None, flags=0, dlen=-1, doff=-1) : + if isinstance(key, str) : + key = bytes(key, charset) +@@ -288,13 +303,21 @@ if sys.version_info[0] >= 3 : + key = key.decode(charset) + data = data.decode(charset) + key = self._callback(key, data) +- if (key != bsddb._db.DB_DONOTINDEX) and isinstance(key, +- str) : +- key = bytes(key, charset) ++ if (key != bsddb._db.DB_DONOTINDEX) : ++ if isinstance(key, str) : ++ key = bytes(key, charset) ++ elif isinstance(key, list) : ++ key2 = [] ++ for i in key : ++ if isinstance(i, str) : ++ i = bytes(i, charset) ++ key2.append(i) ++ key = key2 + return key + + return self._db.associate(secondarydb._db, +- associate_callback(callback).callback, flags=flags, txn=txn) ++ associate_callback(callback).callback, flags=flags, ++ txn=txn) + + def cursor(self, txn=None, flags=0) : + return cursor_py3k(self._db, txn=txn, flags=flags) +@@ -310,6 +333,12 @@ if sys.version_info[0] >= 3 : + def __getattr__(self, v) : + return getattr(self._dbenv, v) + ++ def get_data_dirs(self) : ++ # Have to use a list comprehension and not ++ # generators, because we are supporting Python 2.3. ++ return tuple( ++ [i.decode(charset) for i in self._dbenv.get_data_dirs()]) ++ + class DBSequence_py3k(object) : + def __init__(self, db, *args, **kwargs) : + self._db=db +@@ -332,7 +361,10 @@ if sys.version_info[0] >= 3 : + + bsddb._db.DBEnv_orig = bsddb._db.DBEnv + bsddb._db.DB_orig = bsddb._db.DB +- bsddb._db.DBSequence_orig = bsddb._db.DBSequence ++ if bsddb.db.version() <= (4, 3) : ++ bsddb._db.DBSequence_orig = None ++ else : ++ bsddb._db.DBSequence_orig = bsddb._db.DBSequence + + def do_proxy_db_py3k(flag) : + flag2 = do_proxy_db_py3k.flag +@@ -481,6 +513,7 @@ def suite(module_prefix='', timing_check + test_modules = [ + 'test_associate', + 'test_basics', ++ 'test_dbenv', + 'test_compare', + 'test_compat', + 'test_cursor_pget_bug', +@@ -489,6 +522,7 @@ def suite(module_prefix='', timing_check + 'test_dbtables', + 'test_distributed_transactions', + 'test_early_close', ++ 'test_fileid', + 'test_get_none', + 'test_join', + 'test_lock', +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_associate.py Python-2.6.4/Lib/bsddb/test/test_associate.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_associate.py 2008-08-31 10:00:51.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_associate.py 2009-12-04 07:36:00.000000000 -0500 +@@ -148,12 +148,8 @@ class AssociateTestCase(unittest.TestCas + self.secDB = None + self.primary = db.DB(self.env) + self.primary.set_get_returns_none(2) +- if db.version() >= (4, 1): +- self.primary.open(self.filename, "primary", self.dbtype, +- db.DB_CREATE | db.DB_THREAD | self.dbFlags, txn=txn) +- else: +- self.primary.open(self.filename, "primary", self.dbtype, +- db.DB_CREATE | db.DB_THREAD | self.dbFlags) ++ self.primary.open(self.filename, "primary", self.dbtype, ++ db.DB_CREATE | db.DB_THREAD | self.dbFlags, txn=txn) + + def closeDB(self): + if self.cur: +@@ -169,12 +165,7 @@ class AssociateTestCase(unittest.TestCas + return self.primary + + +- def test01_associateWithDB(self): +- if verbose: +- print '\n', '-=' * 30 +- print "Running %s.test01_associateWithDB..." % \ +- self.__class__.__name__ +- ++ def _associateWithDB(self, getGenre): + self.createDB() + + self.secDB = db.DB(self.env) +@@ -182,19 +173,21 @@ class AssociateTestCase(unittest.TestCas + self.secDB.set_get_returns_none(2) + self.secDB.open(self.filename, "secondary", db.DB_BTREE, + db.DB_CREATE | db.DB_THREAD | self.dbFlags) +- self.getDB().associate(self.secDB, self.getGenre) ++ self.getDB().associate(self.secDB, getGenre) + + self.addDataToDB(self.getDB()) + + self.finish_test(self.secDB) + +- +- def test02_associateAfterDB(self): ++ def test01_associateWithDB(self): + if verbose: + print '\n', '-=' * 30 +- print "Running %s.test02_associateAfterDB..." % \ ++ print "Running %s.test01_associateWithDB..." % \ + self.__class__.__name__ + ++ return self._associateWithDB(self.getGenre) ++ ++ def _associateAfterDB(self, getGenre) : + self.createDB() + self.addDataToDB(self.getDB()) + +@@ -204,10 +197,35 @@ class AssociateTestCase(unittest.TestCas + db.DB_CREATE | db.DB_THREAD | self.dbFlags) + + # adding the DB_CREATE flag will cause it to index existing records +- self.getDB().associate(self.secDB, self.getGenre, db.DB_CREATE) ++ self.getDB().associate(self.secDB, getGenre, db.DB_CREATE) + + self.finish_test(self.secDB) + ++ def test02_associateAfterDB(self): ++ if verbose: ++ print '\n', '-=' * 30 ++ print "Running %s.test02_associateAfterDB..." % \ ++ self.__class__.__name__ ++ ++ return self._associateAfterDB(self.getGenre) ++ ++ if db.version() >= (4, 6): ++ def test03_associateWithDB(self): ++ if verbose: ++ print '\n', '-=' * 30 ++ print "Running %s.test03_associateWithDB..." % \ ++ self.__class__.__name__ ++ ++ return self._associateWithDB(self.getGenreList) ++ ++ def test04_associateAfterDB(self): ++ if verbose: ++ print '\n', '-=' * 30 ++ print "Running %s.test04_associateAfterDB..." % \ ++ self.__class__.__name__ ++ ++ return self._associateAfterDB(self.getGenreList) ++ + + def finish_test(self, secDB, txn=None): + # 'Blues' should not be in the secondary database +@@ -277,6 +295,12 @@ class AssociateTestCase(unittest.TestCas + else: + return genre + ++ def getGenreList(self, priKey, PriData) : ++ v = self.getGenre(priKey, PriData) ++ if type(v) == type("") : ++ v = [v] ++ return v ++ + + #---------------------------------------------------------------------- + +@@ -322,10 +346,7 @@ class AssociateBTreeTxnTestCase(Associat + self.secDB.set_get_returns_none(2) + self.secDB.open(self.filename, "secondary", db.DB_BTREE, + db.DB_CREATE | db.DB_THREAD, txn=txn) +- if db.version() >= (4,1): +- self.getDB().associate(self.secDB, self.getGenre, txn=txn) +- else: +- self.getDB().associate(self.secDB, self.getGenre) ++ self.getDB().associate(self.secDB, self.getGenre, txn=txn) + + self.addDataToDB(self.getDB(), txn=txn) + except: +@@ -426,8 +447,7 @@ def test_suite(): + suite.addTest(unittest.makeSuite(AssociateBTreeTestCase)) + suite.addTest(unittest.makeSuite(AssociateRecnoTestCase)) + +- if db.version() >= (4, 1): +- suite.addTest(unittest.makeSuite(AssociateBTreeTxnTestCase)) ++ suite.addTest(unittest.makeSuite(AssociateBTreeTxnTestCase)) + + suite.addTest(unittest.makeSuite(ShelveAssociateHashTestCase)) + suite.addTest(unittest.makeSuite(ShelveAssociateBTreeTestCase)) +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_basics.py Python-2.6.4/Lib/bsddb/test/test_basics.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_basics.py 2009-07-02 11:37:21.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_basics.py 2009-12-04 07:36:00.000000000 -0500 +@@ -33,6 +33,7 @@ class VersionTestCase(unittest.TestCase) + + class BasicTestCase(unittest.TestCase): + dbtype = db.DB_UNKNOWN # must be set in derived class ++ cachesize = (0, 1024*1024, 1) + dbopenflags = 0 + dbsetflags = 0 + dbmode = 0660 +@@ -43,6 +44,13 @@ class BasicTestCase(unittest.TestCase): + + _numKeys = 1002 # PRIVATE. NOTE: must be an even value + ++ import sys ++ if sys.version_info[:3] < (2, 4, 0): ++ def assertTrue(self, expr, msg=None): ++ self.failUnless(expr,msg=msg) ++ def assertFalse(self, expr, msg=None): ++ self.failIf(expr,msg=msg) ++ + def setUp(self): + if self.useEnv: + self.homeDir=get_new_environment_path() +@@ -50,7 +58,8 @@ class BasicTestCase(unittest.TestCase): + self.env = db.DBEnv() + self.env.set_lg_max(1024*1024) + self.env.set_tx_max(30) +- self.env.set_tx_timestamp(int(time.time())) ++ self._t = int(time.time()) ++ self.env.set_tx_timestamp(self._t) + self.env.set_flags(self.envsetflags, 1) + self.env.open(self.homeDir, self.envflags | db.DB_CREATE) + self.filename = "test" +@@ -64,6 +73,15 @@ class BasicTestCase(unittest.TestCase): + + # create and open the DB + self.d = db.DB(self.env) ++ if not self.useEnv : ++ if db.version() >= (4, 2) : ++ self.d.set_cachesize(*self.cachesize) ++ cachesize = self.d.get_cachesize() ++ self.assertEqual(cachesize[0], self.cachesize[0]) ++ self.assertEqual(cachesize[2], self.cachesize[2]) ++ # Berkeley DB expands the cache 25% accounting overhead, ++ # if the cache is small. ++ self.assertEqual(125, int(100.0*cachesize[1]/self.cachesize[1])) + self.d.set_flags(self.dbsetflags) + if self.dbname: + self.d.open(self.filename, self.dbname, self.dbtype, +@@ -74,6 +92,10 @@ class BasicTestCase(unittest.TestCase): + dbtype = self.dbtype, + flags = self.dbopenflags|db.DB_CREATE) + ++ if not self.useEnv: ++ self.assertRaises(db.DBInvalidArgError, ++ self.d.set_cachesize, *self.cachesize) ++ + self.populateDB() + + +@@ -131,7 +153,7 @@ class BasicTestCase(unittest.TestCase): + + self.assertEqual(d.get('0321'), '0321-0321-0321-0321-0321') + +- # By default non-existent keys return None... ++ # By default non-existant keys return None... + self.assertEqual(d.get('abcd'), None) + + # ...but they raise exceptions in other situations. Call +@@ -276,6 +298,21 @@ class BasicTestCase(unittest.TestCase): + pprint(values[:10]) + + ++ #---------------------------------------- ++ ++ def test02b_SequenceMethods(self): ++ d = self.d ++ ++ for key in ['0002', '0101', '0401', '0701', '0998']: ++ data = d[key] ++ self.assertEqual(data, self.makeData(key)) ++ if verbose: ++ print data ++ ++ self.assertTrue(hasattr(d, "__contains__")) ++ self.assertTrue("0401" in d) ++ self.assertFalse("1234" in d) ++ + + #---------------------------------------- + +@@ -509,6 +546,15 @@ class BasicTestCase(unittest.TestCase): + self.assertEqual(old, 1) + self.test03_SimpleCursorStuff(get_raises_error=0, set_raises_error=0) + ++ if db.version() >= (4, 6): ++ def test03d_SimpleCursorPriority(self) : ++ c = self.d.cursor() ++ c.set_priority(db.DB_PRIORITY_VERY_LOW) # Positional ++ self.assertEqual(db.DB_PRIORITY_VERY_LOW, c.get_priority()) ++ c.set_priority(priority=db.DB_PRIORITY_HIGH) # Keyword ++ self.assertEqual(db.DB_PRIORITY_HIGH, c.get_priority()) ++ c.close() ++ + #---------------------------------------- + + def test04_PartialGetAndPut(self): +@@ -562,7 +608,7 @@ class BasicTestCase(unittest.TestCase): + d = self.d + if verbose: + print '\n', '-=' * 30 +- print "Running %s.test99_Truncate..." % self.__class__.__name__ ++ print "Running %s.test06_Truncate..." % self.__class__.__name__ + + d.put("abcde", "ABCDE"); + num = d.truncate() +@@ -582,6 +628,33 @@ class BasicTestCase(unittest.TestCase): + + #---------------------------------------- + ++ if db.version() >= (4, 6): ++ def test08_exists(self) : ++ self.d.put("abcde", "ABCDE") ++ self.assert_(self.d.exists("abcde") == True, ++ "DB->exists() returns wrong value") ++ self.assert_(self.d.exists("x") == False, ++ "DB->exists() returns wrong value") ++ ++ #---------------------------------------- ++ ++ if db.version() >= (4, 7): ++ def test_compact(self) : ++ d = self.d ++ self.assertEqual(0, d.compact(flags=db.DB_FREELIST_ONLY)) ++ self.assertEqual(0, d.compact(flags=db.DB_FREELIST_ONLY)) ++ d.put("abcde", "ABCDE"); ++ d.put("bcde", "BCDE"); ++ d.put("abc", "ABC"); ++ d.put("monty", "python"); ++ d.delete("abc") ++ d.delete("bcde") ++ d.compact(start='abcde', stop='monty', txn=None, ++ compact_fillpercent=42, compact_pages=1, ++ compact_timeout=50000000, ++ flags=db.DB_FREELIST_ONLY|db.DB_FREE_SPACE) ++ ++ #---------------------------------------- + + #---------------------------------------------------------------------- + +@@ -611,13 +684,13 @@ class BasicWithEnvTestCase(BasicTestCase + + #---------------------------------------- + +- def test08_EnvRemoveAndRename(self): ++ def test09_EnvRemoveAndRename(self): + if not self.env: + return + + if verbose: + print '\n', '-=' * 30 +- print "Running %s.test08_EnvRemoveAndRename..." % self.__class__.__name__ ++ print "Running %s.test09_EnvRemoveAndRename..." % self.__class__.__name__ + + # can't rename or remove an open DB + self.d.close() +@@ -626,10 +699,6 @@ class BasicWithEnvTestCase(BasicTestCase + self.env.dbrename(self.filename, None, newname) + self.env.dbremove(newname) + +- # dbremove and dbrename are in 4.1 and later +- if db.version() < (4,1): +- del test08_EnvRemoveAndRename +- + #---------------------------------------- + + class BasicBTreeWithEnvTestCase(BasicWithEnvTestCase): +@@ -729,11 +798,25 @@ class BasicTransactionTestCase(BasicTest + + #---------------------------------------- + +- def test08_TxnTruncate(self): ++ if db.version() >= (4, 6): ++ def test08_exists(self) : ++ txn = self.env.txn_begin() ++ self.d.put("abcde", "ABCDE", txn=txn) ++ txn.commit() ++ txn = self.env.txn_begin() ++ self.assert_(self.d.exists("abcde", txn=txn) == True, ++ "DB->exists() returns wrong value") ++ self.assert_(self.d.exists("x", txn=txn) == False, ++ "DB->exists() returns wrong value") ++ txn.abort() ++ ++ #---------------------------------------- ++ ++ def test09_TxnTruncate(self): + d = self.d + if verbose: + print '\n', '-=' * 30 +- print "Running %s.test08_TxnTruncate..." % self.__class__.__name__ ++ print "Running %s.test09_TxnTruncate..." % self.__class__.__name__ + + d.put("abcde", "ABCDE"); + txn = self.env.txn_begin() +@@ -746,7 +829,7 @@ class BasicTransactionTestCase(BasicTest + + #---------------------------------------- + +- def test09_TxnLateUse(self): ++ def test10_TxnLateUse(self): + txn = self.env.txn_begin() + txn.abort() + try: +@@ -766,6 +849,39 @@ class BasicTransactionTestCase(BasicTest + raise RuntimeError, "DBTxn.commit() called after DB_TXN no longer valid w/o an exception" + + ++ #---------------------------------------- ++ ++ ++ if db.version() >= (4, 4): ++ def test_txn_name(self) : ++ txn=self.env.txn_begin() ++ self.assertEqual(txn.get_name(), "") ++ txn.set_name("XXYY") ++ self.assertEqual(txn.get_name(), "XXYY") ++ txn.set_name("") ++ self.assertEqual(txn.get_name(), "") ++ txn.abort() ++ ++ #---------------------------------------- ++ ++ ++ def test_txn_set_timeout(self) : ++ txn=self.env.txn_begin() ++ txn.set_timeout(1234567, db.DB_SET_LOCK_TIMEOUT) ++ txn.set_timeout(2345678, flags=db.DB_SET_TXN_TIMEOUT) ++ txn.abort() ++ ++ #---------------------------------------- ++ ++ if db.version() >= (4, 2) : ++ def test_get_tx_max(self) : ++ self.assertEqual(self.env.get_tx_max(), 30) ++ ++ def test_get_tx_timestamp(self) : ++ self.assertEqual(self.env.get_tx_timestamp(), self._t) ++ ++ ++ + class BTreeTransactionTestCase(BasicTransactionTestCase): + dbtype = db.DB_BTREE + +@@ -780,11 +896,11 @@ class BTreeRecnoTestCase(BasicTestCase): + dbtype = db.DB_BTREE + dbsetflags = db.DB_RECNUM + +- def test08_RecnoInBTree(self): ++ def test09_RecnoInBTree(self): + d = self.d + if verbose: + print '\n', '-=' * 30 +- print "Running %s.test08_RecnoInBTree..." % self.__class__.__name__ ++ print "Running %s.test09_RecnoInBTree..." % self.__class__.__name__ + + rec = d.get(200) + self.assertEqual(type(rec), type(())) +@@ -814,11 +930,11 @@ class BTreeRecnoWithThreadFlagTestCase(B + class BasicDUPTestCase(BasicTestCase): + dbsetflags = db.DB_DUP + +- def test09_DuplicateKeys(self): ++ def test10_DuplicateKeys(self): + d = self.d + if verbose: + print '\n', '-=' * 30 +- print "Running %s.test09_DuplicateKeys..." % \ ++ print "Running %s.test10_DuplicateKeys..." % \ + self.__class__.__name__ + + d.put("dup0", "before") +@@ -887,11 +1003,11 @@ class BasicMultiDBTestCase(BasicTestCase + else: + return db.DB_BTREE + +- def test10_MultiDB(self): ++ def test11_MultiDB(self): + d1 = self.d + if verbose: + print '\n', '-=' * 30 +- print "Running %s.test10_MultiDB..." % self.__class__.__name__ ++ print "Running %s.test11_MultiDB..." % self.__class__.__name__ + + d2 = db.DB(self.env) + d2.open(self.filename, "second", self.dbtype, +@@ -1032,11 +1148,12 @@ class CrashAndBurn(unittest.TestCase) : + # # See http://bugs.python.org/issue3307 + # self.assertRaises(db.DBInvalidArgError, db.DB, None, 65535) + +- def test02_DBEnv_dealloc(self): +- # http://bugs.python.org/issue3885 +- import gc +- self.assertRaises(db.DBInvalidArgError, db.DBEnv, ~db.DB_RPCCLIENT) +- gc.collect() ++ if db.version() < (4, 8) : ++ def test02_DBEnv_dealloc(self): ++ # http://bugs.python.org/issue3885 ++ import gc ++ self.assertRaises(db.DBInvalidArgError, db.DBEnv, ~db.DB_RPCCLIENT) ++ gc.collect() + + + #---------------------------------------------------------------------- +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_compare.py Python-2.6.4/Lib/bsddb/test/test_compare.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_compare.py 2008-08-31 10:00:51.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_compare.py 2009-12-04 07:36:00.000000000 -0500 +@@ -12,6 +12,12 @@ from test_all import db, dbshelve, test_ + get_new_environment_path, get_new_database_path + + ++# Needed for python 3. "cmp" vanished in 3.0.1 ++def cmp(a, b) : ++ if a==b : return 0 ++ if a= (4, 2) : ++ def test_setget_data_dirs(self) : ++ dirs = ("a", "b", "c", "d") ++ for i in dirs : ++ self.env.set_data_dir(i) ++ self.assertEqual(dirs, self.env.get_data_dirs()) ++ ++ def test_setget_cachesize(self) : ++ cachesize = (0, 512*1024*1024, 3) ++ self.env.set_cachesize(*cachesize) ++ self.assertEqual(cachesize, self.env.get_cachesize()) ++ ++ cachesize = (0, 1*1024*1024, 5) ++ self.env.set_cachesize(*cachesize) ++ cachesize2 = self.env.get_cachesize() ++ self.assertEqual(cachesize[0], cachesize2[0]) ++ self.assertEqual(cachesize[2], cachesize2[2]) ++ # Berkeley DB expands the cache 25% accounting overhead, ++ # if the cache is small. ++ self.assertEqual(125, int(100.0*cachesize2[1]/cachesize[1])) ++ ++ # You can not change configuration after opening ++ # the environment. ++ self.env.open(self.homeDir, db.DB_CREATE | db.DB_INIT_MPOOL) ++ cachesize = (0, 2*1024*1024, 1) ++ self.assertRaises(db.DBInvalidArgError, ++ self.env.set_cachesize, *cachesize) ++ self.assertEqual(cachesize2, self.env.get_cachesize()) ++ ++ def test_set_cachesize_dbenv_db(self) : ++ # You can not configure the cachesize using ++ # the database handle, if you are using an environment. ++ d = db.DB(self.env) ++ self.assertRaises(db.DBInvalidArgError, ++ d.set_cachesize, 0, 1024*1024, 1) ++ ++ def test_setget_shm_key(self) : ++ shm_key=137 ++ self.env.set_shm_key(shm_key) ++ self.assertEqual(shm_key, self.env.get_shm_key()) ++ self.env.set_shm_key(shm_key+1) ++ self.assertEqual(shm_key+1, self.env.get_shm_key()) ++ ++ # You can not change configuration after opening ++ # the environment. ++ self.env.open(self.homeDir, db.DB_CREATE | db.DB_INIT_MPOOL) ++ # If we try to reconfigure cache after opening the ++ # environment, core dump. ++ self.assertRaises(db.DBInvalidArgError, ++ self.env.set_shm_key, shm_key) ++ self.assertEqual(shm_key+1, self.env.get_shm_key()) ++ ++ if db.version() >= (4, 4) : ++ def test_mutex_setget_max(self) : ++ v = self.env.mutex_get_max() ++ v2 = v*2+1 ++ ++ self.env.mutex_set_max(v2) ++ self.assertEqual(v2, self.env.mutex_get_max()) ++ ++ self.env.mutex_set_max(v) ++ self.assertEqual(v, self.env.mutex_get_max()) ++ ++ # You can not change configuration after opening ++ # the environment. ++ self.env.open(self.homeDir, db.DB_CREATE) ++ self.assertRaises(db.DBInvalidArgError, ++ self.env.mutex_set_max, v2) ++ ++ def test_mutex_setget_increment(self) : ++ v = self.env.mutex_get_increment() ++ v2 = 127 ++ ++ self.env.mutex_set_increment(v2) ++ self.assertEqual(v2, self.env.mutex_get_increment()) ++ ++ self.env.mutex_set_increment(v) ++ self.assertEqual(v, self.env.mutex_get_increment()) ++ ++ # You can not change configuration after opening ++ # the environment. ++ self.env.open(self.homeDir, db.DB_CREATE) ++ self.assertRaises(db.DBInvalidArgError, ++ self.env.mutex_set_increment, v2) ++ ++ def test_mutex_setget_tas_spins(self) : ++ self.env.mutex_set_tas_spins(0) # Default = BDB decides ++ v = self.env.mutex_get_tas_spins() ++ v2 = v*2+1 ++ ++ self.env.mutex_set_tas_spins(v2) ++ self.assertEqual(v2, self.env.mutex_get_tas_spins()) ++ ++ self.env.mutex_set_tas_spins(v) ++ self.assertEqual(v, self.env.mutex_get_tas_spins()) ++ ++ # In this case, you can change configuration ++ # after opening the environment. ++ self.env.open(self.homeDir, db.DB_CREATE) ++ self.env.mutex_set_tas_spins(v2) ++ ++ def test_mutex_setget_align(self) : ++ v = self.env.mutex_get_align() ++ v2 = 64 ++ if v == 64 : ++ v2 = 128 ++ ++ self.env.mutex_set_align(v2) ++ self.assertEqual(v2, self.env.mutex_get_align()) ++ ++ # Requires a nonzero power of two ++ self.assertRaises(db.DBInvalidArgError, ++ self.env.mutex_set_align, 0) ++ self.assertRaises(db.DBInvalidArgError, ++ self.env.mutex_set_align, 17) ++ ++ self.env.mutex_set_align(2*v2) ++ self.assertEqual(2*v2, self.env.mutex_get_align()) ++ ++ # You can not change configuration after opening ++ # the environment. ++ self.env.open(self.homeDir, db.DB_CREATE) ++ self.assertRaises(db.DBInvalidArgError, ++ self.env.mutex_set_align, v2) ++ ++ ++def test_suite(): ++ return unittest.makeSuite(DBEnv) ++ ++if __name__ == '__main__': ++ unittest.main(defaultTest='test_suite') +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_dbtables.py Python-2.6.4/Lib/bsddb/test/test_dbtables.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_dbtables.py 2008-08-31 10:00:51.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_dbtables.py 2009-12-04 07:36:00.000000000 -0500 +@@ -18,13 +18,17 @@ + # + # -- Gregory P. Smith + # +-# $Id: python-2.6-update-bsddb3-4.8.patch,v 1.1 2009/12/18 03:20:50 dmalcolm Exp $ ++# $Id: python-2.6-update-bsddb3-4.8.patch,v 1.1 2009/12/18 03:20:50 dmalcolm Exp $ + +-import os, re +-try: +- import cPickle +- pickle = cPickle +-except ImportError: ++import os, re, sys ++ ++if sys.version_info[0] < 3 : ++ try: ++ import cPickle ++ pickle = cPickle ++ except ImportError: ++ import pickle ++else : + import pickle + + import unittest +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_distributed_transactions.py Python-2.6.4/Lib/bsddb/test/test_distributed_transactions.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_distributed_transactions.py 2008-08-31 10:00:51.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_distributed_transactions.py 2009-12-04 07:36:00.000000000 -0500 +@@ -35,9 +35,9 @@ class DBTxn_distributed(unittest.TestCas + db.DB_INIT_TXN | db.DB_INIT_LOG | db.DB_INIT_MPOOL | + db.DB_INIT_LOCK, 0666) + self.db = db.DB(self.dbenv) +- self.db.set_re_len(db.DB_XIDDATASIZE) ++ self.db.set_re_len(db.DB_GID_SIZE) + if must_open_db : +- if db.version() > (4,1) : ++ if db.version() >= (4,2) : + txn=self.dbenv.txn_begin() + self.db.open(self.filename, + db.DB_QUEUE, db.DB_CREATE | db.DB_THREAD, 0666, +@@ -76,7 +76,7 @@ class DBTxn_distributed(unittest.TestCas + # let them be garbage collected. + for i in xrange(self.num_txns) : + txn = self.dbenv.txn_begin() +- gid = "%%%dd" %db.DB_XIDDATASIZE ++ gid = "%%%dd" %db.DB_GID_SIZE + gid = adapt(gid %i) + self.db.put(i, gid, txn=txn, flags=db.DB_APPEND) + txns.add(gid) +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_early_close.py Python-2.6.4/Lib/bsddb/test/test_early_close.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_early_close.py 2008-09-08 20:49:16.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_early_close.py 2009-12-04 07:36:00.000000000 -0500 +@@ -155,11 +155,8 @@ class DBEnvClosedEarlyCrash(unittest.Tes + db.DB_INIT_LOG | db.DB_CREATE) + d = db.DB(dbenv) + txn = dbenv.txn_begin() +- if db.version() < (4,1) : +- d.open(self.filename, dbtype = db.DB_HASH, flags = db.DB_CREATE) +- else : +- d.open(self.filename, dbtype = db.DB_HASH, flags = db.DB_CREATE, +- txn=txn) ++ d.open(self.filename, dbtype = db.DB_HASH, flags = db.DB_CREATE, ++ txn=txn) + d.put("XXX", "yyy", txn=txn) + txn.commit() + txn = dbenv.txn_begin() +@@ -168,9 +165,9 @@ class DBEnvClosedEarlyCrash(unittest.Tes + self.assertEquals(("XXX", "yyy"), c1.first()) + import warnings + # Not interested in warnings about implicit close. +- with warnings.catch_warnings(): +- warnings.simplefilter("ignore") +- txn.commit() ++ warnings.simplefilter("ignore") ++ txn.commit() ++ warnings.resetwarnings() + self.assertRaises(db.DBCursorClosedError, c2.first) + + if db.version() > (4,3,0) : +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_fileid.py Python-2.6.4/Lib/bsddb/test/test_fileid.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_fileid.py 1969-12-31 19:00:00.000000000 -0500 ++++ Python-2.6.4/Lib/bsddb/test/test_fileid.py 2009-12-04 07:36:00.000000000 -0500 +@@ -0,0 +1,63 @@ ++"""TestCase for reseting File ID. ++""" ++ ++import os ++import shutil ++import unittest ++ ++from test_all import db, test_support, get_new_environment_path, get_new_database_path ++ ++class FileidResetTestCase(unittest.TestCase): ++ def setUp(self): ++ self.db_path_1 = get_new_database_path() ++ self.db_path_2 = get_new_database_path() ++ self.db_env_path = get_new_environment_path() ++ ++ def test_fileid_reset(self): ++ # create DB 1 ++ self.db1 = db.DB() ++ self.db1.open(self.db_path_1, dbtype=db.DB_HASH, flags=(db.DB_CREATE|db.DB_EXCL)) ++ self.db1.put('spam', 'eggs') ++ self.db1.close() ++ ++ shutil.copy(self.db_path_1, self.db_path_2) ++ ++ self.db2 = db.DB() ++ self.db2.open(self.db_path_2, dbtype=db.DB_HASH) ++ self.db2.put('spam', 'spam') ++ self.db2.close() ++ ++ self.db_env = db.DBEnv() ++ self.db_env.open(self.db_env_path, db.DB_CREATE|db.DB_INIT_MPOOL) ++ ++ # use fileid_reset() here ++ self.db_env.fileid_reset(self.db_path_2) ++ ++ self.db1 = db.DB(self.db_env) ++ self.db1.open(self.db_path_1, dbtype=db.DB_HASH, flags=db.DB_RDONLY) ++ self.assertEquals(self.db1.get('spam'), 'eggs') ++ ++ self.db2 = db.DB(self.db_env) ++ self.db2.open(self.db_path_2, dbtype=db.DB_HASH, flags=db.DB_RDONLY) ++ self.assertEquals(self.db2.get('spam'), 'spam') ++ ++ self.db1.close() ++ self.db2.close() ++ ++ self.db_env.close() ++ ++ def tearDown(self): ++ test_support.unlink(self.db_path_1) ++ test_support.unlink(self.db_path_2) ++ test_support.rmtree(self.db_env_path) ++ ++def test_suite(): ++ suite = unittest.TestSuite() ++ if db.version() >= (4, 4): ++ suite.addTest(unittest.makeSuite(FileidResetTestCase)) ++ return suite ++ ++if __name__ == '__main__': ++ unittest.main(defaultTest='test_suite') ++ ++ +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_lock.py Python-2.6.4/Lib/bsddb/test/test_lock.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_lock.py 2009-01-26 16:53:32.000000000 -0500 ++++ Python-2.6.4/Lib/bsddb/test/test_lock.py 2009-12-04 07:36:00.000000000 -0500 +@@ -89,7 +89,18 @@ class LockingTestCase(unittest.TestCase) + for t in threads: + t.join() + +- def test03_lock_timeout(self): ++ if db.version() >= (4, 2) : ++ def test03_lock_timeout(self): ++ self.env.set_timeout(0, db.DB_SET_LOCK_TIMEOUT) ++ self.assertEqual(self.env.get_timeout(db.DB_SET_LOCK_TIMEOUT), 0) ++ self.env.set_timeout(0, db.DB_SET_TXN_TIMEOUT) ++ self.assertEqual(self.env.get_timeout(db.DB_SET_TXN_TIMEOUT), 0) ++ self.env.set_timeout(123456, db.DB_SET_LOCK_TIMEOUT) ++ self.assertEqual(self.env.get_timeout(db.DB_SET_LOCK_TIMEOUT), 123456) ++ self.env.set_timeout(7890123, db.DB_SET_TXN_TIMEOUT) ++ self.assertEqual(self.env.get_timeout(db.DB_SET_TXN_TIMEOUT), 7890123) ++ ++ def test04_lock_timeout2(self): + self.env.set_timeout(0, db.DB_SET_LOCK_TIMEOUT) + self.env.set_timeout(0, db.DB_SET_TXN_TIMEOUT) + self.env.set_timeout(123456, db.DB_SET_LOCK_TIMEOUT) +@@ -124,7 +135,7 @@ class LockingTestCase(unittest.TestCase) + self.env.lock_get,anID2, "shared lock", db.DB_LOCK_READ) + end_time=time.time() + deadlock_detection.end=True +- self.assertTrue((end_time-start_time) >= 0.0999) ++ self.assertTrue((end_time-start_time) >= 0.1) + self.env.lock_put(lock) + t.join() + +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_pickle.py Python-2.6.4/Lib/bsddb/test/test_pickle.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_pickle.py 2008-08-31 10:00:51.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_pickle.py 2009-12-04 07:36:00.000000000 -0500 +@@ -1,10 +1,16 @@ + + import os + import pickle +-try: +- import cPickle +-except ImportError: ++import sys ++ ++if sys.version_info[0] < 3 : ++ try: ++ import cPickle ++ except ImportError: ++ cPickle = None ++else : + cPickle = None ++ + import unittest + + from test_all import db, test_support, get_new_environment_path, get_new_database_path +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_recno.py Python-2.6.4/Lib/bsddb/test/test_recno.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_recno.py 2009-07-02 11:37:21.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_recno.py 2009-12-04 07:36:00.000000000 -0500 +@@ -150,7 +150,7 @@ class SimpleRecnoTestCase(unittest.TestC + if verbose: + print rec + +- # test that non-existent key lookups work (and that ++ # test that non-existant key lookups work (and that + # DBC_set_range doesn't have a memleak under valgrind) + rec = c.set_range(999999) + self.assertEqual(rec, None) +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_replication.py Python-2.6.4/Lib/bsddb/test/test_replication.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_replication.py 2008-09-17 22:47:35.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_replication.py 2009-12-04 07:36:00.000000000 -0500 +@@ -119,19 +119,7 @@ class DBReplicationManager(unittest.Test + timeout = time.time()+10 + while (time.time()> sys.stderr, \ +- "XXX - windows bsddb replication fails on windows and is skipped" +- print >> sys.stderr, "XXX - Please see issue #3892" +- else: +- self.assertTrue(time.time()= (4,7) : ++ def test04_test_clockskew(self) : ++ fast, slow = 1234, 1230 ++ self.dbenvMaster.rep_set_clockskew(fast, slow) ++ self.assertEqual((fast, slow), ++ self.dbenvMaster.rep_get_clockskew()) ++ self.basic_rep_threading() ++ + #---------------------------------------------------------------------- + + def test_suite(): +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test/test_sequence.py Python-2.6.4/Lib/bsddb/test/test_sequence.py +--- Python-2.6.4.orig/Lib/bsddb/test/test_sequence.py 2008-08-31 10:00:51.000000000 -0400 ++++ Python-2.6.4/Lib/bsddb/test/test_sequence.py 2009-12-04 07:36:00.000000000 -0500 +@@ -37,7 +37,7 @@ class DBSequenceTest(unittest.TestCase): + self.seq = db.DBSequence(self.d, flags=0) + start_value = 10 * self.int_32_max + self.assertEqual(0xA00000000, start_value) +- self.assertEquals(None, self.seq.init_value(start_value)) ++ self.assertEquals(None, self.seq.initial_value(start_value)) + self.assertEquals(None, self.seq.open(key='id', txn=None, flags=db.DB_CREATE)) + self.assertEquals(start_value, self.seq.get(5)) + self.assertEquals(start_value + 5, self.seq.get()) +@@ -77,7 +77,7 @@ class DBSequenceTest(unittest.TestCase): + self.seq = db.DBSequence(self.d, flags=0) + seq_range = (10 * self.int_32_max, 11 * self.int_32_max - 1) + self.assertEquals(None, self.seq.set_range(seq_range)) +- self.seq.init_value(seq_range[0]) ++ self.seq.initial_value(seq_range[0]) + self.assertEquals(None, self.seq.open(key='foo', txn=None, flags=db.DB_CREATE)) + self.assertEquals(seq_range, self.seq.get_range()) + +@@ -110,7 +110,7 @@ class DBSequenceTest(unittest.TestCase): + value_minus=(-1L<<63)+1 # Two complement + self.assertEquals(-9223372036854775807L,value_minus) + self.seq = db.DBSequence(self.d, flags=0) +- self.assertEquals(None, self.seq.init_value(value_plus-1)) ++ self.assertEquals(None, self.seq.initial_value(value_plus-1)) + self.assertEquals(None, self.seq.open(key='id', txn=None, + flags=db.DB_CREATE)) + self.assertEquals(value_plus-1, self.seq.get(1)) +@@ -119,7 +119,7 @@ class DBSequenceTest(unittest.TestCase): + self.seq.remove(txn=None, flags=0) + + self.seq = db.DBSequence(self.d, flags=0) +- self.assertEquals(None, self.seq.init_value(value_minus)) ++ self.assertEquals(None, self.seq.initial_value(value_minus)) + self.assertEquals(None, self.seq.open(key='id', txn=None, + flags=db.DB_CREATE)) + self.assertEquals(value_minus, self.seq.get(1)) +diff -Nupr Python-2.6.4.orig/Lib/bsddb/test_support.py Python-2.6.4/Lib/bsddb/test_support.py +--- Python-2.6.4.orig/Lib/bsddb/test_support.py 1969-12-31 19:00:00.000000000 -0500 ++++ Python-2.6.4/Lib/bsddb/test_support.py 2009-12-04 07:36:00.000000000 -0500 +@@ -0,0 +1,54 @@ ++# This module is a bridge. ++# ++# Code is copied from Python 2.6 (trunk) Lib/test/test_support.py that ++# the bsddb test suite needs even when run standalone on a python ++# version that may not have all of these. ++ ++# DO NOT ADD NEW UNIQUE CODE. Copy code from the python trunk ++# trunk test_support module into here. If you need a place for your ++# own stuff specific to bsddb tests, make a bsddb.test.foo module. ++ ++import errno ++import os ++import shutil ++import socket ++ ++def unlink(filename): ++ try: ++ os.unlink(filename) ++ except OSError: ++ pass ++ ++def rmtree(path): ++ try: ++ shutil.rmtree(path) ++ except OSError, e: ++ # Unix returns ENOENT, Windows returns ESRCH. ++ if e.errno not in (errno.ENOENT, errno.ESRCH): ++ raise ++ ++def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM): ++ tempsock = socket.socket(family, socktype) ++ port = bind_port(tempsock, family=family, socktype=socktype) ++ tempsock.close() ++ del tempsock ++ return port ++ ++HOST = 'localhost' ++def bind_port(sock, family, socktype, host=HOST): ++ if family == socket.AF_INET and type == socket.SOCK_STREAM: ++ if hasattr(socket, 'SO_REUSEADDR'): ++ if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) == 1: ++ raise TestFailed("tests should never set the SO_REUSEADDR " \ ++ "socket option on TCP/IP sockets!") ++ if hasattr(socket, 'SO_REUSEPORT'): ++ if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT) == 1: ++ raise TestFailed("tests should never set the SO_REUSEPORT " \ ++ "socket option on TCP/IP sockets!") ++ if hasattr(socket, 'SO_EXCLUSIVEADDRUSE'): ++ sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) ++ ++ sock.bind((host, 0)) ++ port = sock.getsockname()[1] ++ return port ++ +diff -Nupr Python-2.6.4.orig/Modules/_bsddb.c Python-2.6.4/Modules/_bsddb.c +--- Python-2.6.4.orig/Modules/_bsddb.c 2008-09-23 14:54:08.000000000 -0400 ++++ Python-2.6.4/Modules/_bsddb.c 2009-12-04 07:34:56.000000000 -0500 +@@ -95,7 +95,7 @@ + #include "bsddb.h" + #undef COMPILING_BSDDB_C + +-static char *rcs_id = "$Id: python-2.6-update-bsddb3-4.8.patch,v 1.1 2009/12/18 03:20:50 dmalcolm Exp $"; ++static char *rcs_id = "$Id: python-2.6-update-bsddb3-4.8.patch,v 1.1 2009/12/18 03:20:50 dmalcolm Exp $"; + + /* --------------------------------------------------------------------- */ + /* Various macro definitions */ +@@ -169,9 +169,6 @@ static PyInterpreterState* _db_interpret + + #endif + +-/* Should DB_INCOMPLETE be turned into a warning or an exception? */ +-#define INCOMPLETE_IS_WARNING 1 +- + /* --------------------------------------------------------------------- */ + /* Exceptions */ + +@@ -191,10 +188,6 @@ static PyObject* DBNoServerIDError; + static PyObject* DBPageNotFoundError; /* DB_PAGE_NOTFOUND */ + static PyObject* DBSecondaryBadError; /* DB_SECONDARY_BAD */ + +-#if !INCOMPLETE_IS_WARNING +-static PyObject* DBIncompleteError; /* DB_INCOMPLETE */ +-#endif +- + static PyObject* DBInvalidArgError; /* EINVAL */ + static PyObject* DBAccessError; /* EACCES */ + static PyObject* DBNoSpaceError; /* ENOSPC */ +@@ -208,6 +201,13 @@ static PyObject* DBPermissionsError; + #if (DBVER >= 42) + static PyObject* DBRepHandleDeadError; /* DB_REP_HANDLE_DEAD */ + #endif ++#if (DBVER >= 44) ++static PyObject* DBRepLockoutError; /* DB_REP_LOCKOUT */ ++#endif ++ ++#if (DBVER >= 46) ++static PyObject* DBRepLeaseExpiredError; /* DB_REP_LEASE_EXPIRED */ ++#endif + + static PyObject* DBRepUnavailError; /* DB_REP_UNAVAIL */ + +@@ -215,6 +215,10 @@ static PyObject* DBRepUnavailError; + #define DB_BUFFER_SMALL ENOMEM + #endif + ++#if (DBVER < 48) ++#define DB_GID_SIZE DB_XIDDATASIZE ++#endif ++ + + /* --------------------------------------------------------------------- */ + /* Structure definitions */ +@@ -667,27 +671,8 @@ static int makeDBError(int err) + unsigned int bytes_left; + + switch (err) { +- case 0: /* successful, no error */ break; +- +-#if (DBVER < 41) +- case DB_INCOMPLETE: +-#if INCOMPLETE_IS_WARNING +- bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt)); +- /* Ensure that bytes_left never goes negative */ +- if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) { +- bytes_left = sizeof(errTxt) - bytes_left - 4 - 1; +- assert(bytes_left >= 0); +- strcat(errTxt, " -- "); +- strncat(errTxt, _db_errmsg, bytes_left); +- } +- _db_errmsg[0] = 0; +- exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt); +- +-#else /* do an exception instead */ +- errObj = DBIncompleteError; +-#endif +- break; +-#endif /* DBVER < 41 */ ++ case 0: /* successful, no error */ ++ return 0; + + case DB_KEYEMPTY: errObj = DBKeyEmptyError; break; + case DB_KEYEXIST: errObj = DBKeyExistError; break; +@@ -720,6 +705,13 @@ static int makeDBError(int err) + #if (DBVER >= 42) + case DB_REP_HANDLE_DEAD : errObj = DBRepHandleDeadError; break; + #endif ++#if (DBVER >= 44) ++ case DB_REP_LOCKOUT : errObj = DBRepLockoutError; break; ++#endif ++ ++#if (DBVER >= 46) ++ case DB_REP_LEASE_EXPIRED : errObj = DBRepLeaseExpiredError; break; ++#endif + + case DB_REP_UNAVAIL : errObj = DBRepUnavailError; break; + +@@ -1417,10 +1409,70 @@ _db_associateCallback(DB* db, const DBT* + PyErr_Print(); + } + } ++#if (DBVER >= 46) ++ else if (PyList_Check(result)) ++ { ++ char* data; ++ Py_ssize_t size; ++ int i, listlen; ++ DBT* dbts; ++ ++ listlen = PyList_Size(result); ++ ++ dbts = (DBT *)malloc(sizeof(DBT) * listlen); ++ ++ for (i=0; iassociate callback should be a list of strings."); ++#else ++"The list returned by DB->associate callback should be a list of bytes."); ++#endif ++ PyErr_Print(); ++ } ++ ++ PyBytes_AsStringAndSize( ++ PyList_GetItem(result, i), ++ &data, &size); ++ ++ CLEAR_DBT(dbts[i]); ++ dbts[i].data = malloc(size); /* TODO, check this */ ++ ++ if (dbts[i].data) ++ { ++ memcpy(dbts[i].data, data, size); ++ dbts[i].size = size; ++ dbts[i].ulen = dbts[i].size; ++ dbts[i].flags = DB_DBT_APPMALLOC; /* DB will free */ ++ } ++ else ++ { ++ PyErr_SetString(PyExc_MemoryError, ++ "malloc failed in _db_associateCallback (list)"); ++ PyErr_Print(); ++ } ++ } ++ ++ CLEAR_DBT(*secKey); ++ ++ secKey->data = dbts; ++ secKey->size = listlen; ++ secKey->flags = DB_DBT_APPMALLOC | DB_DBT_MULTIPLE; ++ retval = 0; ++ } ++#endif + else { + PyErr_SetString( + PyExc_TypeError, +- "DB associate callback should return DB_DONOTINDEX or string."); ++#if (PY_VERSION_HEX < 0x03000000) ++"DB associate callback should return DB_DONOTINDEX/string/list of strings."); ++#else ++"DB associate callback should return DB_DONOTINDEX/bytes/list of bytes."); ++#endif + PyErr_Print(); + } + +@@ -1439,29 +1491,18 @@ DB_associate(DBObject* self, PyObject* a + int err, flags=0; + DBObject* secondaryDB; + PyObject* callback; +-#if (DBVER >= 41) + PyObject *txnobj = NULL; + DB_TXN *txn = NULL; + static char* kwnames[] = {"secondaryDB", "callback", "flags", "txn", + NULL}; +-#else +- static char* kwnames[] = {"secondaryDB", "callback", "flags", NULL}; +-#endif + +-#if (DBVER >= 41) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iO:associate", kwnames, + &secondaryDB, &callback, &flags, + &txnobj)) { +-#else +- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i:associate", kwnames, +- &secondaryDB, &callback, &flags)) { +-#endif + return NULL; + } + +-#if (DBVER >= 41) + if (!checkTxnObj(txnobj, &txn)) return NULL; +-#endif + + CHECK_DB_NOT_CLOSED(self); + if (!DBObject_Check(secondaryDB)) { +@@ -1497,18 +1538,11 @@ DB_associate(DBObject* self, PyObject* a + PyEval_InitThreads(); + #endif + MYDB_BEGIN_ALLOW_THREADS; +-#if (DBVER >= 41) + err = self->db->associate(self->db, + txn, + secondaryDB->db, + _db_associateCallback, + flags); +-#else +- err = self->db->associate(self->db, +- secondaryDB->db, +- _db_associateCallback, +- flags); +-#endif + MYDB_END_ALLOW_THREADS; + + if (err) { +@@ -1701,6 +1735,64 @@ DB_delete(DBObject* self, PyObject* args + } + + ++#if (DBVER >= 47) ++/* ++** This function is available since Berkeley DB 4.4, ++** but 4.6 version is so buggy that we only support ++** it from BDB 4.7 and newer. ++*/ ++static PyObject* ++DB_compact(DBObject* self, PyObject* args, PyObject* kwargs) ++{ ++ PyObject* txnobj = NULL; ++ PyObject *startobj = NULL, *stopobj = NULL; ++ int flags = 0; ++ DB_TXN *txn = NULL; ++ DBT *start_p = NULL, *stop_p = NULL; ++ DBT start, stop; ++ int err; ++ DB_COMPACT c_data = { 0 }; ++ static char* kwnames[] = { "txn", "start", "stop", "flags", ++ "compact_fillpercent", "compact_pages", ++ "compact_timeout", NULL }; ++ ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOiiiI:compact", kwnames, ++ &txnobj, &startobj, &stopobj, &flags, ++ &c_data.compact_fillpercent, ++ &c_data.compact_pages, ++ &c_data.compact_timeout)) ++ return NULL; ++ ++ CHECK_DB_NOT_CLOSED(self); ++ if (!checkTxnObj(txnobj, &txn)) { ++ return NULL; ++ } ++ ++ if (startobj && make_key_dbt(self, startobj, &start, NULL)) { ++ start_p = &start; ++ } ++ if (stopobj && make_key_dbt(self, stopobj, &stop, NULL)) { ++ stop_p = &stop; ++ } ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db->compact(self->db, txn, start_p, stop_p, &c_data, ++ flags, NULL); ++ MYDB_END_ALLOW_THREADS; ++ ++ if (startobj) ++ FREE_DBT(start); ++ if (stopobj) ++ FREE_DBT(stop); ++ ++ RETURN_IF_ERR(); ++ ++ return PyLong_FromUnsignedLong(c_data.compact_pages_truncated); ++} ++#endif ++ ++ + static PyObject* + DB_fd(DBObject* self) + { +@@ -1716,6 +1808,55 @@ DB_fd(DBObject* self) + } + + ++#if (DBVER >= 46) ++static PyObject* ++DB_exists(DBObject* self, PyObject* args, PyObject* kwargs) ++{ ++ int err, flags=0; ++ PyObject* txnobj = NULL; ++ PyObject* keyobj; ++ DBT key; ++ DB_TXN *txn; ++ ++ static char* kwnames[] = {"key", "txn", "flags", NULL}; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:exists", kwnames, ++ &keyobj, &txnobj, &flags)) ++ return NULL; ++ ++ CHECK_DB_NOT_CLOSED(self); ++ if (!make_key_dbt(self, keyobj, &key, NULL)) ++ return NULL; ++ if (!checkTxnObj(txnobj, &txn)) { ++ FREE_DBT(key); ++ return NULL; ++ } ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db->exists(self->db, txn, &key, flags); ++ MYDB_END_ALLOW_THREADS; ++ ++ FREE_DBT(key); ++ ++ if (!err) { ++ Py_INCREF(Py_True); ++ return Py_True; ++ } ++ if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)) { ++ Py_INCREF(Py_False); ++ return Py_False; ++ } ++ ++ /* ++ ** If we reach there, there was an error. The ++ ** "return" should be unreachable. ++ */ ++ RETURN_IF_ERR(); ++ assert(0); /* This coude SHOULD be unreachable */ ++ return NULL; ++} ++#endif ++ + static PyObject* + DB_get(DBObject* self, PyObject* args, PyObject* kwargs) + { +@@ -2114,7 +2255,6 @@ DB_open(DBObject* self, PyObject* args, + int err, type = DB_UNKNOWN, flags=0, mode=0660; + char* filename = NULL; + char* dbname = NULL; +-#if (DBVER >= 41) + PyObject *txnobj = NULL; + DB_TXN *txn = NULL; + /* with dbname */ +@@ -2123,45 +2263,22 @@ DB_open(DBObject* self, PyObject* args, + /* without dbname */ + static char* kwnames_basic[] = { + "filename", "dbtype", "flags", "mode", "txn", NULL}; +-#else +- /* with dbname */ +- static char* kwnames[] = { +- "filename", "dbname", "dbtype", "flags", "mode", NULL}; +- /* without dbname */ +- static char* kwnames_basic[] = { +- "filename", "dbtype", "flags", "mode", NULL}; +-#endif + +-#if (DBVER >= 41) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziiiO:open", kwnames, + &filename, &dbname, &type, &flags, &mode, + &txnobj)) +-#else +- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziii:open", kwnames, +- &filename, &dbname, &type, &flags, +- &mode)) +-#endif + { + PyErr_Clear(); + type = DB_UNKNOWN; flags = 0; mode = 0660; + filename = NULL; dbname = NULL; +-#if (DBVER >= 41) + if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iiiO:open", + kwnames_basic, + &filename, &type, &flags, &mode, + &txnobj)) + return NULL; +-#else +- if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iii:open", +- kwnames_basic, +- &filename, &type, &flags, &mode)) +- return NULL; +-#endif + } + +-#if (DBVER >= 41) + if (!checkTxnObj(txnobj, &txn)) return NULL; +-#endif + + if (NULL == self->db) { + PyObject *t = Py_BuildValue("(is)", 0, +@@ -2173,24 +2290,17 @@ DB_open(DBObject* self, PyObject* args, + return NULL; + } + +-#if (DBVER >= 41) + if (txn) { /* Can't use 'txnobj' because could be 'txnobj==Py_None' */ + INSERT_IN_DOUBLE_LINKED_LIST_TXN(((DBTxnObject *)txnobj)->children_dbs,self); + self->txn=(DBTxnObject *)txnobj; + } else { + self->txn=NULL; + } +-#else +- self->txn=NULL; +-#endif + + MYDB_BEGIN_ALLOW_THREADS; +-#if (DBVER >= 41) + err = self->db->open(self->db, txn, filename, dbname, type, flags, mode); +-#else +- err = self->db->open(self->db, filename, dbname, type, flags, mode); +-#endif + MYDB_END_ALLOW_THREADS; ++ + if (makeDBError(err)) { + PyObject *dummy; + +@@ -2490,6 +2600,25 @@ DB_set_cachesize(DBObject* self, PyObjec + RETURN_NONE(); + } + ++#if (DBVER >= 42) ++static PyObject* ++DB_get_cachesize(DBObject* self) ++{ ++ int err; ++ u_int32_t gbytes, bytes; ++ int ncache; ++ ++ CHECK_DB_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db->get_cachesize(self->db, &gbytes, &bytes, &ncache); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ ++ return Py_BuildValue("(iii)", gbytes, bytes, ncache); ++} ++#endif + + static PyObject* + DB_set_flags(DBObject* self, PyObject* args) +@@ -2730,9 +2859,6 @@ DB_stat(DBObject* self, PyObject* args, + MAKE_HASH_ENTRY(pagecnt); + #endif + MAKE_HASH_ENTRY(pagesize); +-#if (DBVER < 41) +- MAKE_HASH_ENTRY(nelem); +-#endif + MAKE_HASH_ENTRY(ffactor); + MAKE_HASH_ENTRY(buckets); + MAKE_HASH_ENTRY(free); +@@ -2779,9 +2905,7 @@ DB_stat(DBObject* self, PyObject* args, + MAKE_QUEUE_ENTRY(nkeys); + MAKE_QUEUE_ENTRY(ndata); + MAKE_QUEUE_ENTRY(pagesize); +-#if (DBVER >= 41) + MAKE_QUEUE_ENTRY(extentsize); +-#endif + MAKE_QUEUE_ENTRY(pages); + MAKE_QUEUE_ENTRY(re_len); + MAKE_QUEUE_ENTRY(re_pad); +@@ -2892,7 +3016,7 @@ DB_verify(DBObject* self, PyObject* args + PyObject *error; + + error=DB_close_internal(self, 0, 1); +- if (error ) { ++ if (error) { + return error; + } + } +@@ -2930,7 +3054,6 @@ DB_set_get_returns_none(DBObject* self, + return NUMBER_FromLong(oldValue); + } + +-#if (DBVER >= 41) + static PyObject* + DB_set_encrypt(DBObject* self, PyObject* args, PyObject* kwargs) + { +@@ -2951,7 +3074,24 @@ DB_set_encrypt(DBObject* self, PyObject* + RETURN_IF_ERR(); + RETURN_NONE(); + } +-#endif /* DBVER >= 41 */ ++ ++#if (DBVER >= 42) ++static PyObject* ++DB_get_encrypt_flags(DBObject* self) ++{ ++ int err; ++ u_int32_t flags; ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db->get_encrypt_flags(self->db, &flags); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ ++ return NUMBER_FromLong(flags); ++} ++#endif ++ + + + /*-------------------------------------------------------------- */ +@@ -3097,18 +3237,11 @@ DB_ass_sub(DBObject* self, PyObject* key + + + static PyObject* +-DB_has_key(DBObject* self, PyObject* args, PyObject* kwargs) ++_DB_has_key(DBObject* self, PyObject* keyobj, PyObject* txnobj) + { + int err; +- PyObject* keyobj; +- DBT key, data; +- PyObject* txnobj = NULL; ++ DBT key; + DB_TXN *txn = NULL; +- static char* kwnames[] = {"key","txn", NULL}; +- +- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:has_key", kwnames, +- &keyobj, &txnobj)) +- return NULL; + + CHECK_DB_NOT_CLOSED(self); + if (!make_key_dbt(self, keyobj, &key, NULL)) +@@ -3118,28 +3251,77 @@ DB_has_key(DBObject* self, PyObject* arg + return NULL; + } + ++#if (DBVER < 46) + /* This causes DB_BUFFER_SMALL to be returned when the db has the key because + it has a record but can't allocate a buffer for the data. This saves + having to deal with data we won't be using. + */ +- CLEAR_DBT(data); +- data.flags = DB_DBT_USERMEM; ++ { ++ DBT data ; ++ CLEAR_DBT(data); ++ data.flags = DB_DBT_USERMEM; + ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db->get(self->db, txn, &key, &data, 0); ++ MYDB_END_ALLOW_THREADS; ++ } ++#else + MYDB_BEGIN_ALLOW_THREADS; +- err = self->db->get(self->db, txn, &key, &data, 0); ++ err = self->db->exists(self->db, txn, &key, 0); + MYDB_END_ALLOW_THREADS; ++#endif ++ + FREE_DBT(key); + ++ /* ++ ** DB_BUFFER_SMALL is only used if we use "get". ++ ** We can drop it when we only use "exists", ++ ** when we drop suport for Berkeley DB < 4.6. ++ */ + if (err == DB_BUFFER_SMALL || err == 0) { +- return NUMBER_FromLong(1); ++ Py_INCREF(Py_True); ++ return Py_True; + } else if (err == DB_NOTFOUND || err == DB_KEYEMPTY) { +- return NUMBER_FromLong(0); ++ Py_INCREF(Py_False); ++ return Py_False; + } + + makeDBError(err); + return NULL; + } + ++static PyObject* ++DB_has_key(DBObject* self, PyObject* args, PyObject* kwargs) ++{ ++ PyObject* keyobj; ++ PyObject* txnobj = NULL; ++ static char* kwnames[] = {"key","txn", NULL}; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:has_key", kwnames, ++ &keyobj, &txnobj)) ++ return NULL; ++ ++ return _DB_has_key(self, keyobj, txnobj); ++} ++ ++ ++static int DB_contains(DBObject* self, PyObject* keyobj) ++{ ++ PyObject* result; ++ int result2 = 0; ++ ++ result = _DB_has_key(self, keyobj, NULL) ; ++ if (result == NULL) { ++ return -1; /* Propague exception */ ++ } ++ if (result != Py_False) { ++ result2 = 1; ++ } ++ ++ Py_DECREF(result); ++ return result2; ++} ++ + + #define _KEYS_LIST 1 + #define _VALUES_LIST 2 +@@ -3970,6 +4152,13 @@ DBC_next_nodup(DBCursorObject* self, PyO + return _DBCursor_get(self,DB_NEXT_NODUP,args,kwargs,"|iii:next_nodup"); + } + ++#if (DBVER >= 46) ++static PyObject* ++DBC_prev_dup(DBCursorObject* self, PyObject* args, PyObject *kwargs) ++{ ++ return _DBCursor_get(self,DB_PREV_DUP,args,kwargs,"|iii:prev_dup"); ++} ++#endif + + static PyObject* + DBC_prev_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs) +@@ -4012,6 +4201,44 @@ DBC_join_item(DBCursorObject* self, PyOb + } + + ++#if (DBVER >= 46) ++static PyObject* ++DBC_set_priority(DBCursorObject* self, PyObject* args, PyObject* kwargs) ++{ ++ int err, priority; ++ static char* kwnames[] = { "priority", NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:set_priority", kwnames, ++ &priority)) ++ return NULL; ++ ++ CHECK_CURSOR_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->dbc->set_priority(self->dbc, priority); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++ ++ ++static PyObject* ++DBC_get_priority(DBCursorObject* self) ++{ ++ int err; ++ DB_CACHE_PRIORITY priority; ++ ++ CHECK_CURSOR_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->dbc->get_priority(self->dbc, &priority); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ return NUMBER_FromLong(priority); ++} ++#endif ++ ++ + + /* --------------------------------------------------------------------- */ + /* DBEnv methods */ +@@ -4095,7 +4322,6 @@ DBEnv_remove(DBEnvObject* self, PyObject + RETURN_NONE(); + } + +-#if (DBVER >= 41) + static PyObject* + DBEnv_dbremove(DBEnvObject* self, PyObject* args, PyObject* kwargs) + { +@@ -4152,6 +4378,8 @@ DBEnv_dbrename(DBEnvObject* self, PyObje + RETURN_NONE(); + } + ++ ++ + static PyObject* + DBEnv_set_encrypt(DBEnvObject* self, PyObject* args, PyObject* kwargs) + { +@@ -4172,17 +4400,57 @@ DBEnv_set_encrypt(DBEnvObject* self, PyO + RETURN_IF_ERR(); + RETURN_NONE(); + } +-#endif /* DBVER >= 41 */ + ++#if (DBVER >= 42) + static PyObject* +-DBEnv_set_timeout(DBEnvObject* self, PyObject* args, PyObject* kwargs) ++DBEnv_get_encrypt_flags(DBEnvObject* self) + { + int err; +- u_int32_t flags=0; +- u_int32_t timeout = 0; +- static char* kwnames[] = { "timeout", "flags", NULL }; ++ u_int32_t flags; + +- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames, ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->get_encrypt_flags(self->db_env, &flags); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ ++ return NUMBER_FromLong(flags); ++} ++ ++static PyObject* ++DBEnv_get_timeout(DBEnvObject* self, PyObject* args, PyObject* kwargs) ++{ ++ int err; ++ int flag; ++ u_int32_t timeout; ++ static char* kwnames[] = {"flag", NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:get_timeout", kwnames, ++ &flag)) { ++ return NULL; ++ } ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->get_timeout(self->db_env, &timeout, flag); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ return NUMBER_FromLong(timeout); ++} ++#endif ++ ++ ++static PyObject* ++DBEnv_set_timeout(DBEnvObject* self, PyObject* args, PyObject* kwargs) ++{ ++ int err; ++ u_int32_t flags=0; ++ u_int32_t timeout = 0; ++ static char* kwnames[] = { "timeout", "flags", NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames, + &timeout, &flags)) { + return NULL; + } +@@ -4210,6 +4478,25 @@ DBEnv_set_shm_key(DBEnvObject* self, PyO + RETURN_NONE(); + } + ++#if (DBVER >= 42) ++static PyObject* ++DBEnv_get_shm_key(DBEnvObject* self) ++{ ++ int err; ++ long shm_key; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->get_shm_key(self->db_env, &shm_key); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ ++ return NUMBER_FromLong(shm_key); ++} ++#endif ++ + static PyObject* + DBEnv_set_cachesize(DBEnvObject* self, PyObject* args) + { +@@ -4227,6 +4514,26 @@ DBEnv_set_cachesize(DBEnvObject* self, P + RETURN_NONE(); + } + ++#if (DBVER >= 42) ++static PyObject* ++DBEnv_get_cachesize(DBEnvObject* self) ++{ ++ int err; ++ u_int32_t gbytes, bytes; ++ int ncache; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->get_cachesize(self->db_env, &gbytes, &bytes, &ncache); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ ++ return Py_BuildValue("(iii)", gbytes, bytes, ncache); ++} ++#endif ++ + + static PyObject* + DBEnv_set_flags(DBEnvObject* self, PyObject* args) +@@ -4265,6 +4572,151 @@ DBEnv_log_set_config(DBEnvObject* self, + } + #endif /* DBVER >= 47 */ + ++#if (DBVER >= 44) ++static PyObject* ++DBEnv_mutex_set_max(DBEnvObject* self, PyObject* args) ++{ ++ int err; ++ int value; ++ ++ if (!PyArg_ParseTuple(args, "i:mutex_set_max", &value)) ++ return NULL; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->mutex_set_max(self->db_env, value); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++ ++static PyObject* ++DBEnv_mutex_get_max(DBEnvObject* self) ++{ ++ int err; ++ u_int32_t value; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->mutex_get_max(self->db_env, &value); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ ++ return NUMBER_FromLong(value); ++} ++ ++static PyObject* ++DBEnv_mutex_set_align(DBEnvObject* self, PyObject* args) ++{ ++ int err; ++ int align; ++ ++ if (!PyArg_ParseTuple(args, "i:mutex_set_align", &align)) ++ return NULL; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->mutex_set_align(self->db_env, align); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++ ++static PyObject* ++DBEnv_mutex_get_align(DBEnvObject* self) ++{ ++ int err; ++ u_int32_t align; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->mutex_get_align(self->db_env, &align); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ ++ return NUMBER_FromLong(align); ++} ++ ++static PyObject* ++DBEnv_mutex_set_increment(DBEnvObject* self, PyObject* args) ++{ ++ int err; ++ int increment; ++ ++ if (!PyArg_ParseTuple(args, "i:mutex_set_increment", &increment)) ++ return NULL; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->mutex_set_increment(self->db_env, increment); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++ ++static PyObject* ++DBEnv_mutex_get_increment(DBEnvObject* self) ++{ ++ int err; ++ u_int32_t increment; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->mutex_get_increment(self->db_env, &increment); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ ++ return NUMBER_FromLong(increment); ++} ++ ++static PyObject* ++DBEnv_mutex_set_tas_spins(DBEnvObject* self, PyObject* args) ++{ ++ int err; ++ int tas_spins; ++ ++ if (!PyArg_ParseTuple(args, "i:mutex_set_tas_spins", &tas_spins)) ++ return NULL; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->mutex_set_tas_spins(self->db_env, tas_spins); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++ ++static PyObject* ++DBEnv_mutex_get_tas_spins(DBEnvObject* self) ++{ ++ int err; ++ u_int32_t tas_spins; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->mutex_get_tas_spins(self->db_env, &tas_spins); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ ++ return NUMBER_FromLong(tas_spins); ++} ++#endif + + static PyObject* + DBEnv_set_data_dir(DBEnvObject* self, PyObject* args) +@@ -4283,6 +4735,47 @@ DBEnv_set_data_dir(DBEnvObject* self, Py + RETURN_NONE(); + } + ++#if (DBVER >= 42) ++static PyObject* ++DBEnv_get_data_dirs(DBEnvObject* self) ++{ ++ int err; ++ PyObject *tuple; ++ PyObject *item; ++ const char **dirpp; ++ int size, i; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->get_data_dirs(self->db_env, &dirpp); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ ++ /* ++ ** Calculate size. Python C API ++ ** actually allows for tuple resizing, ++ ** but this is simple enough. ++ */ ++ for (size=0; *(dirpp+size) ; size++); ++ ++ tuple = PyTuple_New(size); ++ if (!tuple) ++ return NULL; ++ ++ for (i=0; i= 42) ++static PyObject* ++DBEnv_get_tx_max(DBEnvObject* self) ++{ ++ int err; ++ u_int32_t max; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->get_tx_max(self->db_env, &max); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ return PyLong_FromUnsignedLong(max); ++} ++#endif ++ ++ + static PyObject* + DBEnv_set_tx_max(DBEnvObject* self, PyObject* args) + { +@@ -4611,12 +5126,31 @@ DBEnv_set_tx_max(DBEnvObject* self, PyOb + return NULL; + CHECK_ENV_NOT_CLOSED(self); + ++ MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_tx_max(self->db_env, max); ++ MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); + } + + ++#if (DBVER >= 42) ++static PyObject* ++DBEnv_get_tx_timestamp(DBEnvObject* self) ++{ ++ int err; ++ time_t timestamp; ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->get_tx_timestamp(self->db_env, ×tamp); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ return NUMBER_FromLong(timestamp); ++} ++#endif ++ + static PyObject* + DBEnv_set_tx_timestamp(DBEnvObject* self, PyObject* args) + { +@@ -4628,7 +5162,9 @@ DBEnv_set_tx_timestamp(DBEnvObject* self + return NULL; + CHECK_ENV_NOT_CLOSED(self); + timestamp = (time_t)stamp; ++ MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_tx_timestamp(self->db_env, ×tamp); ++ MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); + } +@@ -4722,6 +5258,26 @@ DBEnv_lock_put(DBEnvObject* self, PyObje + + #if (DBVER >= 44) + static PyObject* ++DBEnv_fileid_reset(DBEnvObject* self, PyObject* args, PyObject* kwargs) ++{ ++ int err; ++ char *file; ++ u_int32_t flags = 0; ++ static char* kwnames[] = { "file", "flags", NULL}; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|i:fileid_reset", kwnames, ++ &file, &flags)) ++ return NULL; ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->fileid_reset(self->db_env, file, flags); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++ ++static PyObject* + DBEnv_lsn_reset(DBEnvObject* self, PyObject* args, PyObject* kwargs) + { + int err; +@@ -4777,9 +5333,6 @@ DBEnv_log_stat(DBEnvObject* self, PyObje + MAKE_ENTRY(lg_size); + MAKE_ENTRY(record); + #endif +-#if (DBVER < 41) +- MAKE_ENTRY(lg_max); +-#endif + MAKE_ENTRY(w_mbytes); + MAKE_ENTRY(w_bytes); + MAKE_ENTRY(wc_mbytes); +@@ -4832,13 +5385,8 @@ DBEnv_lock_stat(DBEnvObject* self, PyObj + + #define MAKE_ENTRY(name) _addIntToDict(d, #name, sp->st_##name) + +-#if (DBVER < 41) +- MAKE_ENTRY(lastid); +-#endif +-#if (DBVER >=41) + MAKE_ENTRY(id); + MAKE_ENTRY(cur_maxid); +-#endif + MAKE_ENTRY(nmodes); + MAKE_ENTRY(maxlocks); + MAKE_ENTRY(maxlockers); +@@ -4863,10 +5411,8 @@ DBEnv_lock_stat(DBEnvObject* self, PyObj + MAKE_ENTRY(lock_wait); + #endif + MAKE_ENTRY(ndeadlocks); +-#if (DBVER >= 41) + MAKE_ENTRY(locktimeout); + MAKE_ENTRY(txntimeout); +-#endif + MAKE_ENTRY(nlocktimeouts); + MAKE_ENTRY(ntxntimeouts); + #if (DBVER >= 46) +@@ -4955,6 +5501,31 @@ DBEnv_log_archive(DBEnvObject* self, PyO + } + + ++#if (DBVER >= 43) ++static PyObject* ++DBEnv_txn_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs) ++{ ++ int err; ++ int flags=0; ++ static char* kwnames[] = { "flags", NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat_print", ++ kwnames, &flags)) ++ { ++ return NULL; ++ } ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->txn_stat_print(self->db_env, flags); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++#endif ++ ++ + static PyObject* + DBEnv_txn_stat(DBEnvObject* self, PyObject* args) + { +@@ -5047,6 +5618,7 @@ DBEnv_set_private(DBEnvObject* self, PyO + } + + ++#if (DBVER < 48) + static PyObject* + DBEnv_set_rpc_server(DBEnvObject* self, PyObject* args, PyObject* kwargs) + { +@@ -5068,6 +5640,7 @@ DBEnv_set_rpc_server(DBEnvObject* self, + RETURN_IF_ERR(); + RETURN_NONE(); + } ++#endif + + static PyObject* + DBEnv_set_verbose(DBEnvObject* self, PyObject* args) +@@ -5551,79 +6124,248 @@ DBEnv_rep_get_nsites(DBEnvObject* self) + err = self->db_env->rep_get_nsites(self->db_env, &nsites); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); +- return NUMBER_FromLong(nsites); ++ return NUMBER_FromLong(nsites); ++} ++ ++static PyObject* ++DBEnv_rep_set_priority(DBEnvObject* self, PyObject* args) ++{ ++ int err; ++ int priority; ++ ++ if (!PyArg_ParseTuple(args, "i:rep_set_priority", &priority)) { ++ return NULL; ++ } ++ CHECK_ENV_NOT_CLOSED(self); ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->rep_set_priority(self->db_env, priority); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++ ++static PyObject* ++DBEnv_rep_get_priority(DBEnvObject* self) ++{ ++ int err; ++#if (DBVER >= 47) ++ u_int32_t priority; ++#else ++ int priority; ++#endif ++ ++ CHECK_ENV_NOT_CLOSED(self); ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->rep_get_priority(self->db_env, &priority); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ return NUMBER_FromLong(priority); ++} ++ ++static PyObject* ++DBEnv_rep_set_timeout(DBEnvObject* self, PyObject* args) ++{ ++ int err; ++ int which, timeout; ++ ++ if (!PyArg_ParseTuple(args, "ii:rep_set_timeout", &which, &timeout)) { ++ return NULL; ++ } ++ CHECK_ENV_NOT_CLOSED(self); ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->rep_set_timeout(self->db_env, which, timeout); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++ ++static PyObject* ++DBEnv_rep_get_timeout(DBEnvObject* self, PyObject* args) ++{ ++ int err; ++ int which; ++ u_int32_t timeout; ++ ++ if (!PyArg_ParseTuple(args, "i:rep_get_timeout", &which)) { ++ return NULL; ++ } ++ CHECK_ENV_NOT_CLOSED(self); ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->db_env->rep_get_timeout(self->db_env, which, &timeout); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ return NUMBER_FromLong(timeout); + } ++#endif ++ + ++#if (DBVER >= 47) + static PyObject* +-DBEnv_rep_set_priority(DBEnvObject* self, PyObject* args) ++DBEnv_rep_set_clockskew(DBEnvObject* self, PyObject* args) + { + int err; +- int priority; ++ unsigned int fast, slow; + +- if (!PyArg_ParseTuple(args, "i:rep_set_priority", &priority)) { ++#if (PY_VERSION_HEX >= 0x02040000) ++ if (!PyArg_ParseTuple(args,"II:rep_set_clockskew", &fast, &slow)) + return NULL; +- } ++#else ++ if (!PyArg_ParseTuple(args,"ii:rep_set_clockskew", &fast, &slow)) ++ return NULL; ++#endif ++ + CHECK_ENV_NOT_CLOSED(self); ++ + MYDB_BEGIN_ALLOW_THREADS; +- err = self->db_env->rep_set_priority(self->db_env, priority); ++ err = self->db_env->rep_set_clockskew(self->db_env, fast, slow); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); + } + + static PyObject* +-DBEnv_rep_get_priority(DBEnvObject* self) ++DBEnv_rep_get_clockskew(DBEnvObject* self) + { + int err; +-#if (DBVER >= 47) +- u_int32_t priority; +-#else +- int priority; +-#endif ++ unsigned int fast, slow; + + CHECK_ENV_NOT_CLOSED(self); + MYDB_BEGIN_ALLOW_THREADS; +- err = self->db_env->rep_get_priority(self->db_env, &priority); ++ err = self->db_env->rep_get_clockskew(self->db_env, &fast, &slow); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); +- return NUMBER_FromLong(priority); ++#if (PY_VERSION_HEX >= 0x02040000) ++ return Py_BuildValue("(II)", fast, slow); ++#else ++ return Py_BuildValue("(ii)", fast, slow); ++#endif + } ++#endif + ++#if (DBVER >= 43) + static PyObject* +-DBEnv_rep_set_timeout(DBEnvObject* self, PyObject* args) ++DBEnv_rep_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs) + { + int err; +- int which, timeout; ++ int flags=0; ++ static char* kwnames[] = { "flags", NULL }; + +- if (!PyArg_ParseTuple(args, "ii:rep_set_timeout", &which, &timeout)) { ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:rep_stat_print", ++ kwnames, &flags)) ++ { + return NULL; + } + CHECK_ENV_NOT_CLOSED(self); + MYDB_BEGIN_ALLOW_THREADS; +- err = self->db_env->rep_set_timeout(self->db_env, which, timeout); ++ err = self->db_env->rep_stat_print(self->db_env, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); + } ++#endif + + static PyObject* +-DBEnv_rep_get_timeout(DBEnvObject* self, PyObject* args) ++DBEnv_rep_stat(DBEnvObject* self, PyObject* args, PyObject *kwargs) + { + int err; +- int which; +- u_int32_t timeout; ++ int flags=0; ++ DB_REP_STAT *statp; ++ PyObject *stats; ++ static char* kwnames[] = { "flags", NULL }; + +- if (!PyArg_ParseTuple(args, "i:rep_get_timeout", &which)) { ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:rep_stat", ++ kwnames, &flags)) ++ { + return NULL; + } + CHECK_ENV_NOT_CLOSED(self); + MYDB_BEGIN_ALLOW_THREADS; +- err = self->db_env->rep_get_timeout(self->db_env, which, &timeout); ++ err = self->db_env->rep_stat(self->db_env, &statp, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); +- return NUMBER_FromLong(timeout); +-} ++ ++ stats=PyDict_New(); ++ if (stats == NULL) { ++ free(statp); ++ return NULL; ++ } ++ ++#define MAKE_ENTRY(name) _addIntToDict(stats, #name, statp->st_##name) ++#define MAKE_DB_LSN_ENTRY(name) _addDB_lsnToDict(stats , #name, statp->st_##name) ++ ++#if (DBVER >= 44) ++ MAKE_ENTRY(bulk_fills); ++ MAKE_ENTRY(bulk_overflows); ++ MAKE_ENTRY(bulk_records); ++ MAKE_ENTRY(bulk_transfers); ++ MAKE_ENTRY(client_rerequests); ++ MAKE_ENTRY(client_svc_miss); ++ MAKE_ENTRY(client_svc_req); ++#endif ++ MAKE_ENTRY(dupmasters); ++#if (DBVER >= 43) ++ MAKE_ENTRY(egen); ++ MAKE_ENTRY(election_nvotes); ++ MAKE_ENTRY(startup_complete); ++ MAKE_ENTRY(pg_duplicated); ++ MAKE_ENTRY(pg_records); ++ MAKE_ENTRY(pg_requested); ++ MAKE_ENTRY(next_pg); ++ MAKE_ENTRY(waiting_pg); ++#endif ++ MAKE_ENTRY(election_cur_winner); ++ MAKE_ENTRY(election_gen); ++ MAKE_DB_LSN_ENTRY(election_lsn); ++ MAKE_ENTRY(election_nsites); ++ MAKE_ENTRY(election_priority); ++#if (DBVER >= 44) ++ MAKE_ENTRY(election_sec); ++ MAKE_ENTRY(election_usec); ++#endif ++ MAKE_ENTRY(election_status); ++ MAKE_ENTRY(election_tiebreaker); ++ MAKE_ENTRY(election_votes); ++ MAKE_ENTRY(elections); ++ MAKE_ENTRY(elections_won); ++ MAKE_ENTRY(env_id); ++ MAKE_ENTRY(env_priority); ++ MAKE_ENTRY(gen); ++ MAKE_ENTRY(log_duplicated); ++ MAKE_ENTRY(log_queued); ++ MAKE_ENTRY(log_queued_max); ++ MAKE_ENTRY(log_queued_total); ++ MAKE_ENTRY(log_records); ++ MAKE_ENTRY(log_requested); ++ MAKE_ENTRY(master); ++ MAKE_ENTRY(master_changes); ++#if (DBVER >= 47) ++ MAKE_ENTRY(max_lease_sec); ++ MAKE_ENTRY(max_lease_usec); ++ MAKE_DB_LSN_ENTRY(max_perm_lsn); ++#endif ++ MAKE_ENTRY(msgs_badgen); ++ MAKE_ENTRY(msgs_processed); ++ MAKE_ENTRY(msgs_recover); ++ MAKE_ENTRY(msgs_send_failures); ++ MAKE_ENTRY(msgs_sent); ++ MAKE_ENTRY(newsites); ++ MAKE_DB_LSN_ENTRY(next_lsn); ++ MAKE_ENTRY(nsites); ++ MAKE_ENTRY(nthrottles); ++ MAKE_ENTRY(outdated); ++#if (DBVER >= 46) ++ MAKE_ENTRY(startsync_delayed); + #endif ++ MAKE_ENTRY(status); ++ MAKE_ENTRY(txns_applied); ++ MAKE_DB_LSN_ENTRY(waiting_lsn); ++ ++#undef MAKE_DB_LSN_ENTRY ++#undef MAKE_ENTRY ++ ++ free(statp); ++ return stats; ++} + + /* --------------------------------------------------------------------- */ + /* REPLICATION METHODS: Replication Manager */ +@@ -5947,9 +6689,9 @@ DBTxn_prepare(DBTxnObject* self, PyObjec + if (!PyArg_ParseTuple(args, "s#:prepare", &gid, &gid_size)) + return NULL; + +- if (gid_size != DB_XIDDATASIZE) { ++ if (gid_size != DB_GID_SIZE) { + PyErr_SetString(PyExc_TypeError, +- "gid must be DB_XIDDATASIZE bytes long"); ++ "gid must be DB_GID_SIZE bytes long"); + return NULL; + } + +@@ -6064,6 +6806,76 @@ DBTxn_id(DBTxnObject* self) + return NUMBER_FromLong(id); + } + ++ ++static PyObject* ++DBTxn_set_timeout(DBTxnObject* self, PyObject* args, PyObject* kwargs) ++{ ++ int err; ++ u_int32_t flags=0; ++ u_int32_t timeout = 0; ++ static char* kwnames[] = { "timeout", "flags", NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames, ++ &timeout, &flags)) { ++ return NULL; ++ } ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->txn->set_timeout(self->txn, (db_timeout_t)timeout, flags); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++ ++ ++#if (DBVER >= 44) ++static PyObject* ++DBTxn_set_name(DBTxnObject* self, PyObject* args) ++{ ++ int err; ++ const char *name; ++ ++ if (!PyArg_ParseTuple(args, "s:set_name", &name)) ++ return NULL; ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->txn->set_name(self->txn, name); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++#endif ++ ++ ++#if (DBVER >= 44) ++static PyObject* ++DBTxn_get_name(DBTxnObject* self) ++{ ++ int err; ++ const char *name; ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->txn->get_name(self->txn, &name); ++ MYDB_END_ALLOW_THREADS; ++ ++ RETURN_IF_ERR(); ++#if (PY_VERSION_HEX < 0x03000000) ++ if (!name) { ++ return PyString_FromString(""); ++ } ++ return PyString_FromString(name); ++#else ++ if (!name) { ++ return PyUnicode_FromString(""); ++ } ++ return PyUnicode_FromString(name); ++#endif ++} ++#endif ++ ++ + #if (DBVER >= 43) + /* --------------------------------------------------------------------- */ + /* DBSequence methods */ +@@ -6167,12 +6979,12 @@ DBSequence_get_key(DBSequenceObject* sel + } + + static PyObject* +-DBSequence_init_value(DBSequenceObject* self, PyObject* args) ++DBSequence_initial_value(DBSequenceObject* self, PyObject* args) + { + int err; + PY_LONG_LONG value; + db_seq_t value2; +- if (!PyArg_ParseTuple(args,"L:init_value", &value)) ++ if (!PyArg_ParseTuple(args,"L:initial_value", &value)) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + +@@ -6350,6 +7162,29 @@ DBSequence_get_range(DBSequenceObject* s + return Py_BuildValue("(LL)", min, max); + } + ++ ++static PyObject* ++DBSequence_stat_print(DBSequenceObject* self, PyObject* args, PyObject *kwargs) ++{ ++ int err; ++ int flags=0; ++ static char* kwnames[] = { "flags", NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat_print", ++ kwnames, &flags)) ++ { ++ return NULL; ++ } ++ ++ CHECK_SEQUENCE_NOT_CLOSED(self); ++ ++ MYDB_BEGIN_ALLOW_THREADS; ++ err = self->sequence->stat_print(self->sequence, flags); ++ MYDB_END_ALLOW_THREADS; ++ RETURN_IF_ERR(); ++ RETURN_NONE(); ++} ++ + static PyObject* + DBSequence_stat(DBSequenceObject* self, PyObject* args, PyObject* kwargs) + { +@@ -6401,11 +7236,18 @@ static PyMethodDef DB_methods[] = { + {"append", (PyCFunction)DB_append, METH_VARARGS|METH_KEYWORDS}, + {"associate", (PyCFunction)DB_associate, METH_VARARGS|METH_KEYWORDS}, + {"close", (PyCFunction)DB_close, METH_VARARGS}, ++#if (DBVER >= 47) ++ {"compact", (PyCFunction)DB_compact, METH_VARARGS|METH_KEYWORDS}, ++#endif + {"consume", (PyCFunction)DB_consume, METH_VARARGS|METH_KEYWORDS}, + {"consume_wait", (PyCFunction)DB_consume_wait, METH_VARARGS|METH_KEYWORDS}, + {"cursor", (PyCFunction)DB_cursor, METH_VARARGS|METH_KEYWORDS}, + {"delete", (PyCFunction)DB_delete, METH_VARARGS|METH_KEYWORDS}, + {"fd", (PyCFunction)DB_fd, METH_NOARGS}, ++#if (DBVER >= 46) ++ {"exists", (PyCFunction)DB_exists, ++ METH_VARARGS|METH_KEYWORDS}, ++#endif + {"get", (PyCFunction)DB_get, METH_VARARGS|METH_KEYWORDS}, + {"pget", (PyCFunction)DB_pget, METH_VARARGS|METH_KEYWORDS}, + {"get_both", (PyCFunction)DB_get_both, METH_VARARGS|METH_KEYWORDS}, +@@ -6424,9 +7266,14 @@ static PyMethodDef DB_methods[] = { + {"set_bt_minkey", (PyCFunction)DB_set_bt_minkey, METH_VARARGS}, + {"set_bt_compare", (PyCFunction)DB_set_bt_compare, METH_O}, + {"set_cachesize", (PyCFunction)DB_set_cachesize, METH_VARARGS}, +-#if (DBVER >= 41) ++#if (DBVER >= 42) ++ {"get_cachesize", (PyCFunction)DB_get_cachesize, METH_NOARGS}, ++#endif + {"set_encrypt", (PyCFunction)DB_set_encrypt, METH_VARARGS|METH_KEYWORDS}, ++#if (DBVER >= 42) ++ {"get_encrypt_flags", (PyCFunction)DB_get_encrypt_flags, METH_NOARGS}, + #endif ++ + {"set_flags", (PyCFunction)DB_set_flags, METH_VARARGS}, + {"set_h_ffactor", (PyCFunction)DB_set_h_ffactor, METH_VARARGS}, + {"set_h_nelem", (PyCFunction)DB_set_h_nelem, METH_VARARGS}, +@@ -6451,6 +7298,20 @@ static PyMethodDef DB_methods[] = { + }; + + ++/* We need this to support __contains__() */ ++static PySequenceMethods DB_sequence = { ++ 0, /* sq_length, mapping wins here */ ++ 0, /* sq_concat */ ++ 0, /* sq_repeat */ ++ 0, /* sq_item */ ++ 0, /* sq_slice */ ++ 0, /* sq_ass_item */ ++ 0, /* sq_ass_slice */ ++ (objobjproc)DB_contains, /* sq_contains */ ++ 0, /* sq_inplace_concat */ ++ 0, /* sq_inplace_repeat */ ++}; ++ + static PyMappingMethods DB_mapping = { + DB_length, /*mp_length*/ + (binaryfunc)DB_subscript, /*mp_subscript*/ +@@ -6481,8 +7342,17 @@ static PyMethodDef DBCursor_methods[] = + {"consume", (PyCFunction)DBC_consume, METH_VARARGS|METH_KEYWORDS}, + {"next_dup", (PyCFunction)DBC_next_dup, METH_VARARGS|METH_KEYWORDS}, + {"next_nodup", (PyCFunction)DBC_next_nodup, METH_VARARGS|METH_KEYWORDS}, ++#if (DBVER >= 46) ++ {"prev_dup", (PyCFunction)DBC_prev_dup, ++ METH_VARARGS|METH_KEYWORDS}, ++#endif + {"prev_nodup", (PyCFunction)DBC_prev_nodup, METH_VARARGS|METH_KEYWORDS}, + {"join_item", (PyCFunction)DBC_join_item, METH_VARARGS}, ++#if (DBVER >= 46) ++ {"set_priority", (PyCFunction)DBC_set_priority, ++ METH_VARARGS|METH_KEYWORDS}, ++ {"get_priority", (PyCFunction)DBC_get_priority, METH_NOARGS}, ++#endif + {NULL, NULL} /* sentinel */ + }; + +@@ -6491,57 +7361,94 @@ static PyMethodDef DBEnv_methods[] = { + {"close", (PyCFunction)DBEnv_close, METH_VARARGS}, + {"open", (PyCFunction)DBEnv_open, METH_VARARGS}, + {"remove", (PyCFunction)DBEnv_remove, METH_VARARGS}, +-#if (DBVER >= 41) + {"dbremove", (PyCFunction)DBEnv_dbremove, METH_VARARGS|METH_KEYWORDS}, + {"dbrename", (PyCFunction)DBEnv_dbrename, METH_VARARGS|METH_KEYWORDS}, + {"set_encrypt", (PyCFunction)DBEnv_set_encrypt, METH_VARARGS|METH_KEYWORDS}, ++#if (DBVER >= 42) ++ {"get_encrypt_flags", (PyCFunction)DBEnv_get_encrypt_flags, METH_NOARGS}, ++ {"get_timeout", (PyCFunction)DBEnv_get_timeout, ++ METH_VARARGS|METH_KEYWORDS}, ++#endif ++ {"set_timeout", (PyCFunction)DBEnv_set_timeout, METH_VARARGS|METH_KEYWORDS}, ++ {"set_shm_key", (PyCFunction)DBEnv_set_shm_key, METH_VARARGS}, ++#if (DBVER >= 42) ++ {"get_shm_key", (PyCFunction)DBEnv_get_shm_key, METH_NOARGS}, ++#endif ++ {"set_cachesize", (PyCFunction)DBEnv_set_cachesize, METH_VARARGS}, ++#if (DBVER >= 42) ++ {"get_cachesize", (PyCFunction)DBEnv_get_cachesize, METH_NOARGS}, ++#endif ++#if (DBVER >= 44) ++ {"mutex_set_max", (PyCFunction)DBEnv_mutex_set_max, METH_VARARGS}, ++ {"mutex_get_max", (PyCFunction)DBEnv_mutex_get_max, METH_NOARGS}, ++ {"mutex_set_align", (PyCFunction)DBEnv_mutex_set_align, METH_VARARGS}, ++ {"mutex_get_align", (PyCFunction)DBEnv_mutex_get_align, METH_NOARGS}, ++ {"mutex_set_increment", (PyCFunction)DBEnv_mutex_set_increment, ++ METH_VARARGS}, ++ {"mutex_get_increment", (PyCFunction)DBEnv_mutex_get_increment, ++ METH_NOARGS}, ++ {"mutex_set_tas_spins", (PyCFunction)DBEnv_mutex_set_tas_spins, ++ METH_VARARGS}, ++ {"mutex_get_tas_spins", (PyCFunction)DBEnv_mutex_get_tas_spins, ++ METH_NOARGS}, ++#endif ++ {"set_data_dir", (PyCFunction)DBEnv_set_data_dir, METH_VARARGS}, ++#if (DBVER >= 42) ++ {"get_data_dirs", (PyCFunction)DBEnv_get_data_dirs, METH_NOARGS}, + #endif +- {"set_timeout", (PyCFunction)DBEnv_set_timeout, METH_VARARGS|METH_KEYWORDS}, +- {"set_shm_key", (PyCFunction)DBEnv_set_shm_key, METH_VARARGS}, +- {"set_cachesize", (PyCFunction)DBEnv_set_cachesize, METH_VARARGS}, +- {"set_data_dir", (PyCFunction)DBEnv_set_data_dir, METH_VARARGS}, +- {"set_flags", (PyCFunction)DBEnv_set_flags, METH_VARARGS}, ++ {"set_flags", (PyCFunction)DBEnv_set_flags, METH_VARARGS}, + #if (DBVER >= 47) +- {"log_set_config", (PyCFunction)DBEnv_log_set_config, METH_VARARGS}, ++ {"log_set_config", (PyCFunction)DBEnv_log_set_config, METH_VARARGS}, + #endif +- {"set_lg_bsize", (PyCFunction)DBEnv_set_lg_bsize, METH_VARARGS}, +- {"set_lg_dir", (PyCFunction)DBEnv_set_lg_dir, METH_VARARGS}, +- {"set_lg_max", (PyCFunction)DBEnv_set_lg_max, METH_VARARGS}, ++ {"set_lg_bsize", (PyCFunction)DBEnv_set_lg_bsize, METH_VARARGS}, ++ {"set_lg_dir", (PyCFunction)DBEnv_set_lg_dir, METH_VARARGS}, ++ {"set_lg_max", (PyCFunction)DBEnv_set_lg_max, METH_VARARGS}, + #if (DBVER >= 42) +- {"get_lg_max", (PyCFunction)DBEnv_get_lg_max, METH_NOARGS}, ++ {"get_lg_max", (PyCFunction)DBEnv_get_lg_max, METH_NOARGS}, + #endif + {"set_lg_regionmax",(PyCFunction)DBEnv_set_lg_regionmax, METH_VARARGS}, +- {"set_lk_detect", (PyCFunction)DBEnv_set_lk_detect, METH_VARARGS}, ++ {"set_lk_detect", (PyCFunction)DBEnv_set_lk_detect, METH_VARARGS}, + #if (DBVER < 45) +- {"set_lk_max", (PyCFunction)DBEnv_set_lk_max, METH_VARARGS}, ++ {"set_lk_max", (PyCFunction)DBEnv_set_lk_max, METH_VARARGS}, + #endif + {"set_lk_max_locks", (PyCFunction)DBEnv_set_lk_max_locks, METH_VARARGS}, + {"set_lk_max_lockers", (PyCFunction)DBEnv_set_lk_max_lockers, METH_VARARGS}, + {"set_lk_max_objects", (PyCFunction)DBEnv_set_lk_max_objects, METH_VARARGS}, +- {"set_mp_mmapsize", (PyCFunction)DBEnv_set_mp_mmapsize, METH_VARARGS}, +- {"set_tmp_dir", (PyCFunction)DBEnv_set_tmp_dir, METH_VARARGS}, +- {"txn_begin", (PyCFunction)DBEnv_txn_begin, METH_VARARGS|METH_KEYWORDS}, +- {"txn_checkpoint", (PyCFunction)DBEnv_txn_checkpoint, METH_VARARGS}, +- {"txn_stat", (PyCFunction)DBEnv_txn_stat, METH_VARARGS}, +- {"set_tx_max", (PyCFunction)DBEnv_set_tx_max, METH_VARARGS}, ++ {"set_mp_mmapsize", (PyCFunction)DBEnv_set_mp_mmapsize, METH_VARARGS}, ++ {"set_tmp_dir", (PyCFunction)DBEnv_set_tmp_dir, METH_VARARGS}, ++ {"txn_begin", (PyCFunction)DBEnv_txn_begin, METH_VARARGS|METH_KEYWORDS}, ++ {"txn_checkpoint", (PyCFunction)DBEnv_txn_checkpoint, METH_VARARGS}, ++ {"txn_stat", (PyCFunction)DBEnv_txn_stat, METH_VARARGS}, ++#if (DBVER >= 43) ++ {"txn_stat_print", (PyCFunction)DBEnv_txn_stat_print, ++ METH_VARARGS|METH_KEYWORDS}, ++#endif ++#if (DBVER >= 42) ++ {"get_tx_max", (PyCFunction)DBEnv_get_tx_max, METH_NOARGS}, ++ {"get_tx_timestamp", (PyCFunction)DBEnv_get_tx_timestamp, METH_NOARGS}, ++#endif ++ {"set_tx_max", (PyCFunction)DBEnv_set_tx_max, METH_VARARGS}, + {"set_tx_timestamp", (PyCFunction)DBEnv_set_tx_timestamp, METH_VARARGS}, +- {"lock_detect", (PyCFunction)DBEnv_lock_detect, METH_VARARGS}, +- {"lock_get", (PyCFunction)DBEnv_lock_get, METH_VARARGS}, +- {"lock_id", (PyCFunction)DBEnv_lock_id, METH_NOARGS}, +- {"lock_id_free", (PyCFunction)DBEnv_lock_id_free, METH_VARARGS}, +- {"lock_put", (PyCFunction)DBEnv_lock_put, METH_VARARGS}, +- {"lock_stat", (PyCFunction)DBEnv_lock_stat, METH_VARARGS}, +- {"log_archive", (PyCFunction)DBEnv_log_archive, METH_VARARGS}, +- {"log_flush", (PyCFunction)DBEnv_log_flush, METH_NOARGS}, +- {"log_stat", (PyCFunction)DBEnv_log_stat, METH_VARARGS}, ++ {"lock_detect", (PyCFunction)DBEnv_lock_detect, METH_VARARGS}, ++ {"lock_get", (PyCFunction)DBEnv_lock_get, METH_VARARGS}, ++ {"lock_id", (PyCFunction)DBEnv_lock_id, METH_NOARGS}, ++ {"lock_id_free", (PyCFunction)DBEnv_lock_id_free, METH_VARARGS}, ++ {"lock_put", (PyCFunction)DBEnv_lock_put, METH_VARARGS}, ++ {"lock_stat", (PyCFunction)DBEnv_lock_stat, METH_VARARGS}, ++ {"log_archive", (PyCFunction)DBEnv_log_archive, METH_VARARGS}, ++ {"log_flush", (PyCFunction)DBEnv_log_flush, METH_NOARGS}, ++ {"log_stat", (PyCFunction)DBEnv_log_stat, METH_VARARGS}, + #if (DBVER >= 44) +- {"lsn_reset", (PyCFunction)DBEnv_lsn_reset, METH_VARARGS|METH_KEYWORDS}, ++ {"fileid_reset", (PyCFunction)DBEnv_fileid_reset, METH_VARARGS|METH_KEYWORDS}, ++ {"lsn_reset", (PyCFunction)DBEnv_lsn_reset, METH_VARARGS|METH_KEYWORDS}, + #endif + {"set_get_returns_none",(PyCFunction)DBEnv_set_get_returns_none, METH_VARARGS}, +- {"txn_recover", (PyCFunction)DBEnv_txn_recover, METH_NOARGS}, ++ {"txn_recover", (PyCFunction)DBEnv_txn_recover, METH_NOARGS}, ++#if (DBVER < 48) + {"set_rpc_server", (PyCFunction)DBEnv_set_rpc_server, + METH_VARARGS||METH_KEYWORDS}, +- {"set_verbose", (PyCFunction)DBEnv_set_verbose, METH_VARARGS}, ++#endif ++ {"set_verbose", (PyCFunction)DBEnv_set_verbose, METH_VARARGS}, + #if (DBVER >= 42) + {"get_verbose", (PyCFunction)DBEnv_get_verbose, METH_VARARGS}, + #endif +@@ -6579,6 +7486,17 @@ static PyMethodDef DBEnv_methods[] = { + {"rep_set_timeout", (PyCFunction)DBEnv_rep_set_timeout, METH_VARARGS}, + {"rep_get_timeout", (PyCFunction)DBEnv_rep_get_timeout, METH_VARARGS}, + #endif ++#if (DBVER >= 47) ++ {"rep_set_clockskew", (PyCFunction)DBEnv_rep_set_clockskew, METH_VARARGS}, ++ {"rep_get_clockskew", (PyCFunction)DBEnv_rep_get_clockskew, METH_VARARGS}, ++#endif ++ {"rep_stat", (PyCFunction)DBEnv_rep_stat, ++ METH_VARARGS|METH_KEYWORDS}, ++#if (DBVER >= 43) ++ {"rep_stat_print", (PyCFunction)DBEnv_rep_stat_print, ++ METH_VARARGS|METH_KEYWORDS}, ++#endif ++ + #if (DBVER >= 45) + {"repmgr_start", (PyCFunction)DBEnv_repmgr_start, + METH_VARARGS|METH_KEYWORDS}, +@@ -6609,6 +7527,12 @@ static PyMethodDef DBTxn_methods[] = { + {"discard", (PyCFunction)DBTxn_discard, METH_NOARGS}, + {"abort", (PyCFunction)DBTxn_abort, METH_NOARGS}, + {"id", (PyCFunction)DBTxn_id, METH_NOARGS}, ++ {"set_timeout", (PyCFunction)DBTxn_set_timeout, ++ METH_VARARGS|METH_KEYWORDS}, ++#if (DBVER >= 44) ++ {"set_name", (PyCFunction)DBTxn_set_name, METH_VARARGS}, ++ {"get_name", (PyCFunction)DBTxn_get_name, METH_NOARGS}, ++#endif + {NULL, NULL} /* sentinel */ + }; + +@@ -6619,7 +7543,7 @@ static PyMethodDef DBSequence_methods[] + {"get", (PyCFunction)DBSequence_get, METH_VARARGS|METH_KEYWORDS}, + {"get_dbp", (PyCFunction)DBSequence_get_dbp, METH_NOARGS}, + {"get_key", (PyCFunction)DBSequence_get_key, METH_NOARGS}, +- {"init_value", (PyCFunction)DBSequence_init_value, METH_VARARGS}, ++ {"initial_value", (PyCFunction)DBSequence_initial_value, METH_VARARGS}, + {"open", (PyCFunction)DBSequence_open, METH_VARARGS|METH_KEYWORDS}, + {"remove", (PyCFunction)DBSequence_remove, METH_VARARGS|METH_KEYWORDS}, + {"set_cachesize", (PyCFunction)DBSequence_set_cachesize, METH_VARARGS}, +@@ -6629,6 +7553,8 @@ static PyMethodDef DBSequence_methods[] + {"set_range", (PyCFunction)DBSequence_set_range, METH_VARARGS}, + {"get_range", (PyCFunction)DBSequence_get_range, METH_NOARGS}, + {"stat", (PyCFunction)DBSequence_stat, METH_VARARGS|METH_KEYWORDS}, ++ {"stat_print", (PyCFunction)DBSequence_stat_print, ++ METH_VARARGS|METH_KEYWORDS}, + {NULL, NULL} /* sentinel */ + }; + #endif +@@ -6677,7 +7603,7 @@ statichere PyTypeObject DB_Type = { + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ +- 0, /*tp_as_sequence*/ ++ &DB_sequence,/*tp_as_sequence*/ + &DB_mapping,/*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /* tp_call */ +@@ -7029,10 +7955,21 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + { + PyObject* m; + PyObject* d; +- PyObject* pybsddb_version_s = PyBytes_FromString( PY_BSDDB_VERSION ); +- PyObject* db_version_s = PyBytes_FromString( DB_VERSION_STRING ); +- PyObject* cvsid_s = PyBytes_FromString( rcs_id ); + PyObject* py_api; ++ PyObject* pybsddb_version_s; ++ PyObject* db_version_s; ++ PyObject* cvsid_s; ++ ++#if (PY_VERSION_HEX < 0x03000000) ++ pybsddb_version_s = PyString_FromString(PY_BSDDB_VERSION); ++ db_version_s = PyString_FromString(DB_VERSION_STRING); ++ cvsid_s = PyString_FromString(rcs_id); ++#else ++ /* This data should be ascii, so UTF-8 conversion is fine */ ++ pybsddb_version_s = PyUnicode_FromString(PY_BSDDB_VERSION); ++ db_version_s = PyUnicode_FromString(DB_VERSION_STRING); ++ cvsid_s = PyUnicode_FromString(rcs_id); ++#endif + + /* Initialize object types */ + if ((PyType_Ready(&DB_Type) < 0) +@@ -7089,6 +8026,7 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + ADD_INT(d, DB_MAX_PAGES); + ADD_INT(d, DB_MAX_RECORDS); + ++#if (DBVER < 48) + #if (DBVER >= 42) + ADD_INT(d, DB_RPCCLIENT); + #else +@@ -7096,7 +8034,11 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + /* allow apps to be written using DB_RPCCLIENT on older Berkeley DB */ + _addIntToDict(d, "DB_RPCCLIENT", DB_CLIENT); + #endif ++#endif ++ ++#if (DBVER < 48) + ADD_INT(d, DB_XA_CREATE); ++#endif + + ADD_INT(d, DB_CREATE); + ADD_INT(d, DB_NOMMAP); +@@ -7113,7 +8055,13 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + ADD_INT(d, DB_INIT_TXN); + ADD_INT(d, DB_JOINENV); + ++#if (DBVER >= 48) ++ ADD_INT(d, DB_GID_SIZE); ++#else + ADD_INT(d, DB_XIDDATASIZE); ++ /* Allow new code to work in old BDB releases */ ++ _addIntToDict(d, "DB_GID_SIZE", DB_XIDDATASIZE); ++#endif + + ADD_INT(d, DB_RECOVER); + ADD_INT(d, DB_RECOVER_FATAL); +@@ -7128,6 +8076,10 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + ADD_INT(d, DB_TXN_SYNC); + ADD_INT(d, DB_TXN_NOWAIT); + ++#if (DBVER >= 46) ++ ADD_INT(d, DB_TXN_WAIT); ++#endif ++ + ADD_INT(d, DB_EXCL); + ADD_INT(d, DB_FCNTL_LOCKING); + ADD_INT(d, DB_ODDFILESIZE); +@@ -7233,12 +8185,6 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + ADD_INT(d, DB_CACHED_COUNTS); + #endif + +-#if (DBVER >= 41) +- _addIntToDict(d, "DB_CHECKPOINT", 0); +-#else +- ADD_INT(d, DB_CHECKPOINT); +- ADD_INT(d, DB_CURLSN); +-#endif + #if (DBVER <= 41) + ADD_INT(d, DB_COMMIT); + #endif +@@ -7249,6 +8195,7 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + ADD_INT(d, DB_FIRST); + ADD_INT(d, DB_FLUSH); + ADD_INT(d, DB_GET_BOTH); ++ ADD_INT(d, DB_GET_BOTH_RANGE); + ADD_INT(d, DB_GET_RECNO); + ADD_INT(d, DB_JOIN_ITEM); + ADD_INT(d, DB_KEYFIRST); +@@ -7263,6 +8210,9 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + ADD_INT(d, DB_POSITION); + ADD_INT(d, DB_PREV); + ADD_INT(d, DB_PREV_NODUP); ++#if (DBVER >= 46) ++ ADD_INT(d, DB_PREV_DUP); ++#endif + #if (DBVER < 45) + ADD_INT(d, DB_RECORDCOUNT); + #endif +@@ -7278,17 +8228,18 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + ADD_INT(d, DB_MULTIPLE_KEY); + + #if (DBVER >= 44) ++ ADD_INT(d, DB_IMMUTABLE_KEY); + ADD_INT(d, DB_READ_UNCOMMITTED); /* replaces DB_DIRTY_READ in 4.4 */ + ADD_INT(d, DB_READ_COMMITTED); + #endif + ++#if (DBVER >= 44) ++ ADD_INT(d, DB_FREELIST_ONLY); ++ ADD_INT(d, DB_FREE_SPACE); ++#endif ++ + ADD_INT(d, DB_DONOTINDEX); + +-#if (DBVER >= 41) +- _addIntToDict(d, "DB_INCOMPLETE", 0); +-#else +- ADD_INT(d, DB_INCOMPLETE); +-#endif + ADD_INT(d, DB_KEYEMPTY); + ADD_INT(d, DB_KEYEXIST); + ADD_INT(d, DB_LOCK_DEADLOCK); +@@ -7309,14 +8260,15 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + ADD_INT(d, DB_PANIC_ENVIRONMENT); + ADD_INT(d, DB_NOPANIC); + +-#if (DBVER >= 41) + ADD_INT(d, DB_OVERWRITE); +-#endif + +-#ifdef DB_REGISTER ++#if (DBVER >= 44) + ADD_INT(d, DB_REGISTER); + #endif + ++ ADD_INT(d, DB_EID_INVALID); ++ ADD_INT(d, DB_EID_BROADCAST); ++ + #if (DBVER >= 42) + ADD_INT(d, DB_TIME_NOTGRANTED); + ADD_INT(d, DB_TXN_NOT_DURABLE); +@@ -7389,6 +8341,32 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + + ADD_INT(d, DB_REP_MASTER); + ADD_INT(d, DB_REP_CLIENT); ++ ++ ADD_INT(d, DB_REP_PERMANENT); ++ ++#if (DBVER >= 44) ++ ADD_INT(d, DB_REP_CONF_NOAUTOINIT); ++ ADD_INT(d, DB_REP_CONF_DELAYCLIENT); ++ ADD_INT(d, DB_REP_CONF_BULK); ++ ADD_INT(d, DB_REP_CONF_NOWAIT); ++ ADD_INT(d, DB_REP_ANYWHERE); ++ ADD_INT(d, DB_REP_REREQUEST); ++#endif ++ ++#if (DBVER >= 42) ++ ADD_INT(d, DB_REP_NOBUFFER); ++#endif ++ ++#if (DBVER >= 46) ++ ADD_INT(d, DB_REP_LEASE_EXPIRED); ++ ADD_INT(d, DB_IGNORE_LEASE); ++#endif ++ ++#if (DBVER >= 47) ++ ADD_INT(d, DB_REP_CONF_LEASE); ++ ADD_INT(d, DB_REPMGR_CONF_2SITE_STRICT); ++#endif ++ + #if (DBVER >= 45) + ADD_INT(d, DB_REP_ELECTION); + +@@ -7400,6 +8378,11 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + #if (DBVER >= 46) + ADD_INT(d, DB_REP_CHECKPOINT_DELAY); + ADD_INT(d, DB_REP_FULL_ELECTION_TIMEOUT); ++ ADD_INT(d, DB_REP_LEASE_TIMEOUT); ++#endif ++#if (DBVER >= 47) ++ ADD_INT(d, DB_REP_HEARTBEAT_MONITOR); ++ ADD_INT(d, DB_REP_HEARTBEAT_SEND); + #endif + + #if (DBVER >= 45) +@@ -7412,7 +8395,6 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + ADD_INT(d, DB_REPMGR_ACKS_QUORUM); + ADD_INT(d, DB_REPMGR_CONNECTED); + ADD_INT(d, DB_REPMGR_DISCONNECTED); +- ADD_INT(d, DB_STAT_CLEAR); + ADD_INT(d, DB_STAT_ALL); + #endif + +@@ -7428,12 +8410,16 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + ADD_INT(d, DB_DSYNC_LOG); + #endif + +-#if (DBVER >= 41) + ADD_INT(d, DB_ENCRYPT_AES); + ADD_INT(d, DB_AUTO_COMMIT); +-#else +- /* allow Berkeley DB 4.1 aware apps to run on older versions */ +- _addIntToDict(d, "DB_AUTO_COMMIT", 0); ++ ADD_INT(d, DB_PRIORITY_VERY_LOW); ++ ADD_INT(d, DB_PRIORITY_LOW); ++ ADD_INT(d, DB_PRIORITY_DEFAULT); ++ ADD_INT(d, DB_PRIORITY_HIGH); ++ ADD_INT(d, DB_PRIORITY_VERY_HIGH); ++ ++#if (DBVER >= 46) ++ ADD_INT(d, DB_PRIORITY_UNCHANGED); + #endif + + ADD_INT(d, EINVAL); +@@ -7497,10 +8483,6 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + } + #endif + +- +-#if !INCOMPLETE_IS_WARNING +- MAKE_EX(DBIncompleteError); +-#endif + MAKE_EX(DBCursorClosedError); + MAKE_EX(DBKeyEmptyError); + MAKE_EX(DBKeyExistError); +@@ -7528,9 +8510,16 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + #if (DBVER >= 42) + MAKE_EX(DBRepHandleDeadError); + #endif ++#if (DBVER >= 44) ++ MAKE_EX(DBRepLockoutError); ++#endif + + MAKE_EX(DBRepUnavailError); + ++#if (DBVER >= 46) ++ MAKE_EX(DBRepLeaseExpiredError); ++#endif ++ + #undef MAKE_EX + + /* Initiliase the C API structure and add it to the module */ +@@ -7544,7 +8533,24 @@ PyMODINIT_FUNC PyInit__bsddb(void) / + #endif + bsddb_api.makeDBError = makeDBError; + ++ /* ++ ** Capsules exist from Python 3.1, but I ++ ** don't want to break the API compatibility ++ ** for already published Python versions. ++ */ ++#if (PY_VERSION_HEX < 0x03020000) + py_api = PyCObject_FromVoidPtr((void*)&bsddb_api, NULL); ++#else ++ { ++ char py_api_name[250]; ++ ++ strcpy(py_api_name, _bsddbModuleName); ++ strcat(py_api_name, ".api"); ++ ++ py_api = PyCapsule_New((void*)&bsddb_api, py_api_name, NULL); ++ } ++#endif ++ + PyDict_SetItemString(d, "api", py_api); + Py_DECREF(py_api); + +diff -Nupr Python-2.6.4.orig/Modules/bsddb.h Python-2.6.4/Modules/bsddb.h +--- Python-2.6.4.orig/Modules/bsddb.h 2008-09-28 19:24:19.000000000 -0400 ++++ Python-2.6.4/Modules/bsddb.h 2009-12-04 07:34:56.000000000 -0500 +@@ -105,7 +105,7 @@ + #error "eek! DBVER can't handle minor versions > 9" + #endif + +-#define PY_BSDDB_VERSION "4.7.3" ++#define PY_BSDDB_VERSION "4.8.1" + + /* Python object definitions */ + +@@ -220,6 +220,7 @@ typedef struct DBSequenceObject { + /* To access the structure from an external module, use code like the + following (error checking missed out for clarity): + ++ // If you are using Python 3.2: + BSDDB_api* bsddb_api; + PyObject* mod; + PyObject* cobj; +@@ -231,6 +232,15 @@ typedef struct DBSequenceObject { + Py_DECREF(cobj); + Py_DECREF(mod); + ++ ++ // If you are using Python 3.2 or up: ++ BSDDB_api* bsddb_api; ++ ++ // Use "bsddb3._pybsddb.api" if you're using ++ // the standalone pybsddb add-on. ++ bsddb_api = (void **)PyCapsule_Import("bsddb._bsddb.api", 1); ++ ++ + The structure's members must not be changed. + */ + +@@ -247,7 +257,6 @@ typedef struct { + + /* Functions */ + int (*makeDBError)(int err); +- + } BSDDB_api; + + diff --git a/python-2.6.4-setup-db48.patch b/python-2.6.4-setup-db48.patch new file mode 100644 index 0000000..187f239 --- /dev/null +++ b/python-2.6.4-setup-db48.patch @@ -0,0 +1,27 @@ +diff -up Python-2.6.4/Modules/Setup.dist.setup-db48 Python-2.6.4/Modules/Setup.dist +--- Python-2.6.4/Modules/Setup.dist.setup-db48 2009-12-17 22:05:07.000020150 -0500 ++++ Python-2.6.4/Modules/Setup.dist 2009-12-17 22:05:12.545015367 -0500 +@@ -411,7 +411,7 @@ gdbm gdbmmodule.c -lgdbm + # + # Edit the variables DB and DBLIBVERto point to the db top directory + # and the subdirectory of PORT where you built it. +-DBLIBVER=4.7 ++DBLIBVER=4.8 + DBINC=/usr/include/db4 + DBLIB=/usr/lib + _bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb-$(DBLIBVER) +diff -up Python-2.6.4/setup.py.setup-db48 Python-2.6.4/setup.py +--- Python-2.6.4/setup.py.setup-db48 2009-12-17 22:03:58.048015993 -0500 ++++ Python-2.6.4/setup.py 2009-12-17 22:03:58.169016398 -0500 +@@ -705,9 +705,9 @@ class PyBuildExt(build_ext): + # a release. Most open source OSes come with one or more + # versions of BerkeleyDB already installed. + +- max_db_ver = (4, 7) ++ max_db_ver = (4, 8) + min_db_ver = (3, 3) +- db_setup_debug = False # verbose debug prints from this script? ++ db_setup_debug = True # verbose debug prints from this script? + + def allow_db_ver(db_ver): + """Returns a boolean if the given BerkeleyDB version is acceptable. diff --git a/python.spec b/python.spec index 2bf3fba..631b285 100644 --- a/python.spec +++ b/python.spec @@ -22,7 +22,7 @@ Summary: An interpreted, interactive, object-oriented programming language Name: %{python} Version: 2.6.4 -Release: 3%{?dist} +Release: 4%{?dist} License: Python Group: Development/Languages Provides: python-abi = %{pybasever} @@ -49,13 +49,24 @@ Patch16: python-2.6-rpath.patch # Fix distutils to follow the Fedora/RHEL/CentOS policies of having .pyo files Patch51: python-2.6-distutils_rpm.patch +# Automatically disable arena allocator when run under valgrind: +# From http://bugs.python.org/issue2422 +# http://bugs.python.org/file9872/disable-pymalloc-on-valgrind-py26.patch +# with the "configure" part removed; appears to be identical to the version committed to 2.7 +Patch52: disable-pymalloc-on-valgrind-py26.patch + + +# Patch generated by jwboyer@gmail.com to compile against db-4.8, using upstream +# http://www.jcea.es/programacion/pybsddb.htm +# See https://bugzilla.redhat.com/show_bug.cgi?id=544275 +Patch53: python-2.6-update-bsddb3-4.8.patch +# ...and a further patch to setup.py so that it searches for 4.8: +Patch54: python-2.6.4-setup-db48.patch + # upstreamed #Patch50: python-2.5-disable-egginfo.patch -# new db version -#Patch60: python-2.5.2-db47.patch - # lib64 patches Patch101: python-2.3.4-lib64-regex.patch Patch102: python-2.6-lib64.patch @@ -93,8 +104,9 @@ BuildRequires: libGL-devel tk tix gcc-c++ libX11-devel glibc-devel BuildRequires: bzip2 tar /usr/bin/find pkgconfig tcl-devel tk-devel BuildRequires: tix-devel bzip2-devel sqlite-devel BuildRequires: autoconf -BuildRequires: db4-devel >= 4.7 +BuildRequires: db4-devel >= 4.8 BuildRequires: libffi-devel +BuildRequires: valgrind-devel URL: http://www.python.org/ @@ -211,7 +223,6 @@ code that uses more than just unittest and/or test_support.py. # Try not disabling egg-infos, bz#414711 #patch50 -p1 -b .egginfo -#%%patch60 -p1 -b .db47 %if "%{_lib}" == "lib64" %patch101 -p1 -b .lib64-regex @@ -227,6 +238,9 @@ code that uses more than just unittest and/or test_support.py. %patch16 -p1 -b .rpath %patch51 -p1 -b .brprpm +%patch52 -p0 -b .valgrind +%patch53 -p1 -b .db48 +%patch54 -p1 -b .setup-db48 %ifarch alpha ia64 # 64bit, but not lib64 arches need this too... @@ -256,9 +270,9 @@ if pkg-config openssl ; then fi # Force CC export CC=gcc -# For patch 4, need to get a newer configure generated out of configure.in +# For patches 4 and 52, need to get a newer configure generated out of configure.in autoconf -%configure --enable-ipv6 --enable-unicode=%{unicode} --enable-shared --with-system-ffi +%configure --enable-ipv6 --enable-unicode=%{unicode} --enable-shared --with-system-ffi --with-valgrind make OPT="$CFLAGS" %{?_smp_mflags} LD_LIBRARY_PATH=$topdir $topdir/python Tools/scripts/pathfix.py -i "%{_bindir}/env python%{pybasever}" . @@ -550,6 +564,15 @@ rm -fr $RPM_BUILD_ROOT %{_libdir}/python%{pybasever}/lib-dynload/_testcapimodule.so %changelog +* Wed Dec 16 2009 David Malcolm - 2.6.4-4 +- automatically disable arena allocator when run under valgrind (upstream +issue 2422; patch 52) +- add patch from Josh Boyer containing diff against upstream PyBSDDB to make +the bsddb module compile against db-4.8 (patch 53, #544275); bump the necessary +version of db4-devel to 4.8 +- patch setup.py so that it searches for db-4.8, and enable debug output for +said search; make Setup.dist use db-4.8 (patch 54) + * Thu Nov 12 2009 David Malcolm - 2.6.4-3 - fixup the build when __python_ver is set (Zach Sadecki; bug 533989); use pybasever in the files section