@@ -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+
197204struct 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 {
243256typedef 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
249265typedef 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)
859890static void
860891DBEnv_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)
903946static void
904947DBTxn_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,
9491012static void
9501013DBLock_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
43634457statichere 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