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.
This commit is contained in:
Gregory P. Smith 2004-06-28 01:20:40 +00:00
parent 11b91a0ea3
commit 31c50659ea

View file

@ -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
};