|
38 | 38 | #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() |
39 | 39 | #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() |
40 | 40 | #include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8NoNUL |
| 41 | +#include "pycore_weakref.h" |
41 | 42 |
|
42 | 43 | #include <stdbool.h> |
43 | 44 |
|
@@ -143,6 +144,7 @@ class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionTyp |
143 | 144 | [clinic start generated code]*/ |
144 | 145 | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=67369db2faf80891]*/ |
145 | 146 |
|
| 147 | +static int _pysqlite_drop_unused_blob_references(pysqlite_Connection* self); |
146 | 148 | static void incref_callback_context(callback_context *ctx); |
147 | 149 | static void decref_callback_context(callback_context *ctx); |
148 | 150 | static void set_callback_context(callback_context **ctx_pp, |
@@ -300,6 +302,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, |
300 | 302 | self->thread_ident = PyThread_get_thread_ident(); |
301 | 303 | self->statement_cache = statement_cache; |
302 | 304 | self->blobs = blobs; |
| 305 | + self->created_blobs = 0; |
303 | 306 | self->row_factory = Py_NewRef(Py_None); |
304 | 307 | self->text_factory = Py_NewRef(&PyUnicode_Type); |
305 | 308 | self->trace_ctx = NULL; |
@@ -624,6 +627,10 @@ blobopen_impl(pysqlite_Connection *self, const char *table, const char *col, |
624 | 627 | goto error; |
625 | 628 | } |
626 | 629 |
|
| 630 | + if (_pysqlite_drop_unused_blob_references(self) < 0) { |
| 631 | + goto error; |
| 632 | + } |
| 633 | + |
627 | 634 | return (PyObject *)obj; |
628 | 635 |
|
629 | 636 | error: |
@@ -1049,6 +1056,38 @@ final_callback(sqlite3_context *context) |
1049 | 1056 | PyGILState_Release(threadstate); |
1050 | 1057 | } |
1051 | 1058 |
|
| 1059 | +static int |
| 1060 | +_pysqlite_drop_unused_blob_references(pysqlite_Connection* self) |
| 1061 | +{ |
| 1062 | + /* we only need to do this once in a while */ |
| 1063 | + if (self->created_blobs++ < 200) { |
| 1064 | + return 0; |
| 1065 | + } |
| 1066 | + |
| 1067 | + self->created_blobs = 0; |
| 1068 | + |
| 1069 | + PyObject* new_list = PyList_New(0); |
| 1070 | + if (!new_list) { |
| 1071 | + return -1; |
| 1072 | + } |
| 1073 | + |
| 1074 | + assert(PyList_CheckExact(self->blobs)); |
| 1075 | + Py_ssize_t imax = PyList_GET_SIZE(self->blobs); |
| 1076 | + for (Py_ssize_t i = 0; i < imax; i++) { |
| 1077 | + PyObject* weakref = PyList_GET_ITEM(self->blobs, i); |
| 1078 | + if (_PyWeakref_IsDead(weakref)) { |
| 1079 | + continue; |
| 1080 | + } |
| 1081 | + if (PyList_Append(new_list, weakref) != 0) { |
| 1082 | + Py_DECREF(new_list); |
| 1083 | + return -1; |
| 1084 | + } |
| 1085 | + } |
| 1086 | + |
| 1087 | + Py_SETREF(self->blobs, new_list); |
| 1088 | + return 0; |
| 1089 | +} |
| 1090 | + |
1052 | 1091 | /* Allocate a UDF/callback context structure. In order to ensure that the state |
1053 | 1092 | * pointer always outlives the callback context, we make sure it owns a |
1054 | 1093 | * reference to the module itself. create_callback_context() is always called |
|
0 commit comments