r63207 - in python/trunk: Misc/NEWS Modules/_bsddb.c Modules/bsddb.h
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@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* 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", ¬ifyFunc)) { + 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
On Tue, May 13, 2008 at 11:45 AM, jesus.cea <python-checkins@python.org> wrote:
Author: jesus.cea Date: Tue May 13 20:45:46 2008 New Revision: 63207
Log: bsddb module updated to version 4.6.4
It would be nicer to break this change into several. For example, the BuildValue changes could have been a separate change from everything else. I'm not sure of all the pieces, but I suspect there are more intertwined changes. The change is too big for me to find the issues in gmail editor. However, this line was added (actually moved): PyList_Append(list, item); There should be a check that this doesn't fail. Either check the call with if (PyList_Append() < 0) or at the end of the loop, check PyErr_Occurred(). In _close_transaction_cursors and DBTxn_abort_discard_internal there were return values from calls that were not checked. I'm not sure if you added either of these. One or both were the return result from Py_BuildValue. The value was passed to PyErr_SetError() I think. I'm not sure if that API can tolerate a NULL, but a Py_DECREF() followed and that definitely can't take a NULL. Depending on what version of Python you want to support, consider using PyTuple_Pack(). Also, you should use METH_O and METH_NOARGS rather than METH_VARARGS. That will make the code faster and smaller by removing useless calls to PyArg_ParseTuple(). You can also use PyArg_UnpackTuple() when you only need the PyObjects out of the args. n
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Comments implemented in my current SVN. Most of them are inherited by the original python svn implementation :-). Thanks for taking the time and effort, Neal. My current code will land in 2.6 trunk late this week, hoping somebody can guide me to be able to "import" the compiled module in python 3.0 (it already compiles, but importing it crashes the interpreter). Neal Norwitz wrote: | On Tue, May 13, 2008 at 11:45 AM, jesus.cea <python-checkins@python.org> wrote: |> Author: jesus.cea |> Date: Tue May 13 20:45:46 2008 |> New Revision: 63207 |> |> Log: |> bsddb module updated to version 4.6.4 | | It would be nicer to break this change into several. For example, the | BuildValue changes could have been a separate change from everything | else. I'm not sure of all the pieces, but I suspect there are more | intertwined changes. | | The change is too big for me to find the issues in gmail editor. | However, this line was added (actually moved): | | PyList_Append(list, item); | | There should be a check that this doesn't fail. Either check the call | with if (PyList_Append() < 0) or at the end of the loop, check | PyErr_Occurred(). | | In _close_transaction_cursors and DBTxn_abort_discard_internal there | were return values from calls that were not checked. I'm not sure if | you added either of these. One or both were the return result from | Py_BuildValue. The value was passed to PyErr_SetError() I think. I'm | not sure if that API can tolerate a NULL, but a Py_DECREF() followed | and that definitely can't take a NULL. | | Depending on what version of Python you want to support, consider | using PyTuple_Pack(). Also, you should use METH_O and METH_NOARGS | rather than METH_VARARGS. That will make the code faster and smaller | by removing useless calls to PyArg_ParseTuple(). You can also use | PyArg_UnpackTuple() when you only need the PyObjects out of the args. - -- Jesus Cea Avion _/_/ _/_/_/ _/_/_/ jcea@jcea.es - http://www.jcea.es/ _/_/ _/_/ _/_/ _/_/ _/_/ jabber / xmpp:jcea@jabber.org _/_/ _/_/ _/_/_/_/_/ . _/_/ _/_/ _/_/ _/_/ _/_/ "Things are not so easy" _/_/ _/_/ _/_/ _/_/ _/_/ _/_/ "My name is Dump, Core Dump" _/_/_/ _/_/_/ _/_/ _/_/ "El amor es poner tu felicidad en la felicidad de otro" - Leibniz -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.8 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iQCVAwUBSISNAJlgi5GaxT1NAQKbfQP9G8NRF+8FdbgT8QPzYeyQO8n9dchDfoQe MFArO7yWVhWqycuVjwrWq9fa2X7D8oszI0WwP4lWjCSDB/QyG+Vxmik8BzVkg+1n dSDTFSr+doqCttgkh1Qgm5dr6pt+8vIVPfpc1orw4wTI1a5Lx+c14AKOmtVs0nHA oDLn9+K9LZ8= =lOL3 -----END PGP SIGNATURE-----
participants (3)
-
Jesus Cea -
jesus.cea -
Neal Norwitz