mirror of
https://github.com/python/cpython.git
synced 2025-11-13 07:26:31 +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
|
#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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
#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)
|
||||||
#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)
|
||||||
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,
|
||||||
#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,
|
||||||
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 = {
|
||||||
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 = {
|
||||||
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 = {
|
||||||
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 = {
|
||||||
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue