summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesus Cea <jcea@jcea.es>2008-05-13 18:45:46 (GMT)
committerJesus Cea <jcea@jcea.es>2008-05-13 18:45:46 (GMT)
commitef9764f1a479808b340c16bcfdb0cd6838465ea9 (patch)
treea2539d1290a1fdd110d6389ad2b9ecdbee256c78
parentbbb093751c776b3e83d31fec941de563a15c56b6 (diff)
downloadcpython-ef9764f1a479808b340c16bcfdb0cd6838465ea9.zip
cpython-ef9764f1a479808b340c16bcfdb0cd6838465ea9.tar.gz
cpython-ef9764f1a479808b340c16bcfdb0cd6838465ea9.tar.bz2
bsddb module updated to version 4.6.4
-rw-r--r--Misc/NEWS2
-rw-r--r--Modules/_bsddb.c1690
-rw-r--r--Modules/bsddb.h54
3 files changed, 1445 insertions, 301 deletions
diff --git a/Misc/NEWS b/Misc/NEWS
index 123e2dc..9869c0f 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -25,6 +25,8 @@ Extension Modules
- Support for Windows9x has been removed from the winsound module.
+- bsddb module updated to version 4.6.4.
+
Library
-------
diff --git a/Modules/_bsddb.c b/Modules/_bsddb.c
index dc97427..04c7155 100644
--- a/Modules/_bsddb.c
+++ b/Modules/_bsddb.c
@@ -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@krypto.org> is once again the maintainer.
+ * Gregory P. Smith <greg@krypto.org> was once again the maintainer.
+ *
+ * Since January 2008, new maintainer is Jesus Cea <jcea@argo.es>.
+ * Jesus Cea licenses this code to PSF under a Contributor Agreement.
*
* Use the pybsddb-users@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* DBFileExistsError; /* EEXIST */
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 @@ static PyObject* DBPermissionsError; /* EPERM */
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 @@ staticforward PyTypeObject DB_Type, DBCursor_Type, DBEnv_Type, DBTxn_Type, DBLoc
#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 @@ static void _db_errorCallback(const DB_ENV *db_env,
}
+/*
+** 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 @@ static int makeDBError(int err)
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 @@ static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags,
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 @@ static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags,
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 @@ static void _addTimeTToDict(PyObject* dict, char *name, time_t value)
{
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 @@ static void _addDb_seq_tToDict(PyObject* dict, char *name, db_seq_t value)
}
#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 @@ newDBObject(DBEnvObject* arg, int flags)
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 @@ newDBObject(DBEnvObject* arg, int flags)
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 @@ newDBObject(DBEnvObject* arg, int flags)
}
+/* 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 @@ DB_dealloc(DBObject* self)
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 @@ newDBCursorObject(DBC* dbc, DBObject* db)
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 @@ newDBEnvObject(int flags)
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 @@ newDBEnvObject(int flags)
}
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 @@ newDBSequenceObject(DBObject* mydb, int flags)
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 @@ newDBSequenceObject(DBObject* mydb, int flags)
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 @@ _db_associateCallback(DB* db, const DBT* priKey, const DBT* priData,
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 @@ DB_associate(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
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 @@ _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
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 @@ DB_cursor(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
}
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 @@ DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs)
}
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 @@ DB_join(DBObject* self, PyObject* args)
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 @@ DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
#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 @@ DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
#endif
self->flags = flags;
+
RETURN_NONE();
}
@@ -1993,7 +2234,7 @@ _default_cmp(const DBT *leftKey,
}
static int
-_db_compareCallback(DB* db,
+_db_compareCallback(DB* db,
const DBT *leftKey,
const DBT *rightKey)
{
@@ -2015,8 +2256,7 @@ _db_compareCallback(DB* db,
} 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 @@ DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ DB_verify(DBObject* self, PyObject* args, PyObject* kwargs)
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 @@ redo_stat_for_length:
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 @@ PyObject* DB_subscript(DBObject* self, PyObject* keyobj)
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 @@ PyObject* DB_subscript(DBObject* self, PyObject* keyobj)
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 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
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 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
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 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
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 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
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 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
}
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 @@ DB_values(DBObject* self, PyObject* args)
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 @@ DBC_count(DBCursorObject* self, PyObject* args)
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 @@ DBC_delete(DBCursorObject* self, PyObject* args)
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 @@ DBC_dup(DBCursorObject* self, PyObject* args)
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 @@ DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
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 @@ DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
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 @@ DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
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 @@ DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
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 @@ DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
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 @@ DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
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 @@ DBC_get_recno(DBCursorObject* self, PyObject* args)
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 @@ DBC_put(DBCursorObject* self, PyObject* args, PyObject* kwargs)
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 @@ DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs)
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 @@ DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs)
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 @@ DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
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 @@ DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
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 @@ _DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
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 @@ _DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
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 @@ DBC_get_current_size(DBCursorObject* self, PyObject* args)
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 @@ DBC_get_current_size(DBCursorObject* self, PyObject* args)
err = 0;
}
- FREE_DBT(key);
- FREE_DBT(data);
RETURN_IF_ERR();
return retval;
}
@@ -3600,17 +3807,13 @@ DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
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 @@ DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
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 @@ DBC_join_item(DBCursorObject* self, PyObject* args)
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 @@ DBC_join_item(DBCursorObject* self, PyObject* args)
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 @@ DBC_join_item(DBCursorObject* self, PyObject* args)
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 @@ DBEnv_close(DBEnvObject* self, PyObject* args)
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,6 +4196,25 @@ DBEnv_set_lg_max(DBEnvObject* self, PyObject* args)
RETURN_NONE();
}
+#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*
@@ -4125,6 +4358,84 @@ DBEnv_set_tmp_dir(DBEnvObject* self, PyObject* args)
}
+#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 @@ DBEnv_txn_begin(DBEnvObject* self, PyObject* args, PyObject* kwargs)
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 @@ DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
#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 @@ DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
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 @@ DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
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,6 +4791,24 @@ DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
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)
@@ -4535,21 +4889,33 @@ DBEnv_txn_stat(DBEnvObject* self, PyObject* args)
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(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);
@@ -4576,11 +4942,504 @@ DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args)
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;
+ unsigned int countp;
+ DB_REPMGR_SITE *listp;
+ PyObject *stats, *key, *tuple;
+
+ if (!PyArg_ParseTuple(args, ":repmgr_site_list"))
+ {
+ return NULL;
+ }
+ CHECK_ENV_NOT_CLOSED(self);
+ MYDB_BEGIN_ALLOW_THREADS;
+ err = self->db_env->repmgr_site_list(self->db_env, &countp, &listp);
+ MYDB_END_ALLOW_THREADS;
+ RETURN_IF_ERR();
+
+ stats=PyDict_New();
+ if (stats == NULL) {
+ free(listp);
+ return NULL;
+ }
+
+ 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(listp);
+ return stats;
+}
+#endif
+
+#if (DBVER >= 46)
+static PyObject*
+DBEnv_repmgr_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
+{
+ int err;
+ int flags=0;
+ static char* kwnames[] = { "flags", NULL };
+
+ 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;
+ err = self->db_env->repmgr_stat(self->db_env, &statp, flags);
+ MYDB_END_ALLOW_THREADS;
+ RETURN_IF_ERR();
+
+ stats=PyDict_New();
+ if (stats == NULL) {
+ free(statp);
+ return NULL;
+ }
+
+#define MAKE_ENTRY(name) _addIntToDict(stats, #name, statp->st_##name)
+
+ MAKE_ENTRY(perm_failed);
+ MAKE_ENTRY(msgs_queued);
+ MAKE_ENTRY(msgs_dropped);
+ MAKE_ENTRY(connection_drop);
+ MAKE_ENTRY(connect_fail);
+
+#undef MAKE_ENTRY
+
+ free(statp);
+ return stats;
+}
+#endif
+
/* --------------------------------------------------------------------- */
/* DBTxn methods */
+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
+
+ 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*
DBTxn_commit(DBTxnObject* self, PyObject* args)
{
@@ -4590,15 +5449,22 @@ DBTxn_commit(DBTxnObject* self, PyObject* args)
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 @@ DBTxn_commit(DBTxnObject* self, PyObject* args)
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 @@ DBTxn_prepare(DBTxnObject* self, PyObject* args)
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 @@ DBTxn_prepare(DBTxnObject* self, PyObject* args)
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 @@ DBTxn_prepare(DBTxnObject* self, PyObject* args)
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 @@ DBTxn_id(DBTxnObject* self, PyObject* args)
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 @@ DBTxn_id(DBTxnObject* self, PyObject* args)
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 @@ DBSequence_get(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
RETURN_IF_ERR();
return PyLong_FromLongLong(value);
-
}
static PyObject*
@@ -4784,6 +5726,10 @@ DBSequence_get_key(DBSequenceObject* self, PyObject* args)
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 @@ DBSequence_get_key(DBSequenceObject* self, PyObject* args)
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 @@ static PyObject*
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 @@ DBSequence_open(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
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 @@ DBSequence_remove(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
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 @@ DBSequence_set_flags(DBSequenceObject* self, PyObject* args)
RETURN_IF_ERR();
RETURN_NONE();
-
}
static PyObject*
@@ -4940,13 +5896,16 @@ static PyObject*
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 @@ static PyObject*
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 @@ static PyMethodDef DBEnv_methods[] = {
{"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 @@ static PyMethodDef DBEnv_methods[] = {
{"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 DBEnv_methods[] = {
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 @@ static PyObject*
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 @@ DL_EXPORT(void) init_bsddb(void)
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 @@ DL_EXPORT(void) init_bsddb(void)
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 @@ DL_EXPORT(void) init_bsddb(void)
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 @@ DL_EXPORT(void) init_bsddb(void)
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 @@ DL_EXPORT(void) init_bsddb(void)
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 @@ DL_EXPORT(void) init_bsddb(void)
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 @@ DL_EXPORT(void) init_bsddb(void)
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 @@ DL_EXPORT(void) init_bsddb(void)
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 */
diff --git a/Modules/bsddb.h b/Modules/bsddb.h
index a209553..48444b5 100644
--- a/Modules/bsddb.h
+++ b/Modules/bsddb.h
@@ -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 behaviourFlags {
};
+
+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 @@ typedef struct {
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 @@ typedef struct {
} 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 @@ typedef struct {
#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