Commit 31c50659 authored by Gregory P. Smith's avatar Gregory P. Smith

Add weakref support to all bsddb.db objects.

Make DBTxn objects automatically call abort() in their destructor if
not yet finalized and raise a RuntimeWarning to that effect.
parent 11b91a0e
......@@ -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
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment