diff options
-rw-r--r-- | Modules/_bsddb.c | 134 |
1 files changed, 127 insertions, 7 deletions
diff --git a/Modules/_bsddb.c b/Modules/_bsddb.c index 2785f28..e00a64c 100644 --- a/Modules/_bsddb.c +++ b/Modules/_bsddb.c @@ -194,6 +194,13 @@ static PyObject* DBPermissionsError; /* EPERM */ #undef HAVE_WEAKREF #endif +/* if Python >= 2.1 better support warnings */ +#if PYTHON_API_VERSION >= 1010 +#define HAVE_WARNINGS +#else +#undef HAVE_WARNINGS +#endif + struct behaviourFlags { /* What is the default behaviour when DB->get or DBCursor->get returns a DB_NOTFOUND error? Return None or raise an exception? */ @@ -212,6 +219,9 @@ typedef struct { u_int32_t flags; /* saved flags from open() */ int closed; struct behaviourFlags moduleFlags; +#ifdef HAVE_WEAKREF + PyObject *in_weakreflist; /* List of weak references */ +#endif } DBEnvObject; @@ -227,6 +237,9 @@ typedef struct { PyObject* associateCallback; int primaryDBType; #endif +#ifdef HAVE_WEAKREF + PyObject *in_weakreflist; /* List of weak references */ +#endif } DBObject; @@ -243,12 +256,18 @@ typedef struct { typedef struct { PyObject_HEAD DB_TXN* txn; +#ifdef HAVE_WEAKREF + PyObject *in_weakreflist; /* List of weak references */ +#endif } DBTxnObject; typedef struct { PyObject_HEAD DB_LOCK lock; +#ifdef HAVE_WEAKREF + PyObject *in_weakreflist; /* List of weak references */ +#endif } DBLockObject; @@ -467,8 +486,7 @@ static int makeDBError(int err) strcat(errTxt, _db_errmsg); _db_errmsg[0] = 0; } -/* if Python 2.1 or better use warning framework */ -#if PYTHON_API_VERSION >= 1010 +#ifdef HAVE_WARNINGS exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt); #else fprintf(stderr, errTxt); @@ -697,6 +715,9 @@ newDBObject(DBEnvObject* arg, int flags) self->associateCallback = NULL; self->primaryDBType = 0; #endif +#ifdef HAVE_WEAKREF + self->in_weakreflist = NULL; +#endif /* keep a reference to our python DBEnv object */ if (arg) { @@ -718,6 +739,9 @@ newDBObject(DBEnvObject* arg, int flags) self->db->app_private = (void*)self; #endif MYDB_END_ALLOW_THREADS; + /* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs + * list so that a DBEnv can refuse to close without aborting any open + * open DBTxns and closing any open DBs first. */ if (makeDBError(err)) { if (self->myenvobj) { Py_DECREF(self->myenvobj); @@ -741,8 +765,7 @@ DB_dealloc(DBObject* self) MYDB_BEGIN_ALLOW_THREADS; self->db->close(self->db, 0); MYDB_END_ALLOW_THREADS; - /* if Python 2.1 or better use warning framework */ -#if PYTHON_API_VERSION >= 1010 +#ifdef HAVE_WARNINGS } else { PyErr_Warn(PyExc_RuntimeWarning, "DB could not be closed in destructor: DBEnv already closed"); @@ -750,6 +773,11 @@ DB_dealloc(DBObject* self) } self->db = NULL; } +#ifdef HAVE_WEAKREF + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *) self); + } +#endif if (self->myenvobj) { Py_DECREF(self->myenvobj); self->myenvobj = NULL; @@ -842,6 +870,9 @@ newDBEnvObject(int flags) self->flags = flags; self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE; self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE; +#ifdef HAVE_WEAKREF + self->in_weakreflist = NULL; +#endif MYDB_BEGIN_ALLOW_THREADS; err = db_env_create(&self->db_env, flags); @@ -859,6 +890,12 @@ newDBEnvObject(int flags) static void DBEnv_dealloc(DBEnvObject* self) { +#ifdef HAVE_WEAKREF + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *) self); + } +#endif + if (!self->closed) { MYDB_BEGIN_ALLOW_THREADS; self->db_env->close(self->db_env, 0); @@ -885,6 +922,9 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags) #endif if (self == NULL) return NULL; +#ifdef HAVE_WEAKREF + self->in_weakreflist = NULL; +#endif MYDB_BEGIN_ALLOW_THREADS; #if (DBVER >= 40) @@ -892,6 +932,9 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags) #else err = txn_begin(myenv->db_env, parent, &(self->txn), flags); #endif + /* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs + * list so that a DBEnv can refuse to close without aborting any open + * open DBTxns and closing any open DBs first. */ MYDB_END_ALLOW_THREADS; if (makeDBError(err)) { self = NULL; @@ -903,9 +946,26 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags) static void DBTxn_dealloc(DBTxnObject* self) { - /* XXX nothing to do for transaction objects?!? */ +#ifdef HAVE_WEAKREF + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *) self); + } +#endif - /* TODO: if it hasn't been commited, should we abort it? */ +#ifdef HAVE_WARNINGS + 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()."); + } +#endif #if PYTHON_API_VERSION <= 1007 PyMem_DEL(self); @@ -929,6 +989,9 @@ newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj, #endif if (self == NULL) return NULL; +#ifdef HAVE_WEAKREF + self->in_weakreflist = NULL; +#endif MYDB_BEGIN_ALLOW_THREADS; #if (DBVER >= 40) @@ -949,7 +1012,12 @@ newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj, static void DBLock_dealloc(DBLockObject* self) { - /* TODO: if it hasn't been released, should we do it? */ +#ifdef HAVE_WEAKREF + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *) self); + } +#endif + /* TODO: is this lock held? should we release it? */ #if PYTHON_API_VERSION <= 1007 PyMem_DEL(self); @@ -4305,6 +4373,19 @@ statichere PyTypeObject DB_Type = { 0, /*tp_as_sequence*/ &DB_mapping,/*tp_as_mapping*/ 0, /*tp_hash*/ +#ifdef HAVE_WEAKREF + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(DBObject, in_weakreflist), /* tp_weaklistoffset */ +#endif }; @@ -4358,6 +4439,19 @@ statichere PyTypeObject DBEnv_Type = { 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ +#ifdef HAVE_WEAKREF + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(DBEnvObject, in_weakreflist), /* tp_weaklistoffset */ +#endif }; statichere PyTypeObject DBTxn_Type = { @@ -4377,6 +4471,19 @@ statichere PyTypeObject DBTxn_Type = { 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ +#ifdef HAVE_WEAKREF + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(DBTxnObject, in_weakreflist), /* tp_weaklistoffset */ +#endif }; @@ -4397,6 +4504,19 @@ statichere PyTypeObject DBLock_Type = { 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ +#ifdef HAVE_WEAKREF + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(DBLockObject, in_weakreflist), /* tp_weaklistoffset */ +#endif }; |