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

add progress handler support to sqlite #2256

Merged
merged 6 commits into from
Mar 24, 2023

Conversation

nbaztec
Copy link
Contributor

@nbaztec nbaztec commented Dec 27, 2022

What
Adds progress handler support to sqlite. The feature is already supported by the sqlite driver. This PR exposes it.

@abonander abonander force-pushed the main branch 2 times, most recently from 6cf15b0 to eade49c Compare February 21, 2023 22:56
@abonander
Copy link
Collaborator

@nbaztec major refactors have landed on main since this PR was authored, do you mind rebasing? The code for the SQLite driver was moved to: https://github.com/launchbadge/sqlx/tree/main/sqlx-sqlite

@nbaztec
Copy link
Contributor Author

nbaztec commented Feb 23, 2023

@abonander Done

@abonander
Copy link
Collaborator

@nbaztec Github is still saying that there's merge conflicts but won't say what they are. Can you try actually rebasing and not just merging main into your branch?

@nbaztec nbaztec force-pushed the sqlite-progress-handler branch from eee2ab0 to 608d00c Compare March 3, 2023 12:19
@nbaztec
Copy link
Contributor Author

nbaztec commented Mar 3, 2023

@abonander Done

@abonander
Copy link
Collaborator

@nbaztec cargo fmt needs to be run.

@nbaztec
Copy link
Contributor Author

nbaztec commented Mar 4, 2023

Done

Copy link
Collaborator

@abonander abonander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry it's taken me this long to get to, but unfortunately this PR has several instances of possible undefined behavior that need to be addressed.

Additionally, I think it's worth discussing the actual use-cases for setting a progress handler and if we can design an API that's better tailored to them.

sqlx-sqlite/src/connection/mod.rs Outdated Show resolved Hide resolved
sqlx-sqlite/src/connection/mod.rs Outdated Show resolved Hide resolved
sqlx-sqlite/src/connection/mod.rs Outdated Show resolved Hide resolved
tests/sqlite/sqlite.rs Outdated Show resolved Hide resolved
@nbaztec
Copy link
Contributor Author

nbaztec commented Mar 8, 2023

The main motivation of the feature would be to enable long-running queries to be interrupted within a reasonable time-frame. As of now, there's no way to abort a SQLite query that is running for a long while.

Thanks for the good review comments.

I'd suggest we store the handler within the LockedSqliteHandle as Option<Box<dyn FnMut() -> bool + Send>>, with an impl Drop that removes the progress handler, since we'd move the progress_handler functionality to LockedSqliteHandle anyhow.

And definitely a good point about catching the panic. Makes sense to use catch_unwind and perhaps treat the panic as an interrupt (optionally print it out).

extern "C" fn progress_callback<F>(callback: *mut c_void) -> c_int
where
    F: FnMut() -> bool,
{
    unsafe {
       let r = catch_unwind(|| {
                let boxed_callback: *mut F = callback.cast::<F>();
                (*boxed_callback)()
       });
       c_int::from(r.unwrap_or_default())
    }
}
            

I saw this pattern being used in a bunch of other sqlite rust implementations like sqlite and rusqlite so reckoned it to be a "safe enough".

@abonander
Copy link
Collaborator

I'd suggest we store the handler within the LockedSqliteHandle as Option<Box<dyn FnMut() -> bool + Send>>, with an impl Drop that removes the progress handler, since we'd move the progress_handler functionality to LockedSqliteHandle anyhow.

That's probably still UB as I addressed in my follow-up comment. Box implies that the pointer is not aliased, which it very much is while being stored inside SQLite. If we never ever touched the Box while it's aliased, then maybe, but that's a potentially big problem if it goes awry.

I would store it as Option<NotNull<dyn FnMut() -> bool + Send>> as you can have raw pointers to trait objects, and then yeah an impl Drop to remove the progress handler and destroy the value on-drop by just doing let _ = unsafe { Box::from_raw(pointer) };.

@abonander
Copy link
Collaborator

It doesn't make sense to store it in the LockedSqliteHandle though as that just wraps a MutexGuard to ConnectionState. Just put it in ConnectionState please.

@nbaztec
Copy link
Contributor Author

nbaztec commented Mar 14, 2023

@abonander I tried to apply the changes but stumbled onto the problem that the dyn FnMut needs to be Sized. I can't figure out a way to do it without introducing a Box or a generic param (which touches quite a bit of code). Any ideas?

@abonander
Copy link
Collaborator

@nbaztec Option<NonNull<dyn FnMut(...) -> ...>> should be fine, did you forget the NonNull part?

@nbaztec
Copy link
Contributor Author

nbaztec commented Mar 15, 2023

Had some other problem - PEBKAC. Managed to remedy it. Please review the new code, happy to make any further improvements.

Copy link
Collaborator

@abonander abonander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please pay close attention to what you're doing inside unsafe {} blocks, and ensure to address all review comments this time.

sqlx-sqlite/src/connection/mod.rs Outdated Show resolved Hide resolved
sqlx-sqlite/src/connection/mod.rs Outdated Show resolved Hide resolved
sqlx-sqlite/src/connection/mod.rs Outdated Show resolved Hide resolved
sqlx-sqlite/src/connection/mod.rs Outdated Show resolved Hide resolved
sqlx-sqlite/src/connection/mod.rs Outdated Show resolved Hide resolved
tests/sqlite/sqlite.rs Outdated Show resolved Hide resolved
sqlx-sqlite/src/connection/mod.rs Outdated Show resolved Hide resolved
sqlx-sqlite/src/connection/mod.rs Outdated Show resolved Hide resolved
tests/sqlite/sqlite.rs Outdated Show resolved Hide resolved
tests/sqlite/sqlite.rs Outdated Show resolved Hide resolved
@nbaztec nbaztec requested a review from abonander March 22, 2023 11:22
@abonander abonander merged commit 4f1ac1d into launchbadge:main Mar 24, 2023
Aandreba pushed a commit to Aandreba/sqlx that referenced this pull request Mar 31, 2023
* rebase main

* fmt

* use NonNull to fix UB

* apply code suggestions

* add test for multiple handler drops

* remove nightly features for test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants