Skip to content

feat(rust): define cancellation in a sensible way - #3905

Merged
lidavidm merged 4 commits into
apache:mainfrom
lidavidm:gh-3454
Aug 6, 2026
Merged

feat(rust): define cancellation in a sensible way#3905
lidavidm merged 4 commits into
apache:mainfrom
lidavidm:gh-3454

Conversation

@lidavidm

Copy link
Copy Markdown
Member

Closes#3454.

@lidavidm
lidavidm marked this pull request as ready for review January 22, 2026 08:31
@github-actionsgithub-actionsBot added this to the ADBC Libraries 23 milestone Jan 22, 2026
@lidavidmlidavidm changed the title feat(rust/core)!: define cancellation in a sensible wayfeat(rust)!: define cancellation in a sensible wayJan 26, 2026
@lidavidm

Copy link
Copy Markdown
MemberAuthor

CC @felipecrv@abonander@eitsupi

@lidavidm

Copy link
Copy Markdown
MemberAuthor

Any concerns here?

@felipecrv

Copy link
Copy Markdown
Contributor

I started looking at the code and got confused. Are you going to cancel any statement currently running in the connection or do I get one handle per Statement?

@lidavidm

Copy link
Copy Markdown
MemberAuthor

One per statement (the handle has a weak reference to the specific statement)

@abonanderabonander left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems all right, the inheritance can be implemented using tokio_util::sync::CancellationToken::child_token().

Just a few questions about the detailed semantics.

Comment threadrust/core/src/sync.rs Outdated
Comment on lines +52 to +53
/// Cancel the in-progress operation on a connection.
fn try_cancel(&self) -> Result<()>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are the try_ prefix and the default to NoOpCancellationHandle meant to imply that this is on a best-effort basis only? Can that be more clearly documented?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's only sort-of implied by

/// methods of ArrowArrayStream). (It is not guaranteed to, for
/// instance, the result set may be buffered in memory already.)

Comment threadrust/core/src/sync.rs Outdated
///
/// This is a separated handle because otherwise it would be impossible to
/// call a `cancel` method on a connection or statement itself.
pub trait CancelHandle: Send {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

/// This must always be thread-safe (other operations are not). It is
/// not necessarily signal-safe.

"thread-safe" implies that this handle should be Sync as well since there isn't really a distinction between "can be moved between threads" and "can be called concurrently from multiple threads" in C.

Comment threadrust/core/src/sync.rs Outdated

impl CancelHandle for NoOpCancellationHandle {
fn try_cancel(&self) -> Result<()> {
Ok(())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should the default be to return ADBC_STATUS_UNKNOWN to indicate that the operation cannot be cancelled per

/// \return ADBC_STATUS_UNKNOWN if the query could not be cancelled.

Comment threadrust/core/src/sync.rs
Comment on lines +99 to +101
fn get_cancel_handle(&self) -> Box<dyn CancelHandle> {
Box::new(NoOpCancellationHandle {})
}

@abonanderabonanderFeb 24, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you going to introduce AdbcDatabaseCancel() to the C API? Otherwise I don't see why this needs to exist.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I am: #3910

@lidavidmlidavidm removed this from the ADBC Libraries 23 milestone Apr 7, 2026
Comment threadrust/driver_manager/src/lib.rs Outdated
));
}
let driver = &inner.database.driver.driver;
let mut connection = inner.connection.lock().unwrap();

@serramatutuserramatutuAug 5, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

.lock().unwrap() adds an expectation that the thread who owns the adbc_ffi::FFI_AdbcConnection cannot have panicked (mutex poison) otherwise trying to cancel any statements on that connection will also panic the canceler thread, right? This would cause the panic to start spreading.

Instead of unwrap(), could we instead make this return an error so canceler threads can deal with it gracefully?

Since the method is called try_cancel() I'd expect it to not panic if canceling failed for any reason, including a panic in a neighbor thread.

Comment threadrust/driver_manager/src/lib.rs Outdated
));
}
let driver = &inner.connection.database.driver.driver;
let mut statement = inner.statement.lock().unwrap();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same as above :)

@lidavidm

Copy link
Copy Markdown
MemberAuthor

Changes:

  • Don't unwrap() inside driver manager
  • Restore cancel (but mark it #[deprecated]) to avoid the backwards compatibility break (but it will eventually be removed)

@lidavidmlidavidm changed the title feat(rust)!: define cancellation in a sensible wayfeat(rust): define cancellation in a sensible wayAug 6, 2026
@lidavidm
lidavidm requested a review from amoebaAugust 6, 2026 03:04
@lidavidm
lidavidm merged commit d162dd8 into apache:mainAug 6, 2026
20 checks passed
@lidavidm
lidavidm deleted the gh-3454 branch August 6, 2026 23:39
Sign up for freeto 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.

rust: cancel is effectively useless since everything is &mut self

4 participants

@lidavidm@felipecrv@abonander@serramatutu