[Python-checkins] r63207 - in python/trunk: Misc/NEWS Modules/_bsddb.c Modules/bsddb.h

jesus.cea python-checkins at python.org
Tue May 13 20:45:47 CEST 2008


Author: jesus.cea
Date: Tue May 13 20:45:46 2008
New Revision: 63207

Log:
bsddb module updated to version 4.6.4

Modified:
   python/trunk/Misc/NEWS
   python/trunk/Modules/_bsddb.c
   python/trunk/Modules/bsddb.h

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Tue May 13 20:45:46 2008
@@ -25,6 +25,8 @@
 
 - Support for Windows9x has been removed from the winsound module.
 
+- bsddb module updated to version 4.6.4.
+
 Library
 -------
 

Modified: python/trunk/Modules/_bsddb.c
==============================================================================
--- python/trunk/Modules/_bsddb.c	(original)
+++ python/trunk/Modules/_bsddb.c	Tue May 13 20:45:46 2008
@@ -36,7 +36,7 @@
 /*
  * Handwritten code to wrap version 3.x of the Berkeley DB library,
  * written to replace a SWIG-generated file.  It has since been updated
- * to compile with BerkeleyDB versions 3.2 through 4.2.
+ * to compile with Berkeley DB versions 3.2 through 4.2.
  *
  * This module was started by Andrew Kuchling to remove the dependency
  * on SWIG in a package by Gregory P. Smith who based his work on a
@@ -48,7 +48,10 @@
  * the DB 3.x API and to build a solid unit test suite.  Robin has
  * since gone onto other projects (wxPython).
  *
- * Gregory P. Smith <greg at krypto.org> is once again the maintainer.
+ * Gregory P. Smith <greg at krypto.org> was once again the maintainer.
+ *
+ * Since January 2008, new maintainer is Jesus Cea <jcea at argo.es>.
+ * Jesus Cea licenses this code to PSF under a Contributor Agreement.
  *
  * Use the pybsddb-users at lists.sf.net mailing list for all questions.
  * Things can change faster than the header of this file is updated.  This
@@ -183,6 +186,10 @@
 static PyObject* DBNoSuchFileError;     /* ENOENT */
 static PyObject* DBPermissionsError;    /* EPERM  */
 
+#if (DBVER >= 42)
+static PyObject* DBRepHandleDeadError;  /* DB_REP_HANDLE_DEAD */
+#endif
+
 #if (DBVER < 43)
 #define	DB_BUFFER_SMALL		ENOMEM
 #endif
@@ -202,6 +209,9 @@
 
 
 staticforward PyTypeObject DB_Type, DBCursor_Type, DBEnv_Type, DBTxn_Type, DBLock_Type;
+#if (DBVER >= 43)
+staticforward PyTypeObject DBSequence_Type;
+#endif
 
 #ifndef Py_TYPE
 /* for compatibility with Python 2.5 and earlier */
@@ -217,10 +227,77 @@
 #define DBSequenceObject_Check(v)   (Py_TYPE(v) == &DBSequence_Type)
 #endif
 
+#if (DBVER < 46)
+  #define _DBC_close(dbc)           dbc->c_close(dbc)
+  #define _DBC_count(dbc,a,b)       dbc->c_count(dbc,a,b)
+  #define _DBC_del(dbc,a)           dbc->c_del(dbc,a)
+  #define _DBC_dup(dbc,a,b)         dbc->c_dup(dbc,a,b)
+  #define _DBC_get(dbc,a,b,c)       dbc->c_get(dbc,a,b,c)
+  #define _DBC_pget(dbc,a,b,c,d)    dbc->c_pget(dbc,a,b,c,d)
+  #define _DBC_put(dbc,a,b,c)       dbc->c_put(dbc,a,b,c)
+#else
+  #define _DBC_close(dbc)           dbc->close(dbc)
+  #define _DBC_count(dbc,a,b)       dbc->count(dbc,a,b)
+  #define _DBC_del(dbc,a)           dbc->del(dbc,a)
+  #define _DBC_dup(dbc,a,b)         dbc->dup(dbc,a,b)
+  #define _DBC_get(dbc,a,b,c)       dbc->get(dbc,a,b,c)
+  #define _DBC_pget(dbc,a,b,c,d)    dbc->pget(dbc,a,b,c,d)
+  #define _DBC_put(dbc,a,b,c)       dbc->put(dbc,a,b,c)
+#endif
+
 
 /* --------------------------------------------------------------------- */
 /* Utility macros and functions */
 
+#define INSERT_IN_DOUBLE_LINKED_LIST(backlink,object)                   \
+    {                                                                   \
+        object->sibling_next=backlink;                                  \
+        object->sibling_prev_p=&(backlink);                             \
+        backlink=object;                                                \
+        if (object->sibling_next) {                                     \
+          object->sibling_next->sibling_prev_p=&(object->sibling_next); \
+        }                                                               \
+    }
+
+#define EXTRACT_FROM_DOUBLE_LINKED_LIST(object)                          \
+    {                                                                    \
+        if (object->sibling_next) {                                      \
+            object->sibling_next->sibling_prev_p=object->sibling_prev_p; \
+        }                                                                \
+        *(object->sibling_prev_p)=object->sibling_next;                  \
+    }
+
+#define EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(object)               \
+    {                                                                    \
+        if (object->sibling_next) {                                      \
+            object->sibling_next->sibling_prev_p=object->sibling_prev_p; \
+        }                                                                \
+        if (object->sibling_prev_p) {                                    \
+            *(object->sibling_prev_p)=object->sibling_next;              \
+        }                                                                \
+    }
+
+#define INSERT_IN_DOUBLE_LINKED_LIST_TXN(backlink,object)  \
+    {                                                      \
+        object->sibling_next_txn=backlink;                 \
+        object->sibling_prev_p_txn=&(backlink);            \
+        backlink=object;                                   \
+        if (object->sibling_next_txn) {                    \
+            object->sibling_next_txn->sibling_prev_p_txn=  \
+                &(object->sibling_next_txn);               \
+        }                                                  \
+    }
+
+#define EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(object)             \
+    {                                                           \
+        if (object->sibling_next_txn) {                         \
+            object->sibling_next_txn->sibling_prev_p_txn=       \
+                object->sibling_prev_p_txn;                     \
+        }                                                       \
+        *(object->sibling_prev_p_txn)=object->sibling_next_txn; \
+    }
+
+
 #define RETURN_IF_ERR()          \
     if (makeDBError(err)) {      \
         return NULL;             \
@@ -443,6 +520,66 @@
 }
 
 
+/*
+** We need these functions because some results
+** are undefined if pointer is NULL. Some other
+** give None instead of "".
+**
+** This functions are static and will be
+** -I hope- inlined.
+*/
+static const char *DummyString = "This string is a simple placeholder";
+static PyObject *Build_PyString(const char *p,int s)
+{
+  if (!p) {
+    p=DummyString;
+    assert(s==0);
+  }
+  return PyString_FromStringAndSize(p,s);
+}
+
+static PyObject *BuildValue_S(const void *p,int s)
+{
+  if (!p) {
+    p=DummyString;
+    assert(s==0);
+  }
+  return Py_BuildValue("s#",p,s);
+}
+
+static PyObject *BuildValue_SS(const void *p1,int s1,const void *p2,int s2)
+{
+  if (!p1) {
+    p1=DummyString;
+    assert(s1==0);
+  }
+  if (!p2) {
+    p2=DummyString;
+    assert(s2==0);
+  }
+  return Py_BuildValue("s#s#",p1,s1,p2,s2);
+}
+
+static PyObject *BuildValue_IS(int i,const void *p,int s)
+{
+  if (!p) {
+    p=DummyString;
+    assert(s==0);
+  }
+  return Py_BuildValue("is#",i,p,s);
+}
+
+static PyObject *BuildValue_LS(long i,const void *p,int s)
+{
+  if (!p) {
+    p=DummyString;
+    assert(s==0);
+  }
+  return Py_BuildValue("ls#",i,p,s);
+}
+
+
+
 /* make a nice exception object to raise for errors. */
 static int makeDBError(int err)
 {
@@ -505,6 +642,10 @@
         case ENOENT:  errObj = DBNoSuchFileError;   break;
         case EPERM :  errObj = DBPermissionsError;  break;
 
+#if (DBVER >= 42)
+        case DB_REP_HANDLE_DEAD : errObj = DBRepHandleDeadError; break;
+#endif
+
         default:      errObj = DBError;             break;
     }
 
@@ -608,16 +749,11 @@
     flags |= extra_flags;
     CLEAR_DBT(key);
     CLEAR_DBT(data);
-    if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
-        data.flags = DB_DBT_MALLOC;
-        key.flags = DB_DBT_MALLOC;
-    }
     if (!add_partial_dbt(&data, dlen, doff))
         return NULL;
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_get(self->dbc, &key, &data, flags);
+    err = _DBC_get(self->dbc, &key, &data, flags);
     MYDB_END_ALLOW_THREADS;
 
     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
@@ -638,21 +774,15 @@
 
         case DB_RECNO:
         case DB_QUEUE:
-            retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
-                                   data.data, data.size);
+            retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
             break;
         case DB_HASH:
         case DB_BTREE:
         default:
-            retval = Py_BuildValue("s#s#", key.data, key.size,
-                                   data.data, data.size);
+            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
             break;
         }
     }
-    if (!err) {
-        FREE_DBT(key);
-        FREE_DBT(data);
-    }
     return retval;
 }
 
@@ -672,7 +802,7 @@
 {
     PyObject* v;
 	/* if the value fits in regular int, use that. */
-#ifdef HAVE_LONG_LONG
+#ifdef PY_LONG_LONG
 	if (sizeof(time_t) > sizeof(long))
 		v = PyLong_FromLongLong((PY_LONG_LONG) value);
 	else
@@ -696,7 +826,16 @@
 }
 #endif
 
+#if (DBVER >= 40)
+static void _addDB_lsnToDict(PyObject* dict, char *name, DB_LSN value)
+{
+    PyObject *v = Py_BuildValue("(ll)",value.file,value.offset);
+    if (!v || PyDict_SetItemString(dict, name, v))
+        PyErr_Clear();
 
+    Py_XDECREF(v);
+}
+#endif
 
 /* --------------------------------------------------------------------- */
 /* Allocators and deallocators */
@@ -716,6 +855,10 @@
     self->flags = 0;
     self->setflags = 0;
     self->myenvobj = NULL;
+    self->children_cursors = NULL;
+#if (DBVER >=43)
+    self->children_sequences = NULL;
+#endif
 #if (DBVER >= 33)
     self->associateCallback = NULL;
     self->btCompareCallback = NULL;
@@ -728,7 +871,14 @@
         Py_INCREF(arg);
         self->myenvobj = arg;
         db_env = arg->db_env;
+        INSERT_IN_DOUBLE_LINKED_LIST(self->myenvobj->children_dbs,self);
+    } else {
+      self->sibling_prev_p=NULL;
+      self->sibling_next=NULL;
     }
+    self->txn=NULL;
+    self->sibling_prev_p_txn=NULL;
+    self->sibling_next_txn=NULL;
 
     if (self->myenvobj)
         self->moduleFlags = self->myenvobj->moduleFlags;
@@ -760,23 +910,17 @@
 }
 
 
+/* Forward declaration */
+static PyObject *DB_close_internal(DBObject* self, int flags);
+
 static void
 DB_dealloc(DBObject* self)
 {
+  PyObject *dummy;
+
     if (self->db != NULL) {
-        /* avoid closing a DB when its DBEnv has been closed out from under
-         * it */
-        if (!self->myenvobj ||
-            (self->myenvobj && self->myenvobj->db_env))
-        {
-            MYDB_BEGIN_ALLOW_THREADS;
-            self->db->close(self->db, 0);
-            MYDB_END_ALLOW_THREADS;
-        } else {
-            PyErr_Warn(PyExc_RuntimeWarning,
-                "DB could not be closed in destructor: DBEnv already closed");
-        }
-        self->db = NULL;
+      dummy=DB_close_internal(self,0);
+      Py_XDECREF(dummy);
     }
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
@@ -798,9 +942,8 @@
     PyObject_Del(self);
 }
 
-
 static DBCursorObject*
-newDBCursorObject(DBC* dbc, DBObject* db)
+newDBCursorObject(DBC* dbc, DBTxnObject *txn, DBObject* db)
 {
     DBCursorObject* self = PyObject_New(DBCursorObject, &DBCursor_Type);
     if (self == NULL)
@@ -808,40 +951,37 @@
 
     self->dbc = dbc;
     self->mydb = db;
+
+    INSERT_IN_DOUBLE_LINKED_LIST(self->mydb->children_cursors,self);
+    if (txn && ((PyObject *)txn!=Py_None)) {
+	    INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->children_cursors,self);
+	    self->txn=txn;
+    } else {
+	    self->txn=NULL;
+    }
+
     self->in_weakreflist = NULL;
     Py_INCREF(self->mydb);
     return self;
 }
 
 
+/* Forward declaration */
+static PyObject *DBC_close_internal(DBCursorObject* self);
+
 static void
 DBCursor_dealloc(DBCursorObject* self)
 {
-    int err;
+    PyObject *dummy;
 
+    if (self->dbc != NULL) {
+      dummy=DBC_close_internal(self);
+      Py_XDECREF(dummy);
+    }
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
-
-    if (self->dbc != NULL) {
-	/* If the underlying database has been closed, we don't
-	   need to do anything. If the environment has been closed
-	   we need to leak, as BerkeleyDB will crash trying to access
-	   the environment. There was an exception when the 
-	   user closed the environment even though there still was
-	   a database open. */
-	if (self->mydb->db && self->mydb->myenvobj &&
-	    !self->mydb->myenvobj->closed)
-        /* test for: open db + no environment or non-closed environment */
-	if (self->mydb->db && (!self->mydb->myenvobj || (self->mydb->myenvobj &&
-	    !self->mydb->myenvobj->closed))) {
-            MYDB_BEGIN_ALLOW_THREADS;
-            err = self->dbc->c_close(self->dbc);
-            MYDB_END_ALLOW_THREADS;
-        }
-        self->dbc = NULL;
-    }
-    Py_XDECREF( self->mydb );
+    Py_DECREF(self->mydb);
     PyObject_Del(self);
 }
 
@@ -858,8 +998,14 @@
     self->flags = flags;
     self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
     self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
+    self->children_dbs = NULL;
+    self->children_txns = NULL;
     self->in_weakreflist = NULL;
 
+#if (DBVER >= 40)
+    self->event_notifyCallback = NULL;
+#endif
+
     MYDB_BEGIN_ALLOW_THREADS;
     err = db_env_create(&self->db_env, flags);
     MYDB_END_ALLOW_THREADS;
@@ -869,75 +1015,119 @@
     }
     else {
         self->db_env->set_errcall(self->db_env, _db_errorCallback);
+        self->db_env->app_private=self;
     }
     return self;
 }
 
+/* Forward declaration */
+static PyObject *DBEnv_close_internal(DBEnvObject* self, int flags);
 
 static void
 DBEnv_dealloc(DBEnvObject* self)
 {
+  PyObject *dummy;
+
+    if (self->db_env && !self->closed) {
+      dummy=DBEnv_close_internal(self,0);
+      Py_XDECREF(dummy);
+    }
+
+#if (DBVER >= 40)
+    Py_XDECREF(self->event_notifyCallback);
+    self->event_notifyCallback = NULL;
+#endif
+
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
 
-    if (self->db_env && !self->closed) {
-        MYDB_BEGIN_ALLOW_THREADS;
-        self->db_env->close(self->db_env, 0);
-        MYDB_END_ALLOW_THREADS;
-    }
     PyObject_Del(self);
 }
 
 
 static DBTxnObject*
-newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags)
+newDBTxnObject(DBEnvObject* myenv, DBTxnObject *parent, DB_TXN *txn, int flags)
 {
     int err;
+    DB_TXN *parent_txn=NULL;
+
     DBTxnObject* self = PyObject_New(DBTxnObject, &DBTxn_Type);
     if (self == NULL)
         return NULL;
-    Py_INCREF(myenv);
-    self->env = (PyObject*)myenv;
+
     self->in_weakreflist = NULL;
 
-    MYDB_BEGIN_ALLOW_THREADS;
+    if (parent && ((PyObject *)parent!=Py_None)) {
+        parent_txn=parent->txn;
+    }
+
+    if (txn) {
+        self->txn=txn;
+    } else {
+        MYDB_BEGIN_ALLOW_THREADS;
 #if (DBVER >= 40)
-    err = myenv->db_env->txn_begin(myenv->db_env, parent, &(self->txn), flags);
+        err = myenv->db_env->txn_begin(myenv->db_env, parent_txn, &(self->txn), flags);
 #else
-    err = txn_begin(myenv->db_env, parent, &(self->txn), flags);
+        err = txn_begin(myenv->db_env, parent->txn, &(self_txn), flags);
 #endif
-    MYDB_END_ALLOW_THREADS;
-    if (makeDBError(err)) {
-        Py_DECREF(self->env);
-        PyObject_Del(self);
-        self = NULL;
+        MYDB_END_ALLOW_THREADS;
+
+        if (makeDBError(err)) {
+            PyObject_Del(self);
+            return NULL;
+        }
     }
+
+    if (parent_txn) { /* Can't use 'parent' because could be 'parent==Py_None' */
+        self->parent_txn=parent;
+        Py_INCREF(parent);
+        self->env = NULL;
+        INSERT_IN_DOUBLE_LINKED_LIST(parent->children_txns,self);
+    } else {
+        self->parent_txn=NULL;
+        Py_INCREF(myenv);
+        self->env = myenv;
+        INSERT_IN_DOUBLE_LINKED_LIST(myenv->children_txns,self);
+    }
+
+    self->children_txns=NULL;
+    self->children_dbs=NULL;
+    self->children_cursors=NULL;
+    self->children_sequences=NULL;
+    self->flag_prepare=0;
+
     return self;
 }
 
+/* Forward declaration */
+static PyObject *
+DBTxn_abort_discard_internal(DBTxnObject* self, int discard);
 
 static void
 DBTxn_dealloc(DBTxnObject* self)
 {
+  PyObject *dummy;
+
+    if (self->txn) {
+        int flag_prepare = self->flag_prepare;
+        dummy=DBTxn_abort_discard_internal(self,0);
+        Py_XDECREF(dummy);
+        if (!flag_prepare) {
+            PyErr_Warn(PyExc_RuntimeWarning,
+              "DBTxn aborted in destructor.  No prior commit() or abort().");
+        }
+    }
+
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
 
-    if (self->txn) {
-        /* it hasn't been finalized, abort it! */
-        MYDB_BEGIN_ALLOW_THREADS;
-#if (DBVER >= 40)
-        self->txn->abort(self->txn);
-#else
-        txn_abort(self->txn);
-#endif
-        MYDB_END_ALLOW_THREADS;
-        PyErr_Warn(PyExc_RuntimeWarning,
-            "DBTxn aborted in destructor.  No prior commit() or abort().");
+    if (self->env) {
+        Py_DECREF(self->env);
+    } else {
+        Py_DECREF(self->parent_txn);
     }
-
-    Py_DECREF(self->env);
     PyObject_Del(self);
 }
 
@@ -991,8 +1181,11 @@
         return NULL;
     Py_INCREF(mydb);
     self->mydb = mydb;
-    self->in_weakreflist = NULL;
 
+    INSERT_IN_DOUBLE_LINKED_LIST(self->mydb->children_sequences,self);
+    self->txn=NULL;
+
+    self->in_weakreflist = NULL;
 
     MYDB_BEGIN_ALLOW_THREADS;
     err = db_sequence_create(&self->sequence, self->mydb->db, flags);
@@ -1006,10 +1199,20 @@
     return self;
 }
 
+/* Forward declaration */
+static PyObject
+*DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close);
 
 static void
 DBSequence_dealloc(DBSequenceObject* self)
 {
+    PyObject *dummy;
+
+    if (self->sequence != NULL) {
+        dummy=DBSequence_close_internal(self,0,0);
+        Py_XDECREF(dummy);
+    }
+
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
@@ -1072,11 +1275,9 @@
         MYDB_BEGIN_BLOCK_THREADS;
 
         if (type == DB_RECNO || type == DB_QUEUE)
-            args = Py_BuildValue("(ls#)", *((db_recno_t*)priKey->data),
-                                 priData->data, priData->size);
+            args = BuildValue_LS(*((db_recno_t*)priKey->data), priData->data, priData->size);
         else
-            args = Py_BuildValue("(s#s#)", priKey->data, priKey->size,
-                                 priData->data, priData->size);
+            args = BuildValue_SS(priKey->data, priKey->size, priData->data, priData->size);
         if (args != NULL) {
                 result = PyEval_CallObject(callback, args);
         }
@@ -1217,21 +1418,49 @@
 
 
 static PyObject*
-DB_close(DBObject* self, PyObject* args)
+DB_close_internal(DBObject* self, int flags)
 {
-    int err, flags=0;
-    if (!PyArg_ParseTuple(args,"|i:close", &flags))
-        return NULL;
+    PyObject *dummy;
+    int err;
+
     if (self->db != NULL) {
-        if (self->myenvobj)
-            CHECK_ENV_NOT_CLOSED(self->myenvobj);
+        /* Can be NULL if db is not in an environment */
+        EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(self);
+        if (self->txn) {
+            EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
+            self->txn=NULL;
+        }
+
+        while(self->children_cursors) {
+          dummy=DBC_close_internal(self->children_cursors);
+          Py_XDECREF(dummy);
+        }
+
+#if (DBVER >= 43)
+        while(self->children_sequences) {
+            dummy=DBSequence_close_internal(self->children_sequences,0,0);
+            Py_XDECREF(dummy);
+        }
+#endif
+
+        MYDB_BEGIN_ALLOW_THREADS;
         err = self->db->close(self->db, flags);
+        MYDB_END_ALLOW_THREADS;
         self->db = NULL;
         RETURN_IF_ERR();
     }
     RETURN_NONE();
 }
 
+static PyObject*
+DB_close(DBObject* self, PyObject* args)
+{
+    int flags=0;
+    if (!PyArg_ParseTuple(args,"|i:close", &flags))
+        return NULL;
+    return DB_close_internal(self,flags);
+}
+
 
 static PyObject*
 _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
@@ -1262,7 +1491,7 @@
     CLEAR_DBT(key);
     CLEAR_DBT(data);
     if (CHECK_DBFLAG(self, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
+        /* Tell Berkeley DB to malloc the return value (thread safe) */
         data.flags = DB_DBT_MALLOC;
         key.flags = DB_DBT_MALLOC;
     }
@@ -1278,8 +1507,7 @@
         retval = Py_None;
     }
     else if (!err) {
-        retval = Py_BuildValue("s#s#", key.data, key.size, data.data,
-                               data.size);
+        retval = BuildValue_SS(key.data, key.size, data.data, data.size);
         FREE_DBT(key);
         FREE_DBT(data);
     }
@@ -1322,7 +1550,7 @@
     err = self->db->cursor(self->db, txn, &dbc, flags);
     MYDB_END_ALLOW_THREADS;
     RETURN_IF_ERR();
-    return (PyObject*) newDBCursorObject(dbc, self);
+    return (PyObject*) newDBCursorObject(dbc, (DBTxnObject *)txnobj, self);
 }
 
 
@@ -1404,7 +1632,7 @@
 
     CLEAR_DBT(data);
     if (CHECK_DBFLAG(self, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
+        /* Tell Berkeley DB to malloc the return value (thread safe) */
         data.flags = DB_DBT_MALLOC;
     }
     if (!add_partial_dbt(&data, dlen, doff)) {
@@ -1429,10 +1657,9 @@
     }
     else if (!err) {
         if (flags & DB_SET_RECNO) /* return both key and data */
-            retval = Py_BuildValue("s#s#", key.data, key.size, data.data,
-                                   data.size);
+            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
         else /* return just the data */
-            retval = PyString_FromStringAndSize((char*)data.data, data.size);
+            retval = Build_PyString(data.data, data.size);
         FREE_DBT(data);
     }
     FREE_DBT(key);
@@ -1472,7 +1699,7 @@
 
     CLEAR_DBT(data);
     if (CHECK_DBFLAG(self, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
+        /* Tell Berkeley DB to malloc the return value (thread safe) */
         data.flags = DB_DBT_MALLOC;
     }
     if (!add_partial_dbt(&data, dlen, doff)) {
@@ -1501,13 +1728,13 @@
     else if (!err) {
         PyObject *pkeyObj;
         PyObject *dataObj;
-        dataObj = PyString_FromStringAndSize(data.data, data.size);
+        dataObj = Build_PyString(data.data, data.size);
 
         if (self->primaryDBType == DB_RECNO ||
             self->primaryDBType == DB_QUEUE)
             pkeyObj = PyInt_FromLong(*(int *)pkey.data);
         else
-            pkeyObj = PyString_FromStringAndSize(pkey.data, pkey.size);
+            pkeyObj = Build_PyString(pkey.data, pkey.size);
 
         if (flags & DB_SET_RECNO) /* return key , pkey and data */
         {
@@ -1516,7 +1743,7 @@
             if (type == DB_RECNO || type == DB_QUEUE)
                 keyObj = PyInt_FromLong(*(int *)key.data);
             else
-                keyObj = PyString_FromStringAndSize(key.data, key.size);
+                keyObj = Build_PyString(key.data, key.size);
 #if (PY_VERSION_HEX >= 0x02040000)
             retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
 #else
@@ -1620,7 +1847,7 @@
     orig_data = data.data;
 
     if (CHECK_DBFLAG(self, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
+        /* Tell Berkeley DB to malloc the return value (thread safe) */
         /* XXX(nnorwitz): At least 4.4.20 and 4.5.20 require this flag. */
         data.flags = DB_DBT_MALLOC;
     }
@@ -1637,7 +1864,7 @@
     }
     else if (!err) {
         /* XXX(nnorwitz): can we do: retval = dataobj; Py_INCREF(retval); */
-        retval = PyString_FromStringAndSize((char*)data.data, data.size);
+        retval = Build_PyString(data.data, data.size);
 
         /* Even though the flags require DB_DBT_MALLOC, data is not always
            allocated.  4.4: allocated, 4.5: *not* allocated. :-( */
@@ -1748,7 +1975,7 @@
        but does not hold python references to them or prevent
        them from being closed prematurely.  This can cause
        python to crash when things are done in the wrong order. */
-    return (PyObject*) newDBCursorObject(dbc, self);
+    return (PyObject*) newDBCursorObject(dbc, NULL, self);
 }
 
 
@@ -1845,6 +2072,17 @@
         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);
@@ -1853,8 +2091,10 @@
 #endif
     MYDB_END_ALLOW_THREADS;
     if (makeDBError(err)) {
-        self->db->close(self->db, 0);
-        self->db = NULL;
+        PyObject *dummy;
+
+        dummy=DB_close_internal(self,0);
+        Py_XDECREF(dummy);
         return NULL;
     }
 
@@ -1863,6 +2103,7 @@
 #endif
 
     self->flags = flags;
+
     RETURN_NONE();
 }
 
@@ -1993,7 +2234,7 @@
 }
 
 static int
-_db_compareCallback(DB* db, 
+_db_compareCallback(DB* db,
 		    const DBT *leftKey,
 		    const DBT *rightKey)
 {
@@ -2015,8 +2256,7 @@
     } else {
 	MYDB_BEGIN_BLOCK_THREADS;
 
-	args = Py_BuildValue("s#s#", leftKey->data, leftKey->size,
-			     rightKey->data, rightKey->size);
+	args = BuildValue_SS(leftKey->data, leftKey->size, rightKey->data, rightKey->size);
 	if (args != NULL) {
 		/* XXX(twouters) I highly doubt this INCREF is correct */
 		Py_INCREF(self);
@@ -2369,6 +2609,9 @@
         MAKE_HASH_ENTRY(version);
         MAKE_HASH_ENTRY(nkeys);
         MAKE_HASH_ENTRY(ndata);
+#if (DBVER >= 46)
+        MAKE_HASH_ENTRY(pagecnt);
+#endif
         MAKE_HASH_ENTRY(pagesize);
 #if (DBVER < 41)
         MAKE_HASH_ENTRY(nelem);
@@ -2391,6 +2634,9 @@
         MAKE_BT_ENTRY(version);
         MAKE_BT_ENTRY(nkeys);
         MAKE_BT_ENTRY(ndata);
+#if (DBVER >= 46)
+        MAKE_BT_ENTRY(pagecnt);
+#endif
         MAKE_BT_ENTRY(pagesize);
         MAKE_BT_ENTRY(minkey);
         MAKE_BT_ENTRY(re_len);
@@ -2400,6 +2646,9 @@
         MAKE_BT_ENTRY(leaf_pg);
         MAKE_BT_ENTRY(dup_pg);
         MAKE_BT_ENTRY(over_pg);
+#if (DBVER >= 43)
+        MAKE_BT_ENTRY(empty_pg);
+#endif
         MAKE_BT_ENTRY(free);
         MAKE_BT_ENTRY(int_pgfree);
         MAKE_BT_ENTRY(leaf_pgfree);
@@ -2413,6 +2662,9 @@
         MAKE_QUEUE_ENTRY(nkeys);
         MAKE_QUEUE_ENTRY(ndata);
         MAKE_QUEUE_ENTRY(pagesize);
+#if (DBVER > 40)
+        MAKE_QUEUE_ENTRY(extentsize);
+#endif
         MAKE_QUEUE_ENTRY(pages);
         MAKE_QUEUE_ENTRY(re_len);
         MAKE_QUEUE_ENTRY(re_pad);
@@ -2527,15 +2779,14 @@
     if (outFile)
         fclose(outFile);
 
-    /* DB.verify acts as a DB handle destructor (like close); this was
-     * documented in BerkeleyDB 4.2 but had the undocumented effect
-     * of not being safe in prior versions while still requiring an explicit
-     * DB.close call afterwards.  Lets call close for the user to emulate
-     * the safe 4.2 behaviour. */
-#if (DBVER <= 41)
-    self->db->close(self->db, 0);
-#endif
-    self->db = NULL;
+    {  /* DB.verify acts as a DB handle destructor (like close) */
+        PyObject *error;
+
+        error=DB_close_internal(self,0);
+        if (error ) {
+          return error;
+        }
+     }
 
     RETURN_IF_ERR();
     RETURN_NONE();
@@ -2622,7 +2873,7 @@
        so we can use any of them for the type cast */
     size = ((DB_BTREE_STAT*)sp)->bt_ndata;
 
-    /* A size of 0 could mean that BerkeleyDB no longer had the stat values cached.
+    /* A size of 0 could mean that Berkeley DB no longer had the stat values cached.
      * redo a full stat to make sure.
      *   Fixes SF python bug 1493322, pybsddb bug 1184012
      */
@@ -2658,7 +2909,7 @@
 
     CLEAR_DBT(data);
     if (CHECK_DBFLAG(self, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
+        /* Tell Berkeley DB to malloc the return value (thread safe) */
         data.flags = DB_DBT_MALLOC;
     }
     MYDB_BEGIN_ALLOW_THREADS;
@@ -2672,7 +2923,7 @@
         retval = NULL;
     }
     else {
-        retval = PyString_FromStringAndSize((char*)data.data, data.size);
+        retval = Build_PyString(data.data, data.size);
         FREE_DBT(data);
     }
 
@@ -2802,14 +3053,9 @@
         return NULL;
     }
 
-    if (CHECK_DBFLAG(self, DB_THREAD)) {
-        key.flags = DB_DBT_REALLOC;
-        data.flags = DB_DBT_REALLOC;
-    }
-
     while (1) { /* use the cursor to traverse the DB, collecting items */
         MYDB_BEGIN_ALLOW_THREADS;
-        err = cursor->c_get(cursor, &key, &data, DB_NEXT);
+        err = _DBC_get(cursor, &key, &data, DB_NEXT);
         MYDB_END_ALLOW_THREADS;
 
         if (err) {
@@ -2823,7 +3069,7 @@
             case DB_BTREE:
             case DB_HASH:
             default:
-                item = PyString_FromStringAndSize((char*)key.data, key.size);
+                item = Build_PyString(key.data, key.size);
                 break;
             case DB_RECNO:
             case DB_QUEUE:
@@ -2833,7 +3079,7 @@
             break;
 
         case _VALUES_LIST:
-            item = PyString_FromStringAndSize((char*)data.data, data.size);
+            item = Build_PyString(data.data, data.size);
             break;
 
         case _ITEMS_LIST:
@@ -2841,13 +3087,11 @@
             case DB_BTREE:
             case DB_HASH:
             default:
-                item = Py_BuildValue("s#s#", key.data, key.size, data.data,
-                                     data.size);
+                item = BuildValue_SS(key.data, key.size, data.data, data.size);
                 break;
             case DB_RECNO:
             case DB_QUEUE:
-                item = Py_BuildValue("is#", *((db_recno_t*)key.data),
-                                     data.data, data.size);
+                item = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
                 break;
             }
             break;
@@ -2872,10 +3116,8 @@
     }
 
  done:
-    FREE_DBT(key);
-    FREE_DBT(data);
     MYDB_BEGIN_ALLOW_THREADS;
-    cursor->c_close(cursor);
+    _DBC_close(cursor);
     MYDB_END_ALLOW_THREADS;
     return list;
 }
@@ -2927,23 +3169,35 @@
 
 
 static PyObject*
-DBC_close(DBCursorObject* self, PyObject* args)
+DBC_close_internal(DBCursorObject* self)
 {
     int err = 0;
 
-    if (!PyArg_ParseTuple(args, ":close"))
-        return NULL;
-
     if (self->dbc != NULL) {
+        EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
+        if (self->txn) {
+            EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
+            self->txn=NULL;
+        }
+
         MYDB_BEGIN_ALLOW_THREADS;
-        err = self->dbc->c_close(self->dbc);
-        self->dbc = NULL;
+        err = _DBC_close(self->dbc);
         MYDB_END_ALLOW_THREADS;
+        self->dbc = NULL;
     }
     RETURN_IF_ERR();
     RETURN_NONE();
 }
 
+static PyObject*
+DBC_close(DBCursorObject* self, PyObject* args)
+{
+    if (!PyArg_ParseTuple(args, ":close"))
+        return NULL;
+
+    return DBC_close_internal(self);
+}
+
 
 static PyObject*
 DBC_count(DBCursorObject* self, PyObject* args)
@@ -2958,7 +3212,7 @@
     CHECK_CURSOR_NOT_CLOSED(self);
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_count(self->dbc, &count, flags);
+    err = _DBC_count(self->dbc, &count, flags);
     MYDB_END_ALLOW_THREADS;
     RETURN_IF_ERR();
 
@@ -2984,7 +3238,7 @@
     CHECK_CURSOR_NOT_CLOSED(self);
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_del(self->dbc, flags);
+    err = _DBC_del(self->dbc, flags);
     MYDB_END_ALLOW_THREADS;
     RETURN_IF_ERR();
 
@@ -3005,11 +3259,11 @@
     CHECK_CURSOR_NOT_CLOSED(self);
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_dup(self->dbc, &dbc, flags);
+    err = _DBC_dup(self->dbc, &dbc, flags);
     MYDB_END_ALLOW_THREADS;
     RETURN_IF_ERR();
 
-    return (PyObject*) newDBCursorObject(dbc, self->mydb);
+    return (PyObject*) newDBCursorObject(dbc, self->txn, self->mydb);
 }
 
 static PyObject*
@@ -3059,19 +3313,12 @@
     if ( (dataobj && !make_dbt(dataobj, &data)) ||
          (!add_partial_dbt(&data, dlen, doff)) )
     {
-        FREE_DBT(key);
+        FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
         return NULL;
     }
 
-    if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
-        data.flags = DB_DBT_MALLOC;
-        if (!(key.flags & DB_DBT_REALLOC)) {
-            key.flags |= DB_DBT_MALLOC;
-        }
-    }
-
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_get(self->dbc, &key, &data, flags);
+    err = _DBC_get(self->dbc, &key, &data, flags);
     MYDB_END_ALLOW_THREADS;
 
     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
@@ -3090,18 +3337,15 @@
         case DB_BTREE:
         case DB_HASH:
         default:
-            retval = Py_BuildValue("s#s#", key.data, key.size,
-                                   data.data, data.size);
+            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
             break;
         case DB_RECNO:
         case DB_QUEUE:
-            retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
-                                   data.data, data.size);
+            retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
             break;
         }
-        FREE_DBT(data);
     }
-    FREE_DBT(key);
+    FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
     return retval;
 }
 
@@ -3145,22 +3389,15 @@
         return NULL;
     if ( (dataobj && !make_dbt(dataobj, &data)) ||
          (!add_partial_dbt(&data, dlen, doff)) ) {
-        FREE_DBT(key);
+        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
         return NULL;
     }
 
-    if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
-        data.flags = DB_DBT_MALLOC;
-        if (!(key.flags & DB_DBT_REALLOC)) {
-            key.flags |= DB_DBT_MALLOC;
-        }
-    }
-
     CLEAR_DBT(pkey);
     pkey.flags = DB_DBT_MALLOC;
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_pget(self->dbc, &key, &pkey, &data, flags);
+    err = _DBC_pget(self->dbc, &key, &pkey, &data, flags);
     MYDB_END_ALLOW_THREADS;
 
     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
@@ -3174,13 +3411,13 @@
     else {
         PyObject *pkeyObj;
         PyObject *dataObj;
-        dataObj = PyString_FromStringAndSize(data.data, data.size);
+        dataObj = Build_PyString(data.data, data.size);
 
         if (self->mydb->primaryDBType == DB_RECNO ||
             self->mydb->primaryDBType == DB_QUEUE)
             pkeyObj = PyInt_FromLong(*(int *)pkey.data);
         else
-            pkeyObj = PyString_FromStringAndSize(pkey.data, pkey.size);
+            pkeyObj = Build_PyString(pkey.data, pkey.size);
 
         if (key.data && key.size) /* return key, pkey and data */
         {
@@ -3189,14 +3426,14 @@
             if (type == DB_RECNO || type == DB_QUEUE)
                 keyObj = PyInt_FromLong(*(int *)key.data);
             else
-                keyObj = PyString_FromStringAndSize(key.data, key.size);
+                keyObj = Build_PyString(key.data, key.size);
 #if (PY_VERSION_HEX >= 0x02040000)
             retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
 #else
             retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj);
 #endif
             Py_DECREF(keyObj);
-            FREE_DBT(key);
+            FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
         }
         else /* return just the pkey and data */
         {
@@ -3209,11 +3446,10 @@
         Py_DECREF(dataObj);
         Py_DECREF(pkeyObj);
         FREE_DBT(pkey);
-        FREE_DBT(data);
     }
     /* the only time REALLOC should be set is if we used an integer
      * key that make_key_dbt malloc'd for us.  always free these. */
-    if (key.flags & DB_DBT_REALLOC) {
+    if (key.flags & DB_DBT_REALLOC) {  /* 'make_key_dbt' could do a 'malloc' */
         FREE_DBT(key);
     }
     return retval;
@@ -3236,20 +3472,13 @@
 
     CLEAR_DBT(key);
     CLEAR_DBT(data);
-    if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
-        data.flags = DB_DBT_MALLOC;
-        key.flags = DB_DBT_MALLOC;
-    }
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_get(self->dbc, &key, &data, DB_GET_RECNO);
+    err = _DBC_get(self->dbc, &key, &data, DB_GET_RECNO);
     MYDB_END_ALLOW_THREADS;
     RETURN_IF_ERR();
 
     recno = *((db_recno_t*)data.data);
-    FREE_DBT(key);
-    FREE_DBT(data);
     return PyInt_FromLong(recno);
 }
 
@@ -3297,14 +3526,14 @@
     if (!make_dbt(dataobj, &data) ||
         !add_partial_dbt(&data, dlen, doff) )
     {
-        FREE_DBT(key);
+        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
         return NULL;
     }
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_put(self->dbc, &key, &data, flags);
+    err = _DBC_put(self->dbc, &key, &data, flags);
     MYDB_END_ALLOW_THREADS;
-    FREE_DBT(key);
+    FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
     RETURN_IF_ERR();
     self->mydb->haveStat = 0;
     RETURN_NONE();
@@ -3331,17 +3560,13 @@
         return NULL;
 
     CLEAR_DBT(data);
-    if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
-        data.flags = DB_DBT_MALLOC;
-    }
     if (!add_partial_dbt(&data, dlen, doff)) {
-        FREE_DBT(key);
+        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
         return NULL;
     }
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET);
+    err = _DBC_get(self->dbc, &key, &data, flags|DB_SET);
     MYDB_END_ALLOW_THREADS;
     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
 	    && self->mydb->moduleFlags.cursorSetReturnsNone) {
@@ -3359,22 +3584,19 @@
         case DB_BTREE:
         case DB_HASH:
         default:
-            retval = Py_BuildValue("s#s#", key.data, key.size,
-                                   data.data, data.size);
+            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
             break;
         case DB_RECNO:
         case DB_QUEUE:
-            retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
-                                   data.data, data.size);
+            retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
             break;
         }
-        FREE_DBT(data);
-        FREE_DBT(key);
+        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
     }
     /* the only time REALLOC should be set is if we used an integer
      * key that make_key_dbt malloc'd for us.  always free these. */
     if (key.flags & DB_DBT_REALLOC) {
-        FREE_DBT(key);
+        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
     }
 
     return retval;
@@ -3402,19 +3624,11 @@
 
     CLEAR_DBT(data);
     if (!add_partial_dbt(&data, dlen, doff)) {
-        FREE_DBT(key);
+        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
         return NULL;
     }
-    if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
-        data.flags |= DB_DBT_MALLOC;
-        /* only BTREE databases will return anything in the key */
-        if (!(key.flags & DB_DBT_REALLOC) && _DB_get_type(self->mydb) == DB_BTREE) {
-            key.flags |= DB_DBT_MALLOC;
-        }
-    }
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
+    err = _DBC_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
     MYDB_END_ALLOW_THREADS;
     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
 	    && self->mydb->moduleFlags.cursorSetReturnsNone) {
@@ -3432,22 +3646,19 @@
         case DB_BTREE:
         case DB_HASH:
         default:
-            retval = Py_BuildValue("s#s#", key.data, key.size,
-                                   data.data, data.size);
+            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
             break;
         case DB_RECNO:
         case DB_QUEUE:
-            retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
-                                   data.data, data.size);
+            retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
             break;
         }
-        FREE_DBT(key);
-        FREE_DBT(data);
+        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
     }
     /* the only time REALLOC should be set is if we used an integer
      * key that make_key_dbt malloc'd for us.  always free these. */
     if (key.flags & DB_DBT_REALLOC) {
-        FREE_DBT(key);
+        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
     }
 
     return retval;
@@ -3465,12 +3676,12 @@
     if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
         return NULL;
     if (!make_dbt(dataobj, &data)) {
-        FREE_DBT(key);
+        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
         return NULL;
     }
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_GET_BOTH);
+    err = _DBC_get(self->dbc, &key, &data, flags|DB_GET_BOTH);
     MYDB_END_ALLOW_THREADS;
     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && returnsNone) {
         Py_INCREF(Py_None);
@@ -3487,18 +3698,16 @@
         case DB_BTREE:
         case DB_HASH:
         default:
-            retval = Py_BuildValue("s#s#", key.data, key.size,
-                                   data.data, data.size);
+            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
             break;
         case DB_RECNO:
         case DB_QUEUE:
-            retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
-                                   data.data, data.size);
+            retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
             break;
         }
     }
 
-    FREE_DBT(key);
+    FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
     return retval;
 }
 
@@ -3537,7 +3746,7 @@
     data.flags = DB_DBT_USERMEM;
     data.ulen = 0;
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_get(self->dbc, &key, &data, flags);
+    err = _DBC_get(self->dbc, &key, &data, flags);
     MYDB_END_ALLOW_THREADS;
     if (err == DB_BUFFER_SMALL || !err) {
         /* DB_BUFFER_SMALL means positive size, !err means zero length value */
@@ -3545,8 +3754,6 @@
         err = 0;
     }
 
-    FREE_DBT(key);
-    FREE_DBT(data);
     RETURN_IF_ERR();
     return retval;
 }
@@ -3600,17 +3807,13 @@
     key.flags = DB_DBT_REALLOC;
 
     CLEAR_DBT(data);
-    if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
-        data.flags = DB_DBT_MALLOC;
-    }
     if (!add_partial_dbt(&data, dlen, doff)) {
         FREE_DBT(key);
         return NULL;
     }
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RECNO);
+    err = _DBC_get(self->dbc, &key, &data, flags|DB_SET_RECNO);
     MYDB_END_ALLOW_THREADS;
     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
 	    && self->mydb->moduleFlags.cursorSetReturnsNone) {
@@ -3621,9 +3824,7 @@
         retval = NULL;
     }
     else {  /* Can only be used for BTrees, so no need to return int key */
-        retval = Py_BuildValue("s#s#", key.data, key.size,
-                               data.data, data.size);
-        FREE_DBT(data);
+        retval = BuildValue_SS(key.data, key.size, data.data, data.size);
     }
     FREE_DBT(key);
 
@@ -3673,13 +3874,9 @@
 
     CLEAR_DBT(key);
     CLEAR_DBT(data);
-    if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
-        /* Tell BerkeleyDB to malloc the return value (thread safe) */
-        key.flags = DB_DBT_MALLOC;
-    }
 
     MYDB_BEGIN_ALLOW_THREADS;
-    err = self->dbc->c_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM);
+    err = _DBC_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM);
     MYDB_END_ALLOW_THREADS;
     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
 	    && self->mydb->moduleFlags.getReturnsNone) {
@@ -3690,8 +3887,7 @@
         retval = NULL;
     }
     else {
-        retval = Py_BuildValue("s#", key.data, key.size);
-        FREE_DBT(key);
+        retval = BuildValue_S(key.data, key.size);
     }
 
     return retval;
@@ -3704,18 +3900,26 @@
 
 
 static PyObject*
-DBEnv_close(DBEnvObject* self, PyObject* args)
+DBEnv_close_internal(DBEnvObject* self, int flags)
 {
-    int err, flags = 0;
+    PyObject *dummy;
+    int err;
 
-    if (!PyArg_ParseTuple(args, "|i:close", &flags))
-        return NULL;
     if (!self->closed) {      /* Don't close more than once */
+        while(self->children_txns) {
+          dummy=DBTxn_abort_discard_internal(self->children_txns,0);
+          Py_XDECREF(dummy);
+        }
+        while(self->children_dbs) {
+          dummy=DB_close_internal(self->children_dbs,0);
+          Py_XDECREF(dummy);
+        }
+
         MYDB_BEGIN_ALLOW_THREADS;
         err = self->db_env->close(self->db_env, flags);
         MYDB_END_ALLOW_THREADS;
         /* after calling DBEnv->close, regardless of error, this DBEnv
-         * may not be accessed again (BerkeleyDB docs). */
+         * may not be accessed again (Berkeley DB docs). */
         self->closed = 1;
         self->db_env = NULL;
         RETURN_IF_ERR();
@@ -3723,6 +3927,16 @@
     RETURN_NONE();
 }
 
+static PyObject*
+DBEnv_close(DBEnvObject* self, PyObject* args)
+{
+    int flags = 0;
+
+    if (!PyArg_ParseTuple(args, "|i:close", &flags))
+        return NULL;
+    return DBEnv_close_internal(self,flags);
+}
+
 
 static PyObject*
 DBEnv_open(DBEnvObject* self, PyObject* args)
@@ -3982,8 +4196,27 @@
     RETURN_NONE();
 }
 
-
-#if (DBVER >= 33)
+#if (DBVER >= 42)
+static PyObject*
+DBEnv_get_lg_max(DBEnvObject* self, PyObject* args)
+{
+    int err;
+    u_int32_t lg_max;
+
+    if (!PyArg_ParseTuple(args, ":get_lg_max"))
+        return NULL;
+    CHECK_ENV_NOT_CLOSED(self);
+
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->get_lg_max(self->db_env, &lg_max);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    return PyInt_FromLong(lg_max);
+}
+#endif
+
+
+#if (DBVER >= 33)
 static PyObject*
 DBEnv_set_lg_regionmax(DBEnvObject* self, PyObject* args)
 {
@@ -4125,6 +4358,84 @@
 }
 
 
+#if (DBVER >= 40)
+static PyObject*
+DBEnv_txn_recover(DBEnvObject* self, PyObject* args)
+{
+    int flags = DB_FIRST;
+    int err, i;
+    PyObject *list, *tuple, *gid;
+    DBTxnObject *txn;
+#define PREPLIST_LEN 16
+    DB_PREPLIST preplist[PREPLIST_LEN];
+    long retp;
+
+    if (!PyArg_ParseTuple(args, ":txn_recover"))
+        return NULL;
+
+    CHECK_ENV_NOT_CLOSED(self);
+
+    list=PyList_New(0);
+    if (!list)
+        return NULL;
+    while (!0) {
+        MYDB_BEGIN_ALLOW_THREADS
+        err=self->db_env->txn_recover(self->db_env,
+                        preplist, PREPLIST_LEN, &retp, flags);
+#undef PREPLIST_LEN
+        MYDB_END_ALLOW_THREADS
+        if (err) {
+            Py_DECREF(list);
+            RETURN_IF_ERR();
+        }
+        if (!retp) break;
+        flags=DB_NEXT;  /* Prepare for next loop pass */
+        for (i=0; i<retp; i++) {
+            gid=PyString_FromStringAndSize((char *)(preplist[i].gid),
+                                DB_XIDDATASIZE);
+            if (!gid) {
+                Py_DECREF(list);
+                return NULL;
+            }
+            txn=newDBTxnObject(self, NULL, preplist[i].txn, flags);
+            if (!txn) {
+                Py_DECREF(list);
+                Py_DECREF(gid);
+                return NULL;
+            }
+            txn->flag_prepare=1;  /* Recover state */
+            tuple=PyTuple_New(2);
+            if (!tuple) {
+                Py_DECREF(list);
+                Py_DECREF(gid);
+                Py_DECREF(txn);
+                return NULL;
+            }
+            if (PyTuple_SetItem(tuple, 0, gid)) {
+                Py_DECREF(list);
+                Py_DECREF(gid);
+                Py_DECREF(txn);
+                Py_DECREF(tuple);
+                return NULL;
+            }
+            if (PyTuple_SetItem(tuple, 1, (PyObject *)txn)) {
+                Py_DECREF(list);
+                Py_DECREF(txn);
+                Py_DECREF(tuple); /* This delete the "gid" also */
+                return NULL;
+            }
+            if (PyList_Append(list, tuple)) {
+                Py_DECREF(list);
+                Py_DECREF(tuple);/* This delete the "gid" and the "txn" also */
+                return NULL;
+            }
+            Py_DECREF(tuple);
+        }
+    }
+    return list;
+}
+#endif
+
 static PyObject*
 DBEnv_txn_begin(DBEnvObject* self, PyObject* args, PyObject* kwargs)
 {
@@ -4141,7 +4452,7 @@
         return NULL;
     CHECK_ENV_NOT_CLOSED(self);
 
-    return (PyObject*)newDBTxnObject(self, txn, flags);
+    return (PyObject*)newDBTxnObject(self, (DBTxnObject *)txnobj, NULL, flags);
 }
 
 
@@ -4426,6 +4737,10 @@
 #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);
@@ -4438,6 +4753,10 @@
     MAKE_ENTRY(maxnobjects);
     MAKE_ENTRY(nrequests);
     MAKE_ENTRY(nreleases);
+#if (DBVER >= 44)
+    MAKE_ENTRY(nupgrade);
+    MAKE_ENTRY(ndowngrade);
+#endif
 #if (DBVER < 44)
     MAKE_ENTRY(nnowaits);       /* these were renamed in 4.4 */
     MAKE_ENTRY(nconflicts);
@@ -4446,6 +4765,23 @@
     MAKE_ENTRY(lock_wait);
 #endif
     MAKE_ENTRY(ndeadlocks);
+#if (DBVER >= 41)
+    MAKE_ENTRY(locktimeout);
+    MAKE_ENTRY(txntimeout);
+#endif
+#if (DBVER >= 40)
+    MAKE_ENTRY(nlocktimeouts);
+    MAKE_ENTRY(ntxntimeouts);
+#endif
+#if (DBVER >= 46)
+    MAKE_ENTRY(objs_wait);
+    MAKE_ENTRY(objs_nowait);
+    MAKE_ENTRY(lockers_wait);
+    MAKE_ENTRY(lockers_nowait);
+    MAKE_ENTRY(locks_wait);
+    MAKE_ENTRY(locks_nowait);
+    MAKE_ENTRY(hash_len);
+#endif
     MAKE_ENTRY(regsize);
     MAKE_ENTRY(region_wait);
     MAKE_ENTRY(region_nowait);
@@ -4455,130 +4791,653 @@
     return d;
 }
 
+#if (DBVER >= 40)
+static PyObject*
+DBEnv_log_flush(DBEnvObject* self, PyObject* args)
+{
+    int err;
+
+    if (!PyArg_ParseTuple(args, ":log_flush"))
+        return NULL;
+    CHECK_ENV_NOT_CLOSED(self);
+
+    MYDB_BEGIN_ALLOW_THREADS
+    err = self->db_env->log_flush(self->db_env, NULL);
+    MYDB_END_ALLOW_THREADS
+
+    RETURN_IF_ERR();
+    RETURN_NONE();
+}
+#endif
 
 static PyObject*
 DBEnv_log_archive(DBEnvObject* self, PyObject* args)
 {
-    int flags=0;
+    int flags=0;
+    int err;
+    char **log_list = NULL;
+    PyObject* list;
+    PyObject* item = NULL;
+
+    if (!PyArg_ParseTuple(args, "|i:log_archive", &flags))
+        return NULL;
+
+    CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+#if (DBVER >= 40)
+    err = self->db_env->log_archive(self->db_env, &log_list, flags);
+#elif (DBVER == 33)
+    err = log_archive(self->db_env, &log_list, flags);
+#else
+    err = log_archive(self->db_env, &log_list, flags, NULL);
+#endif
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+
+    list = PyList_New(0);
+    if (list == NULL) {
+        if (log_list)
+            free(log_list);
+        return NULL;
+    }
+
+    if (log_list) {
+        char **log_list_start;
+        for (log_list_start = log_list; *log_list != NULL; ++log_list) {
+            item = PyString_FromString (*log_list);
+            if (item == NULL) {
+                Py_DECREF(list);
+                list = NULL;
+                break;
+            }
+            PyList_Append(list, item);
+            Py_DECREF(item);
+        }
+        free(log_list_start);
+    }
+    return list;
+}
+
+
+static PyObject*
+DBEnv_txn_stat(DBEnvObject* self, PyObject* args)
+{
+    int err;
+    DB_TXN_STAT* sp;
+    PyObject* d = NULL;
+    u_int32_t flags=0;
+
+    if (!PyArg_ParseTuple(args, "|i:txn_stat", &flags))
+        return NULL;
+    CHECK_ENV_NOT_CLOSED(self);
+
+    MYDB_BEGIN_ALLOW_THREADS;
+#if (DBVER >= 40)
+    err = self->db_env->txn_stat(self->db_env, &sp, flags);
+#elif (DBVER == 33)
+    err = txn_stat(self->db_env, &sp);
+#else
+    err = txn_stat(self->db_env, &sp, NULL);
+#endif
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+
+    /* Turn the stat structure into a dictionary */
+    d = PyDict_New();
+    if (d == NULL) {
+        free(sp);
+        return NULL;
+    }
+
+#define MAKE_ENTRY(name)        _addIntToDict(d, #name, sp->st_##name)
+#define MAKE_TIME_T_ENTRY(name) _addTimeTToDict(d, #name, sp->st_##name)
+#define MAKE_DB_LSN_ENTRY(name) _addDB_lsnToDict(d, #name, sp->st_##name)
+
+#if (DBVER >= 40)
+    MAKE_DB_LSN_ENTRY(last_ckp);
+#endif
+    MAKE_TIME_T_ENTRY(time_ckp);
+    MAKE_ENTRY(last_txnid);
+    MAKE_ENTRY(maxtxns);
+    MAKE_ENTRY(nactive);
+    MAKE_ENTRY(maxnactive);
+#if (DBVER >= 45)
+    MAKE_ENTRY(nsnapshot);
+    MAKE_ENTRY(maxnsnapshot);
+#endif
+    MAKE_ENTRY(nbegins);
+    MAKE_ENTRY(naborts);
+    MAKE_ENTRY(ncommits);
+#if (DBVER >= 40)
+    MAKE_ENTRY(nrestores);
+#endif
+    MAKE_ENTRY(regsize);
+    MAKE_ENTRY(region_wait);
+    MAKE_ENTRY(region_nowait);
+
+#undef MAKE_DB_LSN_ENTRY
+#undef MAKE_ENTRY
+#undef MAKE_TIME_T_ENTRY
+    free(sp);
+    return d;
+}
+
+
+static PyObject*
+DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args)
+{
+    int flags=0;
+    int oldValue=0;
+
+    if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
+        return NULL;
+    CHECK_ENV_NOT_CLOSED(self);
+
+    if (self->moduleFlags.getReturnsNone)
+        ++oldValue;
+    if (self->moduleFlags.cursorSetReturnsNone)
+        ++oldValue;
+    self->moduleFlags.getReturnsNone = (flags >= 1);
+    self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
+    return PyInt_FromLong(oldValue);
+}
+
+#if (DBVER >= 40)
+static PyObject*
+DBEnv_set_verbose(DBEnvObject* self, PyObject* args)
+{
+    int err;
+    int which, onoff;
+
+    if (!PyArg_ParseTuple(args, "ii:set_verbose", &which, &onoff)) {
+        return NULL;
+    }
+    CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->set_verbose(self->db_env, which, onoff);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    RETURN_NONE();
+}
+
+#if (DBVER >= 42)
+static PyObject*
+DBEnv_get_verbose(DBEnvObject* self, PyObject* args)
+{
+    int err;
+    int which;
+    int verbose;
+
+    if (!PyArg_ParseTuple(args, "i:get_verbose", &which)) {
+        return NULL;
+    }
+    CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->get_verbose(self->db_env, which, &verbose);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    return PyBool_FromLong(verbose);
+}
+#endif
+#endif
+
+#if (DBVER >= 45)
+static void
+_dbenv_event_notifyCallback(DB_ENV* db_env, u_int32_t event, void *event_info)
+{
+    DBEnvObject *dbenv;
+    PyObject* callback;
+    PyObject* args;
+    PyObject* result = NULL;
+
+    MYDB_BEGIN_BLOCK_THREADS;
+    dbenv = (DBEnvObject *)db_env->app_private;
+    callback = dbenv->event_notifyCallback;
+    if (callback) {
+        if (event == DB_EVENT_REP_NEWMASTER) {
+            args = Py_BuildValue("(Oii)", dbenv, event, *((int *)event_info));
+        } else {
+            args = Py_BuildValue("(OiO)", dbenv, event, Py_None);
+        }
+        if (args) {
+            result = PyEval_CallObject(callback, args);
+        }
+        if ((!args) || (!result)) {
+            PyErr_Print();
+        }
+        Py_XDECREF(args);
+        Py_XDECREF(result);
+    }
+    MYDB_END_BLOCK_THREADS;
+}
+#endif
+
+#if (DBVER >= 45)
+static PyObject*
+DBEnv_set_event_notify(DBEnvObject* self, PyObject* args)
+{
+    int err;
+    PyObject *notifyFunc;
+
+    if (!PyArg_ParseTuple(args, "O:set_event_notify", &notifyFunc)) {
+	    return NULL;
+    }
+
+    CHECK_ENV_NOT_CLOSED(self);
+
+    if (!PyCallable_Check(notifyFunc)) {
+	    makeTypeError("Callable", notifyFunc);
+	    return NULL;
+    }
+
+    Py_XDECREF(self->event_notifyCallback);
+    Py_INCREF(notifyFunc);
+    self->event_notifyCallback = notifyFunc;
+
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->set_event_notify(self->db_env, _dbenv_event_notifyCallback);
+    MYDB_END_ALLOW_THREADS;
+
+    if (err) {
+	    Py_DECREF(notifyFunc);
+	    self->event_notifyCallback = NULL;
+    }
+
+    RETURN_IF_ERR();
+    RETURN_NONE();
+}
+#endif
+
+
+/* --------------------------------------------------------------------- */
+/* REPLICATION METHODS: Base Replication */
+
+#if (DBVER >= 45)
+static PyObject*
+DBEnv_rep_set_nsites(DBEnvObject* self, PyObject* args)
+{
+    int err;
+    int nsites;
+
+    if (!PyArg_ParseTuple(args, "i:rep_set_nsites", &nsites)) {
+        return NULL;
+    }
+    CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->rep_set_nsites(self->db_env, nsites);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    RETURN_NONE();
+}
+
+static PyObject*
+DBEnv_rep_get_nsites(DBEnvObject* self, PyObject* args)
+{
+    int err;
+    int nsites;
+
+    if (!PyArg_ParseTuple(args, ":rep_get_nsites")) {
+        return NULL;
+    }
+    CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->rep_get_nsites(self->db_env, &nsites);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    return PyInt_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, PyObject* args)
+{
+    int err;
+    int priority;
+
+    if (!PyArg_ParseTuple(args, ":rep_get_priority")) {
+        return NULL;
+    }
+    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 PyInt_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 PyInt_FromLong(timeout);
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+/* REPLICATION METHODS: Replication Manager */
+
+#if (DBVER >= 45)
+static PyObject*
+DBEnv_repmgr_start(DBEnvObject* self, PyObject* args, PyObject*
+        kwargs)
+{
+    int err;
+    int nthreads, flags;
+    static char* kwnames[] = {"nthreads","flags", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+                "ii:repmgr_start", kwnames, &nthreads, &flags))
+    {
+	    return NULL;
+    }
+    CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->repmgr_start(self->db_env, nthreads, flags);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    RETURN_NONE();
+}
+
+static PyObject*
+DBEnv_repmgr_set_local_site(DBEnvObject* self, PyObject* args, PyObject*
+        kwargs)
+{
+    int err;
+    char *host;
+    int port;
+    int flags = 0;
+    static char* kwnames[] = {"host", "port", "flags", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+                "si|i:repmgr_set_local_site", kwnames, &host, &port, &flags))
+    {
+	    return NULL;
+    }
+    CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->repmgr_set_local_site(self->db_env, host, port, flags);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    RETURN_NONE();
+}
+
+static PyObject*
+DBEnv_repmgr_add_remote_site(DBEnvObject* self, PyObject* args, PyObject*
+        kwargs)
+{
+    int err;
+    char *host;
+    int port;
+    int flags = 0;
+    int eidp;
+    static char* kwnames[] = {"host", "port", "flags", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+                "si|i:repmgr_add_remote_site", kwnames, &host, &port, &flags))
+    {
+	    return NULL;
+    }
+    CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->repmgr_add_remote_site(self->db_env, host, port, &eidp, flags);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    return PyInt_FromLong(eidp);
+}
+
+static PyObject*
+DBEnv_repmgr_set_ack_policy(DBEnvObject* self, PyObject* args)
+{
+    int err;
+    int ack_policy;
+
+    if (!PyArg_ParseTuple(args, "i:repmgr_set_ack_policy", &ack_policy))
+    {
+	    return NULL;
+    }
+    CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->repmgr_set_ack_policy(self->db_env, ack_policy);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    RETURN_NONE();
+}
+
+static PyObject*
+DBEnv_repmgr_get_ack_policy(DBEnvObject* self, PyObject* args)
+{
+    int err;
+    int ack_policy;
+
+    if (!PyArg_ParseTuple(args, ":repmgr_get_ack_policy"))
+    {
+	    return NULL;
+    }
+    CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->repmgr_get_ack_policy(self->db_env, &ack_policy);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    return PyInt_FromLong(ack_policy);
+}
+
+static PyObject*
+DBEnv_repmgr_site_list(DBEnvObject* self, PyObject* args)
+{
     int err;
-    char **log_list = NULL;
-    PyObject* list;
-    PyObject* item = NULL;
+    unsigned int countp;
+    DB_REPMGR_SITE *listp;
+    PyObject *stats, *key, *tuple;
 
-    if (!PyArg_ParseTuple(args, "|i:log_archive", &flags))
+    if (!PyArg_ParseTuple(args, ":repmgr_site_list"))
+    {
         return NULL;
-
+    }
     CHECK_ENV_NOT_CLOSED(self);
     MYDB_BEGIN_ALLOW_THREADS;
-#if (DBVER >= 40)
-    err = self->db_env->log_archive(self->db_env, &log_list, flags);
-#elif (DBVER == 33)
-    err = log_archive(self->db_env, &log_list, flags);
-#else
-    err = log_archive(self->db_env, &log_list, flags, NULL);
-#endif
+    err = self->db_env->repmgr_site_list(self->db_env, &countp, &listp);
     MYDB_END_ALLOW_THREADS;
     RETURN_IF_ERR();
 
-    list = PyList_New(0);
-    if (list == NULL) {
-        if (log_list)
-            free(log_list);
+    stats=PyDict_New();
+    if (stats == NULL) {
+        free(listp);
         return NULL;
     }
 
-    if (log_list) {
-        char **log_list_start;
-        for (log_list_start = log_list; *log_list != NULL; ++log_list) {
-            item = PyString_FromString (*log_list);
-            if (item == NULL) {
-                Py_DECREF(list);
-                list = NULL;
-                break;
-            }
-            PyList_Append(list, item);
-            Py_DECREF(item);
+    for(;countp--;) {
+        key=PyInt_FromLong(listp[countp].eid);
+        if(!key) {
+            Py_DECREF(stats);
+            free(listp);
+            return NULL;
+        }
+#if (PY_VERSION_HEX >= 0x02040000)
+        tuple=Py_BuildValue("(sII)", listp[countp].host,
+                listp[countp].port, listp[countp].status);
+#else
+        tuple=Py_BuildValue("(sii)", listp[countp].host,
+                listp[countp].port, listp[countp].status);
+#endif
+        if(!tuple) {
+            Py_DECREF(key);
+            Py_DECREF(stats);
+            free(listp);
+            return NULL;
+        }
+        if(PyDict_SetItem(stats, key, tuple)) {
+            Py_DECREF(key);
+            Py_DECREF(tuple);
+            Py_DECREF(stats);
+            free(listp);
+            return NULL;
         }
-        free(log_list_start);
     }
-    return list;
+    free(listp);
+    return stats;
 }
+#endif
 
-
+#if (DBVER >= 46)
 static PyObject*
-DBEnv_txn_stat(DBEnvObject* self, PyObject* args)
+DBEnv_repmgr_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
 {
     int err;
-    DB_TXN_STAT* sp;
-    PyObject* d = NULL;
-    u_int32_t flags=0;
+    int flags=0;
+    static char* kwnames[] = { "flags", NULL };
 
-    if (!PyArg_ParseTuple(args, "|i:txn_stat", &flags))
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:repmgr_stat_print",
+                kwnames, &flags))
+    {
         return NULL;
+    }
     CHECK_ENV_NOT_CLOSED(self);
+    MYDB_BEGIN_ALLOW_THREADS;
+    err = self->db_env->repmgr_stat_print(self->db_env, flags);
+    MYDB_END_ALLOW_THREADS;
+    RETURN_IF_ERR();
+    RETURN_NONE();
+}
 
+static PyObject*
+DBEnv_repmgr_stat(DBEnvObject* self, PyObject* args, PyObject *kwargs)
+{
+    int err;
+    int flags=0;
+    DB_REPMGR_STAT *statp;
+    PyObject *stats;
+    static char* kwnames[] = { "flags", NULL };
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:repmgr_stat",
+                kwnames, &flags))
+    {
+        return NULL;
+    }
+    CHECK_ENV_NOT_CLOSED(self);
     MYDB_BEGIN_ALLOW_THREADS;
-#if (DBVER >= 40)
-    err = self->db_env->txn_stat(self->db_env, &sp, flags);
-#elif (DBVER == 33)
-    err = txn_stat(self->db_env, &sp);
-#else
-    err = txn_stat(self->db_env, &sp, NULL);
-#endif
+    err = self->db_env->repmgr_stat(self->db_env, &statp, flags);
     MYDB_END_ALLOW_THREADS;
     RETURN_IF_ERR();
 
-    /* Turn the stat structure into a dictionary */
-    d = PyDict_New();
-    if (d == NULL) {
-        free(sp);
+    stats=PyDict_New();
+    if (stats == NULL) {
+        free(statp);
         return NULL;
     }
 
-#define MAKE_ENTRY(name)  _addIntToDict(d, #name, sp->st_##name)
-#define MAKE_TIME_T_ENTRY(name)_addTimeTToDict(d, #name, sp->st_##name)
+#define MAKE_ENTRY(name)  _addIntToDict(stats, #name, statp->st_##name)
 
-    MAKE_TIME_T_ENTRY(time_ckp);
-    MAKE_ENTRY(last_txnid);
-    MAKE_ENTRY(maxtxns);
-    MAKE_ENTRY(nactive);
-    MAKE_ENTRY(maxnactive);
-    MAKE_ENTRY(nbegins);
-    MAKE_ENTRY(naborts);
-    MAKE_ENTRY(ncommits);
-    MAKE_ENTRY(regsize);
-    MAKE_ENTRY(region_wait);
-    MAKE_ENTRY(region_nowait);
+    MAKE_ENTRY(perm_failed);
+    MAKE_ENTRY(msgs_queued);
+    MAKE_ENTRY(msgs_dropped);
+    MAKE_ENTRY(connection_drop);
+    MAKE_ENTRY(connect_fail);
 
 #undef MAKE_ENTRY
-#undef MAKE_TIME_T_ENTRY
-    free(sp);
-    return d;
+
+    free(statp);
+    return stats;
 }
+#endif
 
 
-static PyObject*
-DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args)
-{
-    int flags=0;
-    int oldValue=0;
+/* --------------------------------------------------------------------- */
+/* DBTxn methods */
 
-    if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
-        return NULL;
-    CHECK_ENV_NOT_CLOSED(self);
 
-    if (self->moduleFlags.getReturnsNone)
-        ++oldValue;
-    if (self->moduleFlags.cursorSetReturnsNone)
-        ++oldValue;
-    self->moduleFlags.getReturnsNone = (flags >= 1);
-    self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
-    return PyInt_FromLong(oldValue);
+static void _close_transaction_cursors(DBTxnObject* txn)
+{
+    PyObject *dummy;
+
+    while(txn->children_cursors) {
+        PyErr_Warn(PyExc_RuntimeWarning,
+            "Must close cursors before resolving a transaction.");
+        dummy=DBC_close_internal(txn->children_cursors);
+        Py_XDECREF(dummy);
+    }
 }
 
+static void _promote_transaction_dbs_and_sequences(DBTxnObject *txn)
+{
+    DBObject *db;
+#if (DBVER >= 43)
+    DBSequenceObject *dbs;
+#endif
 
-/* --------------------------------------------------------------------- */
-/* DBTxn methods */
+    while (txn->children_dbs) {
+        db=txn->children_dbs;
+        EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(db);
+        if (txn->parent_txn) {
+            INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->parent_txn->children_dbs,db);
+            db->txn=txn->parent_txn;
+        } else {
+            /* The db is already linked to its environment,
+            ** so nothing to do.
+            */
+            db->txn=NULL; 
+        }
+    }
+
+#if (DBVER >= 43)
+    while (txn->children_sequences) {
+        dbs=txn->children_sequences;
+        EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(dbs);
+        if (txn->parent_txn) {
+            INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->parent_txn->children_sequences,dbs);
+            dbs->txn=txn->parent_txn;
+        } else {
+            /* The sequence is already linked to its
+            ** parent db. Nothing to do.
+            */
+            dbs->txn=NULL;
+        }
+    }
+#endif
+}
 
 
 static PyObject*
@@ -4590,15 +5449,22 @@
     if (!PyArg_ParseTuple(args, "|i:commit", &flags))
         return NULL;
 
+    _close_transaction_cursors(self);
+
     if (!self->txn) {
         PyObject *t =  Py_BuildValue("(is)", 0, "DBTxn must not be used "
-                                     "after txn_commit or txn_abort");
+                                     "after txn_commit, txn_abort "
+                                     "or txn_discard");
         PyErr_SetObject(DBError, t);
         Py_DECREF(t);
         return NULL;
     }
+    self->flag_prepare=0;
     txn = self->txn;
     self->txn = NULL;   /* this DB_TXN is no longer valid after this call */
+
+    EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
+
     MYDB_BEGIN_ALLOW_THREADS;
 #if (DBVER >= 40)
     err = txn->commit(txn, flags);
@@ -4606,6 +5472,9 @@
     err = txn_commit(txn, flags);
 #endif
     MYDB_END_ALLOW_THREADS;
+
+    _promote_transaction_dbs_and_sequences(self);
+
     RETURN_IF_ERR();
     RETURN_NONE();
 }
@@ -4629,11 +5498,13 @@
 
     if (!self->txn) {
         PyObject *t = Py_BuildValue("(is)", 0,"DBTxn must not be used "
-                                    "after txn_commit or txn_abort");
+                                    "after txn_commit, txn_abort "
+                                    "or txn_discard");
         PyErr_SetObject(DBError, t);
         Py_DECREF(t);
         return NULL;
     }
+    self->flag_prepare=1;  /* Prepare state */
     MYDB_BEGIN_ALLOW_THREADS;
 #if (DBVER >= 40)
     err = self->txn->prepare(self->txn, (u_int8_t*)gid);
@@ -4651,7 +5522,8 @@
 
     if (!self->txn) {
         PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
-                                    "after txn_commit or txn_abort");
+                                    "after txn_commit, txn_abort "
+                                    "or txn_discard");
         PyErr_SetObject(DBError, t);
         Py_DECREF(t);
         return NULL;
@@ -4666,34 +5538,87 @@
 
 
 static PyObject*
-DBTxn_abort(DBTxnObject* self, PyObject* args)
+DBTxn_abort_discard_internal(DBTxnObject* self, int discard)
 {
-    int err;
+    PyObject *dummy;
+    int err=0;
     DB_TXN *txn;
 
-    if (!PyArg_ParseTuple(args, ":abort"))
-        return NULL;
-
     if (!self->txn) {
         PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
-                                    "after txn_commit or txn_abort");
+                                    "after txn_commit, txn_abort "
+                                    "or txn_discard");
         PyErr_SetObject(DBError, t);
         Py_DECREF(t);
         return NULL;
     }
     txn = self->txn;
     self->txn = NULL;   /* this DB_TXN is no longer valid after this call */
+
+    _close_transaction_cursors(self);
+#if (DBVER >= 43)
+    while (self->children_sequences) {
+        dummy=DBSequence_close_internal(self->children_sequences,0,0);
+        Py_XDECREF(dummy);
+    }
+#endif
+    while (self->children_dbs) {
+        dummy=DB_close_internal(self->children_dbs,0);
+        Py_XDECREF(dummy);
+    }
+
+    EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
+
     MYDB_BEGIN_ALLOW_THREADS;
+    if (discard) {
+        assert(!self->flag_prepare);
+#if (DBVER >= 40)
+        err = txn->discard(txn,0);
+#else
+        err = txn_discard(txn);
+#endif
+    } else {
+        /*
+        ** If the transaction is in the "prepare" or "recover" state,
+        ** we better do not implicitly abort it.
+        */
+        if (!self->flag_prepare) {
 #if (DBVER >= 40)
-    err = txn->abort(txn);
+            err = txn->abort(txn);
 #else
-    err = txn_abort(txn);
+            err = txn_abort(txn);
 #endif
+        }
+    }
     MYDB_END_ALLOW_THREADS;
     RETURN_IF_ERR();
     RETURN_NONE();
 }
 
+static PyObject*
+DBTxn_abort(DBTxnObject* self, PyObject* args)
+{
+    if (!PyArg_ParseTuple(args, ":abort"))
+        return NULL;
+
+    self->flag_prepare=0;
+    _close_transaction_cursors(self);
+
+    return DBTxn_abort_discard_internal(self,0);
+}
+
+static PyObject*
+DBTxn_discard(DBTxnObject* self, PyObject* args)
+{
+    if (!PyArg_ParseTuple(args, ":discard"))
+        return NULL;
+
+    self->flag_prepare=0;
+    _close_transaction_cursors(self);
+
+    return DBTxn_abort_discard_internal(self,1);
+}
+
 
 static PyObject*
 DBTxn_id(DBTxnObject* self, PyObject* args)
@@ -4705,7 +5630,8 @@
 
     if (!self->txn) {
         PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
-                                    "after txn_commit or txn_abort");
+                                    "after txn_commit, txn_abort "
+                                    "or txn_discard");
         PyErr_SetObject(DBError, t);
         Py_DECREF(t);
         return NULL;
@@ -4726,24 +5652,41 @@
 
 
 static PyObject*
-DBSequence_close(DBSequenceObject* self, PyObject* args)
+DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close)
 {
-    int err, flags=0;
-    if (!PyArg_ParseTuple(args,"|i:close", &flags))
-        return NULL;
-    CHECK_SEQUENCE_NOT_CLOSED(self)
+    int err=0;
 
-    MYDB_BEGIN_ALLOW_THREADS
-    err = self->sequence->close(self->sequence, flags);
-    self->sequence = NULL;
-    MYDB_END_ALLOW_THREADS
+    if (self->sequence!=NULL) {
+        EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
+        if (self->txn) {
+            EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
+            self->txn=NULL;
+        }
 
-    RETURN_IF_ERR();
+        if (!do_not_close) {
+            MYDB_BEGIN_ALLOW_THREADS
+            err = self->sequence->close(self->sequence, flags);
+            MYDB_END_ALLOW_THREADS
+        }
+        self->sequence = NULL;
+
+        RETURN_IF_ERR();
+    }
 
     RETURN_NONE();
 }
 
 static PyObject*
+DBSequence_close(DBSequenceObject* self, PyObject* args)
+{
+    int flags=0;
+    if (!PyArg_ParseTuple(args,"|i:close", &flags))
+        return NULL;
+
+    return DBSequence_close_internal(self,flags,0);
+}
+
+static PyObject*
 DBSequence_get(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
 {
     int err, flags = 0;
@@ -4765,7 +5708,6 @@
 
     RETURN_IF_ERR();
     return PyLong_FromLongLong(value);
-
 }
 
 static PyObject*
@@ -4784,6 +5726,10 @@
     int err;
     DBT key;
     PyObject *retval = NULL;
+
+    if (!PyArg_ParseTuple(args,":get_key"))
+        return NULL;
+
     key.flags = DB_DBT_MALLOC;
     CHECK_SEQUENCE_NOT_CLOSED(self)
     MYDB_BEGIN_ALLOW_THREADS
@@ -4791,7 +5737,7 @@
     MYDB_END_ALLOW_THREADS
 
     if (!err)
-        retval = PyString_FromStringAndSize(key.data, key.size); 
+        retval = Build_PyString(key.data, key.size); 
 
     FREE_DBT(key);
     RETURN_IF_ERR();
@@ -4803,13 +5749,15 @@
 DBSequence_init_value(DBSequenceObject* self, PyObject* args)
 {
     int err;
-    db_seq_t value;
+    PY_LONG_LONG value;
+    db_seq_t value2;
     if (!PyArg_ParseTuple(args,"L:init_value", &value))
         return NULL;
     CHECK_SEQUENCE_NOT_CLOSED(self)
 
+    value2=value; /* If truncation, compiler should show a warning */
     MYDB_BEGIN_ALLOW_THREADS
-    err = self->sequence->initial_value(self->sequence, value);
+    err = self->sequence->initial_value(self->sequence, value2);
     MYDB_END_ALLOW_THREADS
 
     RETURN_IF_ERR();
@@ -4843,12 +5791,18 @@
     CLEAR_DBT(key);
     RETURN_IF_ERR();
 
+    if (txn) {
+        INSERT_IN_DOUBLE_LINKED_LIST_TXN(((DBTxnObject *)txnobj)->children_sequences,self);
+        self->txn=(DBTxnObject *)txnobj;
+    }
+
     RETURN_NONE();
 }
 
 static PyObject*
 DBSequence_remove(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
 {
+    PyObject *dummy;
     int err, flags = 0;
     PyObject *txnobj = NULL;
     DB_TXN *txn = NULL;
@@ -4866,6 +5820,9 @@
     err = self->sequence->remove(self->sequence, txn, flags);
     MYDB_END_ALLOW_THREADS
 
+    dummy=DBSequence_close_internal(self,flags,1);
+    Py_XDECREF(dummy);
+
     RETURN_IF_ERR();
     RETURN_NONE();
 }
@@ -4916,7 +5873,6 @@
 
     RETURN_IF_ERR();
     RETURN_NONE();
-
 }
 
 static PyObject*
@@ -4940,13 +5896,16 @@
 DBSequence_set_range(DBSequenceObject* self, PyObject* args)
 {
     int err;
-    db_seq_t min, max;
+    PY_LONG_LONG min, max;
+    db_seq_t min2, max2;
     if (!PyArg_ParseTuple(args,"(LL):set_range", &min, &max))
         return NULL;
     CHECK_SEQUENCE_NOT_CLOSED(self)
 
+    min2=min;  /* If truncation, compiler should show a warning */
+    max2=max;
     MYDB_BEGIN_ALLOW_THREADS
-    err = self->sequence->set_range(self->sequence, min, max);
+    err = self->sequence->set_range(self->sequence, min2, max2);
     MYDB_END_ALLOW_THREADS
 
     RETURN_IF_ERR();
@@ -4957,16 +5916,19 @@
 DBSequence_get_range(DBSequenceObject* self, PyObject* args)
 {
     int err;
-    db_seq_t min, max;
+    PY_LONG_LONG min, max;
+    db_seq_t min2, max2;
     if (!PyArg_ParseTuple(args,":get_range"))
         return NULL;
     CHECK_SEQUENCE_NOT_CLOSED(self)
 
     MYDB_BEGIN_ALLOW_THREADS
-    err = self->sequence->get_range(self->sequence, &min, &max);
+    err = self->sequence->get_range(self->sequence, &min2, &max2);
     MYDB_END_ALLOW_THREADS
 
     RETURN_IF_ERR();
+    min=min2;  /* If truncation, compiler should show a warning */
+    max=max2;
     return Py_BuildValue("(LL)", min, max);
 }
 
@@ -5134,6 +6096,9 @@
     {"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_VARARGS},
+#endif
 #if (DBVER >= 33)
     {"set_lg_regionmax",(PyCFunction)DBEnv_set_lg_regionmax, METH_VARARGS},
 #endif
@@ -5161,12 +6126,55 @@
     {"lock_stat",       (PyCFunction)DBEnv_lock_stat,        METH_VARARGS},
     {"log_archive",     (PyCFunction)DBEnv_log_archive,      METH_VARARGS},
 #if (DBVER >= 40)
+    {"log_flush",       (PyCFunction)DBEnv_log_flush,       METH_VARARGS},
+#endif
+#if (DBVER >= 40)
     {"log_stat",        (PyCFunction)DBEnv_log_stat,         METH_VARARGS},
 #endif
 #if (DBVER >= 44)
     {"lsn_reset",       (PyCFunction)DBEnv_lsn_reset,        METH_VARARGS|METH_KEYWORDS},
 #endif
     {"set_get_returns_none",(PyCFunction)DBEnv_set_get_returns_none, METH_VARARGS},
+#if (DBVER >= 40)
+    {"txn_recover",     (PyCFunction)DBEnv_txn_recover,       METH_VARARGS},
+#endif
+#if (DBVER >= 40)
+    {"set_verbose",     (PyCFunction)DBEnv_set_verbose,       METH_VARARGS},
+#if (DBVER >= 42)
+    {"get_verbose",     (PyCFunction)DBEnv_get_verbose,       METH_VARARGS},
+#endif
+#endif
+#if (DBVER >= 45)
+    {"set_event_notify", (PyCFunction)DBEnv_set_event_notify, METH_VARARGS},
+#endif
+#if (DBVER >= 45)
+    {"rep_set_nsites", (PyCFunction)DBEnv_rep_set_nsites, METH_VARARGS},
+    {"rep_get_nsites", (PyCFunction)DBEnv_rep_get_nsites, METH_VARARGS},
+    {"rep_set_priority", (PyCFunction)DBEnv_rep_set_priority, METH_VARARGS},
+    {"rep_get_priority", (PyCFunction)DBEnv_rep_get_priority, METH_VARARGS},
+    {"rep_set_timeout", (PyCFunction)DBEnv_rep_set_timeout, METH_VARARGS},
+    {"rep_get_timeout", (PyCFunction)DBEnv_rep_get_timeout, METH_VARARGS},
+#endif
+#if (DBVER >= 45)
+    {"repmgr_start", (PyCFunction)DBEnv_repmgr_start,
+        METH_VARARGS|METH_KEYWORDS},
+    {"repmgr_set_local_site", (PyCFunction)DBEnv_repmgr_set_local_site,
+        METH_VARARGS|METH_KEYWORDS},
+    {"repmgr_add_remote_site", (PyCFunction)DBEnv_repmgr_add_remote_site,
+        METH_VARARGS|METH_KEYWORDS},
+    {"repmgr_set_ack_policy", (PyCFunction)DBEnv_repmgr_set_ack_policy,
+        METH_VARARGS},
+    {"repmgr_get_ack_policy", (PyCFunction)DBEnv_repmgr_get_ack_policy,
+        METH_VARARGS},
+    {"repmgr_site_list", (PyCFunction)DBEnv_repmgr_site_list,
+        METH_VARARGS},
+#endif
+#if (DBVER >= 46)
+    {"repmgr_stat", (PyCFunction)DBEnv_repmgr_stat,
+        METH_VARARGS|METH_KEYWORDS},
+    {"repmgr_stat_print", (PyCFunction)DBEnv_repmgr_stat_print,
+        METH_VARARGS|METH_KEYWORDS},
+#endif
     {NULL,      NULL}       /* sentinel */
 };
 
@@ -5174,6 +6182,7 @@
 static PyMethodDef DBTxn_methods[] = {
     {"commit",          (PyCFunction)DBTxn_commit,      METH_VARARGS},
     {"prepare",         (PyCFunction)DBTxn_prepare,     METH_VARARGS},
+    {"discard",         (PyCFunction)DBTxn_discard,     METH_VARARGS},
     {"abort",           (PyCFunction)DBTxn_abort,       METH_VARARGS},
     {"id",              (PyCFunction)DBTxn_id,          METH_VARARGS},
     {NULL,      NULL}       /* sentinel */
@@ -5212,11 +6221,17 @@
 DBEnv_getattr(DBEnvObject* self, char *name)
 {
     if (!strcmp(name, "db_home")) {
-        CHECK_ENV_NOT_CLOSED(self);
-        if (self->db_env->db_home == NULL) {
-            RETURN_NONE();
-        }
-        return PyString_FromString(self->db_env->db_home);
+      const char *home = NULL;
+      CHECK_ENV_NOT_CLOSED(self);
+#if (DBVER >= 42)
+      self->db_env->get_home(self->db_env, &home);
+#else
+      home=self->db_env->db_home;
+#endif
+      if (home == NULL) {
+          RETURN_NONE();
+      }
+      return PyString_FromString(home);
     }
 
     return Py_FindMethod(DBEnv_methods, (PyObject* )self, name);
@@ -5582,7 +6597,7 @@
     ADD_INT(d, DB_RPCCLIENT);
 #else
     ADD_INT(d, DB_CLIENT);
-    /* allow apps to be written using DB_RPCCLIENT on older BerkeleyDB */
+    /* allow apps to be written using DB_RPCCLIENT on older Berkeley DB */
     _addIntToDict(d, "DB_RPCCLIENT", DB_CLIENT);
 #endif
     ADD_INT(d, DB_XA_CREATE);
@@ -5590,6 +6605,9 @@
     ADD_INT(d, DB_CREATE);
     ADD_INT(d, DB_NOMMAP);
     ADD_INT(d, DB_THREAD);
+#if (DBVER >= 45)
+    ADD_INT(d, DB_MULTIVERSION);
+#endif
 
     ADD_INT(d, DB_FORCE);
     ADD_INT(d, DB_INIT_CDB);
@@ -5599,6 +6617,10 @@
     ADD_INT(d, DB_INIT_TXN);
     ADD_INT(d, DB_JOINENV);
 
+#if (DBVER >= 40)
+    ADD_INT(d, DB_XIDDATASIZE);
+#endif
+
     ADD_INT(d, DB_RECOVER);
     ADD_INT(d, DB_RECOVER_FATAL);
     ADD_INT(d, DB_TXN_NOSYNC);
@@ -5645,6 +6667,13 @@
     ADD_INT(d, DB_LOCK_MINWRITE);
 #endif
 
+#if (DBVER >= 40)
+    ADD_INT(d, DB_LOCK_EXPIRE);
+#endif
+#if (DBVER >= 43)
+    ADD_INT(d, DB_LOCK_MAXWRITE);
+#endif
+
 
 #if (DBVER >= 33)
     /* docs say to use zero instead */
@@ -5816,6 +6845,10 @@
     ADD_INT(d, DB_NOPANIC);
 #endif
 
+#if (DBVER >= 41)
+    ADD_INT(d, DB_OVERWRITE);
+#endif
+
 #ifdef DB_REGISTER
     ADD_INT(d, DB_REGISTER);
 #endif
@@ -5832,7 +6865,76 @@
     ADD_INT(d, DB_CHKSUM);
 #endif
 
+#if (DBVER >= 44)
+    ADD_INT(d, DB_DSYNC_DB);
+#endif
+
+#if (DBVER >= 45)
+    ADD_INT(d, DB_TXN_SNAPSHOT);
+#endif
+
+#if (DBVER >= 40)
+    ADD_INT(d, DB_VERB_DEADLOCK);
+#if (DBVER >= 46)
+    ADD_INT(d, DB_VERB_FILEOPS);
+    ADD_INT(d, DB_VERB_FILEOPS_ALL);
+#endif
+    ADD_INT(d, DB_VERB_RECOVERY);
+#if (DBVER >= 44)
+    ADD_INT(d, DB_VERB_REGISTER);
+#endif
+    ADD_INT(d, DB_VERB_REPLICATION);
+    ADD_INT(d, DB_VERB_WAITSFOR);
+#endif
+
+#if (DBVER >= 45)
+    ADD_INT(d, DB_EVENT_PANIC);
+    ADD_INT(d, DB_EVENT_REP_CLIENT);
+#if (DBVER >= 46)
+    ADD_INT(d, DB_EVENT_REP_ELECTED);
+#endif
+    ADD_INT(d, DB_EVENT_REP_MASTER);
+    ADD_INT(d, DB_EVENT_REP_NEWMASTER);
+#if (DBVER >= 46)
+    ADD_INT(d, DB_EVENT_REP_PERM_FAILED);
+#endif
+    ADD_INT(d, DB_EVENT_REP_STARTUPDONE);
+    ADD_INT(d, DB_EVENT_WRITE_FAILED);
+#endif
+
+#if (DBVER >= 40)
+    ADD_INT(d, DB_REP_MASTER);
+    ADD_INT(d, DB_REP_CLIENT);
+#if (DBVER >= 45)
+    ADD_INT(d, DB_REP_ELECTION);
+
+    ADD_INT(d, DB_REP_ACK_TIMEOUT);
+    ADD_INT(d, DB_REP_CONNECTION_RETRY);
+    ADD_INT(d, DB_REP_ELECTION_TIMEOUT);
+    ADD_INT(d, DB_REP_ELECTION_RETRY);
+#endif
+#if (DBVER >= 46)
+    ADD_INT(d, DB_REP_CHECKPOINT_DELAY);
+    ADD_INT(d, DB_REP_FULL_ELECTION_TIMEOUT);
+#endif
+#endif
+
+#if (DBVER >= 45)
+    ADD_INT(d, DB_REPMGR_PEER);
+    ADD_INT(d, DB_REPMGR_ACKS_ALL);
+    ADD_INT(d, DB_REPMGR_ACKS_ALL_PEERS);
+    ADD_INT(d, DB_REPMGR_ACKS_NONE);
+    ADD_INT(d, DB_REPMGR_ACKS_ONE);
+    ADD_INT(d, DB_REPMGR_ACKS_ONE_PEER);
+    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
+
 #if (DBVER >= 43)
+    ADD_INT(d, DB_DSYNC_LOG);
     ADD_INT(d, DB_LOG_INMEMORY);
     ADD_INT(d, DB_BUFFER_SMALL);
     ADD_INT(d, DB_SEQ_DEC);
@@ -5844,7 +6946,7 @@
     ADD_INT(d, DB_ENCRYPT_AES);
     ADD_INT(d, DB_AUTO_COMMIT);
 #else
-    /* allow berkeleydb 4.1 aware apps to run on older versions */
+    /* allow Berkeley DB 4.1 aware apps to run on older versions */
     _addIntToDict(d, "DB_AUTO_COMMIT", 0);
 #endif
 
@@ -5920,6 +7022,10 @@
     MAKE_EX(DBNoSuchFileError);
     MAKE_EX(DBPermissionsError);
 
+#if (DBVER >= 42)
+    MAKE_EX(DBRepHandleDeadError);
+#endif
+
 #undef MAKE_EX
 
     /* Initiliase the C API structure and add it to the module */

Modified: python/trunk/Modules/bsddb.h
==============================================================================
--- python/trunk/Modules/bsddb.h	(original)
+++ python/trunk/Modules/bsddb.h	Tue May 13 20:45:46 2008
@@ -36,7 +36,7 @@
 /*
  * Handwritten code to wrap version 3.x of the Berkeley DB library,
  * written to replace a SWIG-generated file.  It has since been updated
- * to compile with BerkeleyDB versions 3.2 through 4.2.
+ * to compile with Berkeley DB versions 3.2 through 4.2.
  *
  * This module was started by Andrew Kuchling to remove the dependency
  * on SWIG in a package by Gregory P. Smith who based his work on a
@@ -105,7 +105,7 @@
 #error "eek! DBVER can't handle minor versions > 9"
 #endif
 
-#define PY_BSDDB_VERSION "4.6.0"
+#define PY_BSDDB_VERSION "4.6.5devel2"
 
 /* Python object definitions */
 
@@ -119,17 +119,27 @@
 };
 
 
+
+struct DBObject;          /* Forward declaration */
+struct DBCursorObject;    /* Forward declaration */
+struct DBTxnObject;       /* Forward declaration */
+struct DBSequenceObject;  /* Forward declaration */
+
 typedef struct {
     PyObject_HEAD
     DB_ENV*     db_env;
     u_int32_t   flags;             /* saved flags from open() */
     int         closed;
     struct behaviourFlags moduleFlags;
+#if (DBVER >= 40)
+    PyObject*       event_notifyCallback;
+#endif
+    struct DBObject *children_dbs;
+    struct DBTxnObject *children_txns;
     PyObject        *in_weakreflist; /* List of weak references */
 } DBEnvObject;
 
-
-typedef struct {
+typedef struct DBObject {
     PyObject_HEAD
     DB*             db;
     DBEnvObject*    myenvobj;  /* PyObject containing the DB_ENV */
@@ -137,6 +147,15 @@
     u_int32_t       setflags;  /* saved flags from set_flags() */
     int             haveStat;
     struct behaviourFlags moduleFlags;
+    struct DBTxnObject *txn;
+    struct DBCursorObject *children_cursors;
+#if (DBVER >=43)
+    struct DBSequenceObject *children_sequences;
+#endif
+    struct DBObject **sibling_prev_p;
+    struct DBObject *sibling_next;
+    struct DBObject **sibling_prev_p_txn;
+    struct DBObject *sibling_next_txn;
 #if (DBVER >= 33)
     PyObject*       associateCallback;
     PyObject*       btCompareCallback;
@@ -146,18 +165,31 @@
 } DBObject;
 
 
-typedef struct {
+typedef struct DBCursorObject {
     PyObject_HEAD
     DBC*            dbc;
+    struct DBCursorObject **sibling_prev_p;
+    struct DBCursorObject *sibling_next;
+    struct DBCursorObject **sibling_prev_p_txn;
+    struct DBCursorObject *sibling_next_txn;
     DBObject*       mydb;
+    struct DBTxnObject *txn;
     PyObject        *in_weakreflist; /* List of weak references */
 } DBCursorObject;
 
 
-typedef struct {
+typedef struct DBTxnObject {
     PyObject_HEAD
     DB_TXN*         txn;
-    PyObject        *env;
+    DBEnvObject*    env;
+    int             flag_prepare;
+    struct DBTxnObject *parent_txn;
+    struct DBTxnObject **sibling_prev_p;
+    struct DBTxnObject *sibling_next;
+    struct DBTxnObject *children_txns;
+    struct DBObject *children_dbs;
+    struct DBSequenceObject *children_sequences;
+    struct DBCursorObject *children_cursors;
     PyObject        *in_weakreflist; /* List of weak references */
 } DBTxnObject;
 
@@ -170,13 +202,17 @@
 
 
 #if (DBVER >= 43)
-typedef struct {
+typedef struct DBSequenceObject {
     PyObject_HEAD
     DB_SEQUENCE*     sequence;
     DBObject*        mydb;
+    struct DBTxnObject *txn;
+    struct DBSequenceObject **sibling_prev_p;
+    struct DBSequenceObject *sibling_next;
+    struct DBSequenceObject **sibling_prev_p_txn;
+    struct DBSequenceObject *sibling_next_txn;
     PyObject        *in_weakreflist; /* List of weak references */
 } DBSequenceObject;
-staticforward PyTypeObject DBSequence_Type;
 #endif
 
 


More information about the Python-checkins mailing list