Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 31c5065

Browse files
committed
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.
1 parent 11b91a0 commit 31c5065

1 file changed

Lines changed: 127 additions & 7 deletions

File tree

Modules/_bsddb.c

Lines changed: 127 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,13 @@ static PyObject* DBPermissionsError; /* EPERM */
194194
#undef HAVE_WEAKREF
195195
#endif
196196

197+
/* if Python >= 2.1 better support warnings */
198+
#if PYTHON_API_VERSION >= 1010
199+
#define HAVE_WARNINGS
200+
#else
201+
#undef HAVE_WARNINGS
202+
#endif
203+
197204
struct behaviourFlags {
198205
/* What is the default behaviour when DB->get or DBCursor->get returns a
199206
DB_NOTFOUND error? Return None or raise an exception? */
@@ -212,6 +219,9 @@ typedef struct {
212219
u_int32_t flags; /* saved flags from open() */
213220
int closed;
214221
struct behaviourFlags moduleFlags;
222+
#ifdef HAVE_WEAKREF
223+
PyObject *in_weakreflist; /* List of weak references */
224+
#endif
215225
} DBEnvObject;
216226

217227

@@ -227,6 +237,9 @@ typedef struct {
227237
PyObject* associateCallback;
228238
int primaryDBType;
229239
#endif
240+
#ifdef HAVE_WEAKREF
241+
PyObject *in_weakreflist; /* List of weak references */
242+
#endif
230243
} DBObject;
231244

232245

@@ -243,12 +256,18 @@ typedef struct {
243256
typedef struct {
244257
PyObject_HEAD
245258
DB_TXN* txn;
259+
#ifdef HAVE_WEAKREF
260+
PyObject *in_weakreflist; /* List of weak references */
261+
#endif
246262
} DBTxnObject;
247263

248264

249265
typedef struct {
250266
PyObject_HEAD
251267
DB_LOCK lock;
268+
#ifdef HAVE_WEAKREF
269+
PyObject *in_weakreflist; /* List of weak references */
270+
#endif
252271
} DBLockObject;
253272

254273

@@ -467,8 +486,7 @@ static int makeDBError(int err)
467486
strcat(errTxt, _db_errmsg);
468487
_db_errmsg[0] = 0;
469488
}
470-
/* if Python 2.1 or better use warning framework */
471-
#if PYTHON_API_VERSION >= 1010
489+
#ifdef HAVE_WARNINGS
472490
exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt);
473491
#else
474492
fprintf(stderr, errTxt);
@@ -697,6 +715,9 @@ newDBObject(DBEnvObject* arg, int flags)
697715
self->associateCallback = NULL;
698716
self->primaryDBType = 0;
699717
#endif
718+
#ifdef HAVE_WEAKREF
719+
self->in_weakreflist = NULL;
720+
#endif
700721

701722
/* keep a reference to our python DBEnv object */
702723
if (arg) {
@@ -718,6 +739,9 @@ newDBObject(DBEnvObject* arg, int flags)
718739
self->db->app_private = (void*)self;
719740
#endif
720741
MYDB_END_ALLOW_THREADS;
742+
/* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs
743+
* list so that a DBEnv can refuse to close without aborting any open
744+
* open DBTxns and closing any open DBs first. */
721745
if (makeDBError(err)) {
722746
if (self->myenvobj) {
723747
Py_DECREF(self->myenvobj);
@@ -741,15 +765,19 @@ DB_dealloc(DBObject* self)
741765
MYDB_BEGIN_ALLOW_THREADS;
742766
self->db->close(self->db, 0);
743767
MYDB_END_ALLOW_THREADS;
744-
/* if Python 2.1 or better use warning framework */
745-
#if PYTHON_API_VERSION >= 1010
768+
#ifdef HAVE_WARNINGS
746769
} else {
747770
PyErr_Warn(PyExc_RuntimeWarning,
748771
"DB could not be closed in destructor: DBEnv already closed");
749772
#endif
750773
}
751774
self->db = NULL;
752775
}
776+
#ifdef HAVE_WEAKREF
777+
if (self->in_weakreflist != NULL) {
778+
PyObject_ClearWeakRefs((PyObject *) self);
779+
}
780+
#endif
753781
if (self->myenvobj) {
754782
Py_DECREF(self->myenvobj);
755783
self->myenvobj = NULL;
@@ -842,6 +870,9 @@ newDBEnvObject(int flags)
842870
self->flags = flags;
843871
self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
844872
self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
873+
#ifdef HAVE_WEAKREF
874+
self->in_weakreflist = NULL;
875+
#endif
845876

846877
MYDB_BEGIN_ALLOW_THREADS;
847878
err = db_env_create(&self->db_env, flags);
@@ -859,6 +890,12 @@ newDBEnvObject(int flags)
859890
static void
860891
DBEnv_dealloc(DBEnvObject* self)
861892
{
893+
#ifdef HAVE_WEAKREF
894+
if (self->in_weakreflist != NULL) {
895+
PyObject_ClearWeakRefs((PyObject *) self);
896+
}
897+
#endif
898+
862899
if (!self->closed) {
863900
MYDB_BEGIN_ALLOW_THREADS;
864901
self->db_env->close(self->db_env, 0);
@@ -885,13 +922,19 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags)
885922
#endif
886923
if (self == NULL)
887924
return NULL;
925+
#ifdef HAVE_WEAKREF
926+
self->in_weakreflist = NULL;
927+
#endif
888928

889929
MYDB_BEGIN_ALLOW_THREADS;
890930
#if (DBVER >= 40)
891931
err = myenv->db_env->txn_begin(myenv->db_env, parent, &(self->txn), flags);
892932
#else
893933
err = txn_begin(myenv->db_env, parent, &(self->txn), flags);
894934
#endif
935+
/* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs
936+
* list so that a DBEnv can refuse to close without aborting any open
937+
* open DBTxns and closing any open DBs first. */
895938
MYDB_END_ALLOW_THREADS;
896939
if (makeDBError(err)) {
897940
self = NULL;
@@ -903,9 +946,26 @@ newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags)
903946
static void
904947
DBTxn_dealloc(DBTxnObject* self)
905948
{
906-
/* XXX nothing to do for transaction objects?!? */
949+
#ifdef HAVE_WEAKREF
950+
if (self->in_weakreflist != NULL) {
951+
PyObject_ClearWeakRefs((PyObject *) self);
952+
}
953+
#endif
907954

908-
/* TODO: if it hasn't been commited, should we abort it? */
955+
#ifdef HAVE_WARNINGS
956+
if (self->txn) {
957+
/* it hasn't been finalized, abort it! */
958+
MYDB_BEGIN_ALLOW_THREADS;
959+
#if (DBVER >= 40)
960+
self->txn->abort(self->txn);
961+
#else
962+
txn_abort(self->txn);
963+
#endif
964+
MYDB_END_ALLOW_THREADS;
965+
PyErr_Warn(PyExc_RuntimeWarning,
966+
"DBTxn aborted in destructor. No prior commit() or abort().");
967+
}
968+
#endif
909969

910970
#if PYTHON_API_VERSION <= 1007
911971
PyMem_DEL(self);
@@ -929,6 +989,9 @@ newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj,
929989
#endif
930990
if (self == NULL)
931991
return NULL;
992+
#ifdef HAVE_WEAKREF
993+
self->in_weakreflist = NULL;
994+
#endif
932995

933996
MYDB_BEGIN_ALLOW_THREADS;
934997
#if (DBVER >= 40)
@@ -949,7 +1012,12 @@ newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj,
9491012
static void
9501013
DBLock_dealloc(DBLockObject* self)
9511014
{
952-
/* TODO: if it hasn't been released, should we do it? */
1015+
#ifdef HAVE_WEAKREF
1016+
if (self->in_weakreflist != NULL) {
1017+
PyObject_ClearWeakRefs((PyObject *) self);
1018+
}
1019+
#endif
1020+
/* TODO: is this lock held? should we release it? */
9531021

9541022
#if PYTHON_API_VERSION <= 1007
9551023
PyMem_DEL(self);
@@ -4305,6 +4373,19 @@ statichere PyTypeObject DB_Type = {
43054373
0, /*tp_as_sequence*/
43064374
&DB_mapping,/*tp_as_mapping*/
43074375
0, /*tp_hash*/
4376+
#ifdef HAVE_WEAKREF
4377+
0, /* tp_call */
4378+
0, /* tp_str */
4379+
0, /* tp_getattro */
4380+
0, /* tp_setattro */
4381+
0, /* tp_as_buffer */
4382+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
4383+
0, /* tp_doc */
4384+
0, /* tp_traverse */
4385+
0, /* tp_clear */
4386+
0, /* tp_richcompare */
4387+
offsetof(DBObject, in_weakreflist), /* tp_weaklistoffset */
4388+
#endif
43084389
};
43094390

43104391

@@ -4358,6 +4439,19 @@ statichere PyTypeObject DBEnv_Type = {
43584439
0, /*tp_as_sequence*/
43594440
0, /*tp_as_mapping*/
43604441
0, /*tp_hash*/
4442+
#ifdef HAVE_WEAKREF
4443+
0, /* tp_call */
4444+
0, /* tp_str */
4445+
0, /* tp_getattro */
4446+
0, /* tp_setattro */
4447+
0, /* tp_as_buffer */
4448+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
4449+
0, /* tp_doc */
4450+
0, /* tp_traverse */
4451+
0, /* tp_clear */
4452+
0, /* tp_richcompare */
4453+
offsetof(DBEnvObject, in_weakreflist), /* tp_weaklistoffset */
4454+
#endif
43614455
};
43624456

43634457
statichere PyTypeObject DBTxn_Type = {
@@ -4377,6 +4471,19 @@ statichere PyTypeObject DBTxn_Type = {
43774471
0, /*tp_as_sequence*/
43784472
0, /*tp_as_mapping*/
43794473
0, /*tp_hash*/
4474+
#ifdef HAVE_WEAKREF
4475+
0, /* tp_call */
4476+
0, /* tp_str */
4477+
0, /* tp_getattro */
4478+
0, /* tp_setattro */
4479+
0, /* tp_as_buffer */
4480+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
4481+
0, /* tp_doc */
4482+
0, /* tp_traverse */
4483+
0, /* tp_clear */
4484+
0, /* tp_richcompare */
4485+
offsetof(DBTxnObject, in_weakreflist), /* tp_weaklistoffset */
4486+
#endif
43804487
};
43814488

43824489

@@ -4397,6 +4504,19 @@ statichere PyTypeObject DBLock_Type = {
43974504
0, /*tp_as_sequence*/
43984505
0, /*tp_as_mapping*/
43994506
0, /*tp_hash*/
4507+
#ifdef HAVE_WEAKREF
4508+
0, /* tp_call */
4509+
0, /* tp_str */
4510+
0, /* tp_getattro */
4511+
0, /* tp_setattro */
4512+
0, /* tp_as_buffer */
4513+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
4514+
0, /* tp_doc */
4515+
0, /* tp_traverse */
4516+
0, /* tp_clear */
4517+
0, /* tp_richcompare */
4518+
offsetof(DBLockObject, in_weakreflist), /* tp_weaklistoffset */
4519+
#endif
44004520
};
44014521

44024522

0 commit comments

Comments
 (0)