mirror of
https://github.com/python/cpython.git
synced 2025-11-02 11:08:57 +00:00
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:
parent
11b91a0ea3
commit
31c50659ea
1 changed files with 127 additions and 7 deletions
134
Modules/_bsddb.c
134
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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue