summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/_bsddb.c134
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
};