Kaydet (Commit) 31c50659 authored tarafından 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.
üst 11b91a0e
...@@ -194,6 +194,13 @@ static PyObject* DBPermissionsError; /* EPERM */ ...@@ -194,6 +194,13 @@ static PyObject* DBPermissionsError; /* EPERM */
#undef HAVE_WEAKREF #undef HAVE_WEAKREF
#endif #endif
/* if Python >= 2.1 better support warnings */
#if PYTHON_API_VERSION >= 1010
#define HAVE_WARNINGS
#else
#undef HAVE_WARNINGS
#endif
struct behaviourFlags { struct behaviourFlags {
/* What is the default behaviour when DB->get or DBCursor->get returns a /* What is the default behaviour when DB->get or DBCursor->get returns a
DB_NOTFOUND error? Return None or raise an exception? */ DB_NOTFOUND error? Return None or raise an exception? */
...@@ -212,6 +219,9 @@ typedef struct { ...@@ -212,6 +219,9 @@ typedef struct {
u_int32_t flags; /* saved flags from open() */ u_int32_t flags; /* saved flags from open() */
int closed; int closed;
struct behaviourFlags moduleFlags; struct behaviourFlags moduleFlags;
#ifdef HAVE_WEAKREF
PyObject *in_weakreflist; /* List of weak references */
#endif
} DBEnvObject; } DBEnvObject;
...@@ -227,6 +237,9 @@ typedef struct { ...@@ -227,6 +237,9 @@ typedef struct {
PyObject* associateCallback; PyObject* associateCallback;
int primaryDBType; int primaryDBType;
#endif #endif
#ifdef HAVE_WEAKREF
PyObject *in_weakreflist; /* List of weak references */
#endif
} DBObject; } DBObject;
...@@ -243,12 +256,18 @@ typedef struct { ...@@ -243,12 +256,18 @@ typedef struct {
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
DB_TXN* txn; DB_TXN* txn;
#ifdef HAVE_WEAKREF
PyObject *in_weakreflist; /* List of weak references */
#endif
} DBTxnObject; } DBTxnObject;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
DB_LOCK lock; DB_LOCK lock;
#ifdef HAVE_WEAKREF
PyObject *in_weakreflist; /* List of weak references */
#endif
} DBLockObject; } DBLockObject;
...@@ -467,8 +486,7 @@ static int makeDBError(int err) ...@@ -467,8 +486,7 @@ static int makeDBError(int err)
strcat(errTxt, _db_errmsg); strcat(errTxt, _db_errmsg);
_db_errmsg[0] = 0; _db_errmsg[0] = 0;
} }
/* if Python 2.1 or better use warning framework */ #ifdef HAVE_WARNINGS
#if PYTHON_API_VERSION >= 1010
exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt); exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt);
#else #else
fprintf(stderr, errTxt); fprintf(stderr, errTxt);
...@@ -697,6 +715,9 @@ newDBObject(DBEnvObject* arg, int flags) ...@@ -697,6 +715,9 @@ newDBObject(DBEnvObject* arg, int flags)
self->associateCallback = NULL; self->associateCallback = NULL;
self->primaryDBType = 0; self->primaryDBType = 0;
#endif #endif
#ifdef HAVE_WEAKREF
self->in_weakreflist = NULL;
#endif
/* keep a reference to our python DBEnv object */ /* keep a reference to our python DBEnv object */
if (arg) { if (arg) {
...@@ -718,6 +739,9 @@ newDBObject(DBEnvObject* arg, int flags) ...@@ -718,6 +739,9 @@ newDBObject(DBEnvObject* arg, int flags)
self->db->app_private = (void*)self; self->db->app_private = (void*)self;
#endif #endif
MYDB_END_ALLOW_THREADS; 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 (makeDBError(err)) {
if (self->myenvobj) { if (self->myenvobj) {
Py_DECREF(self->myenvobj); Py_DECREF(self->myenvobj);
...@@ -741,8 +765,7 @@ DB_dealloc(DBObject* self) ...@@ -741,8 +765,7 @@ DB_dealloc(DBObject* self)
MYDB_BEGIN_ALLOW_THREADS; MYDB_BEGIN_ALLOW_THREADS;
self->db->close(self->db, 0); self->db->close(self->db, 0);
MYDB_END_ALLOW_THREADS; MYDB_END_ALLOW_THREADS;
/* if Python 2.1 or better use warning framework */ #ifdef HAVE_WARNINGS
#if PYTHON_API_VERSION >= 1010
} else { } else {
PyErr_Warn(PyExc_RuntimeWarning, PyErr_Warn(PyExc_RuntimeWarning,
"DB could not be closed in destructor: DBEnv already closed"); "DB could not be closed in destructor: DBEnv already closed");
...@@ -750,6 +773,11 @@ DB_dealloc(DBObject* self) ...@@ -750,6 +773,11 @@ DB_dealloc(DBObject* self)
} }
self->db = NULL; self->db = NULL;
} }
#ifdef HAVE_WEAKREF
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
}
#endif
if (self->myenvobj) { if (self->myenvobj) {
Py_DECREF(self->myenvobj); Py_DECREF(self->myenvobj);
self->myenvobj = NULL; self->myenvobj = NULL;
...@@ -842,6 +870,9 @@ newDBEnvObject(int flags) ...@@ -842,6 +870,9 @@ newDBEnvObject(int flags)
self->flags = flags; self->flags = flags;
self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE; self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE; self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
#ifdef HAVE_WEAKREF
self->in_weakreflist = NULL;
#endif
MYDB_BEGIN_ALLOW_THREADS; MYDB_BEGIN_ALLOW_THREADS;
err = db_env_create(&self->db_env, flags); err = db_env_create(&self->db_env, flags);
...@@ -859,6 +890,12 @@ newDBEnvObject(int flags) ...@@ -859,6 +890,12 @@ newDBEnvObject(int flags)
static void static void
DBEnv_dealloc(DBEnvObject* self) DBEnv_dealloc(DBEnvObject* self)
{ {
#ifdef HAVE_WEAKREF
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
}
#endif
if (!self->closed) { if (!self->closed) {
MYDB_BEGIN_ALLOW_THREADS; MYDB_BEGIN_ALLOW_THREADS;
self->db_env->close(self->db_env, 0); self->db_env->close(self->db_env, 0);
...@@ -885,6 +922,9 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags) ...@@ -885,6 +922,9 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags)
#endif #endif
if (self == NULL) if (self == NULL)
return NULL; return NULL;
#ifdef HAVE_WEAKREF
self->in_weakreflist = NULL;
#endif
MYDB_BEGIN_ALLOW_THREADS; MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 40) #if (DBVER >= 40)
...@@ -892,6 +932,9 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags) ...@@ -892,6 +932,9 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags)
#else #else
err = txn_begin(myenv->db_env, parent, &(self->txn), flags); err = txn_begin(myenv->db_env, parent, &(self->txn), flags);
#endif #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; MYDB_END_ALLOW_THREADS;
if (makeDBError(err)) { if (makeDBError(err)) {
self = NULL; self = NULL;
...@@ -903,9 +946,26 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags) ...@@ -903,9 +946,26 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags)
static void static void
DBTxn_dealloc(DBTxnObject* self) 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 #if PYTHON_API_VERSION <= 1007
PyMem_DEL(self); PyMem_DEL(self);
...@@ -929,6 +989,9 @@ newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj, ...@@ -929,6 +989,9 @@ newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj,
#endif #endif
if (self == NULL) if (self == NULL)
return NULL; return NULL;
#ifdef HAVE_WEAKREF
self->in_weakreflist = NULL;
#endif
MYDB_BEGIN_ALLOW_THREADS; MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 40) #if (DBVER >= 40)
...@@ -949,7 +1012,12 @@ newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj, ...@@ -949,7 +1012,12 @@ newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj,
static void static void
DBLock_dealloc(DBLockObject* self) 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 #if PYTHON_API_VERSION <= 1007
PyMem_DEL(self); PyMem_DEL(self);
...@@ -4305,6 +4373,19 @@ statichere PyTypeObject DB_Type = { ...@@ -4305,6 +4373,19 @@ statichere PyTypeObject DB_Type = {
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
&DB_mapping,/*tp_as_mapping*/ &DB_mapping,/*tp_as_mapping*/
0, /*tp_hash*/ 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 = { ...@@ -4358,6 +4439,19 @@ statichere PyTypeObject DBEnv_Type = {
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
0, /*tp_hash*/ 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 = { statichere PyTypeObject DBTxn_Type = {
...@@ -4377,6 +4471,19 @@ statichere PyTypeObject DBTxn_Type = { ...@@ -4377,6 +4471,19 @@ statichere PyTypeObject DBTxn_Type = {
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
0, /*tp_hash*/ 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 = { ...@@ -4397,6 +4504,19 @@ statichere PyTypeObject DBLock_Type = {
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
0, /*tp_hash*/ 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