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
Convert sqlite3 to multi-phase initialisation (PEP 489) #86230
Comments
Porting sqlite3 to multi-phase initialisation is non-trivial and must be broken into smaller bpo's, often with multiple PR's per bpo. As far as I can see, this is the task list:
The list may be incomplete. Separate bpo's for 1) and 2) are opened. Pr. 2020-10-17, 1) is almost done, and 2), part 1 of 5 is awaiting review. It may be convenient to open up sub-bpo's for some of the other tasks as well. For instance, using sqlite3_create_collation_v2() iso. sqlite3_create_collation(). (FYI, this imposes no new SQLite version requirements.) I'd wait until AC is implemented with moving forward with the rest of the PR's, in order to avoid merge mess. The exception might be item 4, preparing the trace/progress/auth callbacks, which is easy to isolate from the rest. I've prepared branches for most of these things locally, some split in multiple PR's to ease reviewing. I've tagged Victor Stinner and Dong-hee Na (hope that's ok), since they've been helpful with reviewing and providing helpful hints thus far. Any input from Berker Peksag would be highly appreciated; after all, he is the maintainer of this module :) Ref. bpo-1635741 (the grand multi-phase issue) |
Instead of using a custom context struct for sqlite3_create_funcion_v2(), we may just use sqlite3_context_db_handle() to get |
No, unless we can add Proof-of-concept implementation diffstat: |
FYI, WIP branch for this bpo is here: https://github.com/erlend-aasland/cpython/commits/bpo-42064/all |
Work with item 7 is progressing; see WIP branch for details. Current showstopper is how to fetch module state from Connection.__init__ when it has been overloaded (for example in /Lib/sqlite3/test/factory.py). Guessing that Py_TYPE(self) does not return the sqlite3.Connection type. |
Connection.__init__() fixed by iterating though tp_bases in order to find the correct base class to load the state from. There should be a better way to do this than to dig through type member internals. |
Sorted out item 7 (module state). Item 8 is mostly in place, although I get ref. count errors if I add traverse/clear callbacks, so I've temporarily disabled those. Proof-of-concept of multi-phase init can be found here: https://github.com/erlend-aasland/cpython/commits/bpo-42064/all |
I've narrowed down the traverse problems to Py_VISIT(state->CacheType). Suspecting this has to do with the cyclic references in cache/connection. Preliminary tests with GC tracking |
FYI, rebased https://github.com/erlend-aasland/cpython/tree/bpo-42064/all onto master, added Petr Viktorin's _PyType_GetModuleByDef() for use in item 7 (module state). I still run into problems in item 8, but I haven't devoted much time for this yet: object address : 0x7f861140c6b0 Fatal Python error: _PyObject_AssertFailed: _PyObject_AssertFailed |
I think the module could use a more comprehensive review for GIL handling, rather than doing it piecewise in individual PRs. I recommend that any function passed to SQLite (and only those) should
|
Petr:
I agree. I created bpo-44991 for this. |
Here's a gotcha you might not be aware of: The state doesn't have a refcount, but it is owned by a module object, so callback_context should own a reference to the module object. |
Thanks, good catch! I'll add that after PR 27934 is merged. |
Would it be sufficient to hold a reference to the connection object? The connection holds a reference to the connection type, and the connection type holds a reference to the module, right? |
Yes. |
Good, that simplifies things. I'll wait with this until we've resolved PR 27940 though. |
I did some experiments using the connection object as a "backref" in the callback context, but it seems that the GC does not play well with such ref circles; I ended up with a lot of ref leaks (yes, I modified the traverse and clear slots to visit and clear the backref). Using the module object as a "backref", however, worked swell. It ends up being a much larger PR, though. |
Hooray! |
Thanks, and thank you for helping out, Petr :) Also a big thanks to Dong-hee, Berker, Serhiy, Pablo, and Victor for reviews and guidance with this "project". |
sqlite3
exceptions to global state, part 1 of 2 #26745sqlite3
headers #26840sqlite3
exceptions to global state, part 2 of 2 #26884sqlite3_create_collation_v2
#27156sqlite3
state access, part 1 #27273sqlite3
UDF callbacks #27456sqlite3
callback context #28242sqlite3
global state to module state #29073sqlite3
to multi-phase init (PEP 489) #29234Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: