Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.10] bpo-42972: Fully implement GC protocol for sqlite3 heap types (GH-26104) #26361

Merged
merged 1 commit into from
May 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 60 additions & 23 deletions Modules/_sqlite/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,29 @@ pysqlite_new_node(PyObject *key, PyObject *data)
return node;
}

static int
node_traverse(pysqlite_Node *self, visitproc visit, void *arg)
{
Py_VISIT(self->key);
Py_VISIT(self->data);
Py_VISIT(Py_TYPE(self));
return 0;
}

static int
node_clear(pysqlite_Node *self)
{
Py_CLEAR(self->key);
Py_CLEAR(self->data);
return 0;
}

static void
pysqlite_node_dealloc(pysqlite_Node *self)
{
PyTypeObject *tp = Py_TYPE(self);

Py_DECREF(self->key);
Py_DECREF(self->data);

PyObject_GC_UnTrack(self);
tp->tp_clear((PyObject *)self);
tp->tp_free(self);
Py_DECREF(tp);
}
Expand Down Expand Up @@ -88,31 +103,51 @@ pysqlite_cache_init(pysqlite_Cache *self, PyObject *args, PyObject *kwargs)
return 0;
}

static void
pysqlite_cache_dealloc(pysqlite_Cache *self)
static int
cache_traverse(pysqlite_Cache *self, visitproc visit, void *arg)
{
PyTypeObject *tp = Py_TYPE(self);
pysqlite_Node* node;
pysqlite_Node* delete_node;

if (!self->factory) {
/* constructor failed, just get out of here */
return;
pysqlite_Node *node = self->first;
while (node) {
Py_VISIT(node);
node = node->next;
}
Py_VISIT(self->mapping);
if (self->decref_factory) {
Py_VISIT(self->factory);
}
Py_VISIT(Py_TYPE(self));
return 0;
}

static int
cache_clear(pysqlite_Cache *self)
{
/* iterate over all nodes and deallocate them */
node = self->first;
pysqlite_Node *node = self->first;
self->first = NULL;
while (node) {
delete_node = node;
pysqlite_Node *delete_node = node;
node = node->next;
Py_DECREF(delete_node);
Py_CLEAR(delete_node);
}

if (self->decref_factory) {
Py_DECREF(self->factory);
Py_CLEAR(self->factory);
}
Py_CLEAR(self->mapping);
return 0;
}

static void
pysqlite_cache_dealloc(pysqlite_Cache *self)
{
if (!self->factory) {
/* constructor failed, just get out of here */
return;
}
Py_DECREF(self->mapping);

PyObject_GC_UnTrack(self);
PyTypeObject *tp = Py_TYPE(self);
tp->tp_clear((PyObject *)self);
tp->tp_free(self);
Py_DECREF(tp);
}
Expand Down Expand Up @@ -260,14 +295,15 @@ pysqlite_cache_display(pysqlite_Cache *self, PyObject *args)

static PyType_Slot node_slots[] = {
{Py_tp_dealloc, pysqlite_node_dealloc},
{Py_tp_new, PyType_GenericNew},
{Py_tp_traverse, node_traverse},
{Py_tp_clear, node_clear},
{0, NULL},
};

static PyType_Spec node_spec = {
.name = MODULE_NAME ".Node",
.basicsize = sizeof(pysqlite_Node),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.slots = node_slots,
};
PyTypeObject *pysqlite_NodeType = NULL;
Expand All @@ -283,15 +319,16 @@ static PyMethodDef cache_methods[] = {
static PyType_Slot cache_slots[] = {
{Py_tp_dealloc, pysqlite_cache_dealloc},
{Py_tp_methods, cache_methods},
{Py_tp_new, PyType_GenericNew},
{Py_tp_init, pysqlite_cache_init},
{Py_tp_traverse, cache_traverse},
{Py_tp_clear, cache_clear},
{0, NULL},
};

static PyType_Spec cache_spec = {
.name = MODULE_NAME ".Cache",
.basicsize = sizeof(pysqlite_Cache),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.slots = cache_slots,
};
PyTypeObject *pysqlite_CacheType = NULL;
Expand Down
58 changes: 41 additions & 17 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,28 +225,51 @@ pysqlite_do_all_statements(pysqlite_Connection *self, int action,
}
}

static int
connection_traverse(pysqlite_Connection *self, visitproc visit, void *arg)
{
Py_VISIT(self->statement_cache);
Py_VISIT(self->isolation_level);
Py_VISIT(self->function_pinboard_trace_callback);
Py_VISIT(self->function_pinboard_progress_handler);
Py_VISIT(self->function_pinboard_authorizer_cb);
Py_VISIT(self->row_factory);
Py_VISIT(self->text_factory);
Py_VISIT(self->collations);
Py_VISIT(self->statements);
Py_VISIT(self->cursors);
Py_VISIT(Py_TYPE(self));
return 0;
}

static int
connection_clear(pysqlite_Connection *self)
{
Py_CLEAR(self->statement_cache);
Py_CLEAR(self->isolation_level);
Py_CLEAR(self->function_pinboard_trace_callback);
Py_CLEAR(self->function_pinboard_progress_handler);
Py_CLEAR(self->function_pinboard_authorizer_cb);
Py_CLEAR(self->row_factory);
Py_CLEAR(self->text_factory);
Py_CLEAR(self->collations);
Py_CLEAR(self->statements);
Py_CLEAR(self->cursors);
return 0;
}

static void
pysqlite_connection_dealloc(pysqlite_Connection *self)
connection_dealloc(pysqlite_Connection *self)
{
PyTypeObject *tp = Py_TYPE(self);

Py_XDECREF(self->statement_cache);
PyObject_GC_UnTrack(self);
tp->tp_clear((PyObject *)self);

/* Clean up if user has not called .close() explicitly. */
if (self->db) {
sqlite3_close_v2(self->db);
}

Py_XDECREF(self->isolation_level);
Py_XDECREF(self->function_pinboard_trace_callback);
Py_XDECREF(self->function_pinboard_progress_handler);
Py_XDECREF(self->function_pinboard_authorizer_cb);
Py_XDECREF(self->row_factory);
Py_XDECREF(self->text_factory);
Py_XDECREF(self->collations);
Py_XDECREF(self->statements);
Py_XDECREF(self->cursors);

tp->tp_free(self);
Py_DECREF(tp);
}
Expand Down Expand Up @@ -1328,7 +1351,7 @@ pysqlite_connection_call(pysqlite_Connection *self, PyObject *args,

_pysqlite_drop_unused_statement_references(self);

statement = PyObject_New(pysqlite_Statement, pysqlite_StatementType);
statement = PyObject_GC_New(pysqlite_Statement, pysqlite_StatementType);
if (!statement) {
return NULL;
}
Expand Down Expand Up @@ -1909,21 +1932,22 @@ static struct PyMemberDef connection_members[] =
};

static PyType_Slot connection_slots[] = {
{Py_tp_dealloc, pysqlite_connection_dealloc},
{Py_tp_dealloc, connection_dealloc},
{Py_tp_doc, (void *)connection_doc},
{Py_tp_methods, connection_methods},
{Py_tp_members, connection_members},
{Py_tp_getset, connection_getset},
{Py_tp_new, PyType_GenericNew},
{Py_tp_init, pysqlite_connection_init},
{Py_tp_call, pysqlite_connection_call},
{Py_tp_traverse, connection_traverse},
{Py_tp_clear, connection_clear},
{0, NULL},
};

static PyType_Spec connection_spec = {
.name = MODULE_NAME ".Connection",
.basicsize = sizeof(pysqlite_Connection),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.slots = connection_slots,
};

Expand Down
46 changes: 33 additions & 13 deletions Modules/_sqlite/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,27 +81,46 @@ pysqlite_cursor_init_impl(pysqlite_Cursor *self,
return 0;
}

static void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
static int
cursor_traverse(pysqlite_Cursor *self, visitproc visit, void *arg)
{
PyTypeObject *tp = Py_TYPE(self);
Py_VISIT(self->connection);
Py_VISIT(self->row_cast_map);
Py_VISIT(self->row_factory);
Py_VISIT(self->next_row);
Py_VISIT(Py_TYPE(self));
return 0;
}

static int
cursor_clear(pysqlite_Cursor *self)
{
/* Reset the statement if the user has not closed the cursor */
if (self->statement) {
pysqlite_statement_reset(self->statement);
Py_DECREF(self->statement);
Py_CLEAR(self->statement);
}

Py_XDECREF(self->connection);
Py_XDECREF(self->row_cast_map);
Py_XDECREF(self->description);
Py_XDECREF(self->lastrowid);
Py_XDECREF(self->row_factory);
Py_XDECREF(self->next_row);
Py_CLEAR(self->connection);
Py_CLEAR(self->row_cast_map);
Py_CLEAR(self->description);
Py_CLEAR(self->lastrowid);
Py_CLEAR(self->row_factory);
Py_CLEAR(self->next_row);

if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject*)self);
}

return 0;
}

static void
cursor_dealloc(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
tp->tp_clear(self);
tp->tp_free(self);
Py_DECREF(tp);
}
Expand Down Expand Up @@ -487,7 +506,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation

if (self->statement->in_use) {
Py_SETREF(self->statement,
PyObject_New(pysqlite_Statement, pysqlite_StatementType));
PyObject_GC_New(pysqlite_Statement, pysqlite_StatementType));
if (!self->statement) {
goto error;
}
Expand Down Expand Up @@ -1006,21 +1025,22 @@ static const char cursor_doc[] =
PyDoc_STR("SQLite database cursor class.");

static PyType_Slot cursor_slots[] = {
{Py_tp_dealloc, pysqlite_cursor_dealloc},
{Py_tp_dealloc, cursor_dealloc},
{Py_tp_doc, (void *)cursor_doc},
{Py_tp_iter, PyObject_SelfIter},
{Py_tp_iternext, pysqlite_cursor_iternext},
{Py_tp_methods, cursor_methods},
{Py_tp_members, cursor_members},
{Py_tp_new, PyType_GenericNew},
{Py_tp_init, pysqlite_cursor_init},
{Py_tp_traverse, cursor_traverse},
{Py_tp_clear, cursor_clear},
{0, NULL},
};

static PyType_Spec cursor_spec = {
.name = MODULE_NAME ".Cursor",
.basicsize = sizeof(pysqlite_Cursor),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.slots = cursor_slots,
};

Expand Down
13 changes: 10 additions & 3 deletions Modules/_sqlite/prepare_protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,33 @@ pysqlite_prepare_protocol_init(pysqlite_PrepareProtocol *self, PyObject *args,
return 0;
}

static int
pysqlite_prepare_protocol_traverse(PyObject *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
return 0;
}

static void
pysqlite_prepare_protocol_dealloc(pysqlite_PrepareProtocol *self)
{
PyTypeObject *tp = Py_TYPE(self);

PyObject_GC_UnTrack(self);
tp->tp_free(self);
Py_DECREF(tp);
}

static PyType_Slot type_slots[] = {
{Py_tp_dealloc, pysqlite_prepare_protocol_dealloc},
{Py_tp_new, PyType_GenericNew},
{Py_tp_init, pysqlite_prepare_protocol_init},
{Py_tp_traverse, pysqlite_prepare_protocol_traverse},
{0, NULL},
};

static PyType_Spec type_spec = {
.name = MODULE_NAME ".PrepareProtocol",
.basicsize = sizeof(pysqlite_PrepareProtocol),
.flags = Py_TPFLAGS_DEFAULT,
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
.slots = type_slots,
};

Expand Down
Loading