You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by gi...@apache.org on 2026/10/01 08:01:02 UTC
(iceberg-rust) branch gh-readonly-queue/main/pr-3268-36eae2969b0773ee5b6f23d9be230fd0a17ffe92 created (now de19a3986)
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a change to branch gh-readonly-queue/main/pr-3268-36eae2969b0773ee5b6f23d9be230fd0a17ffe92
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git
at de19a3986 fix: avoid lost-wakeup hang in get_equality_delete_predicate_for_delete_file_path (#3268)
This branch includes the following new commits:
new de19a3986 fix: avoid lost-wakeup hang in get_equality_delete_predicate_for_delete_file_path (#3268)
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(iceberg-rust) 01/01: fix: avoid lost-wakeup hang in get_equality_delete_predicate_for_delete_file_path (#3268)
Posted by gi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-3268-36eae2969b0773ee5b6f23d9be230fd0a17ffe92
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git
commit de19a3986fbdf399f09f71cd8c08e2573630c80f
Author: Dhruv Arya <dh...@databricks.com>
AuthorDate: Thu Oct 1 08:00:37 2026 +0000
fix: avoid lost-wakeup hang in get_equality_delete_predicate_for_delete_file_path (#3268)
* fix: avoid lost-wakeup hang in get_equality_delete_predicate_for_delete_file_path
The equality-delete loader signals completion with Notify::notify_waiters(),
which stores no permit and only wakes Notified futures created before the call.
get_equality_delete_predicate_for_delete_file_path observed the Loading state,
released the read lock, and only then created the Notified future; a
notify_waiters() fired in that window is lost and the await hangs forever.
Create the Notified (via notified_owned) while still holding the read lock, so
it is guaranteed to precede any notify_waiters() and be delivered.
Signed-off-by: Dhruv Arya <ar...@gmail.com>
* docs: explain why building Notified under the read lock prevents the lost wakeup
State the mechanism rather than the outcome: notified_owned() snapshots tokio's
notify_waiters_calls counter at construction, and holding the read lock orders
that snapshot before insert_equality_delete can advance it. This keeps a later
refactor from moving notified_owned() out from under the lock unnoticed.
Signed-off-by: Dhruv Arya <ar...@gmail.com>
---------
Signed-off-by: Dhruv Arya <ar...@gmail.com>
Co-authored-by: Dhruv Arya <ar...@gmail.com>
---
crates/iceberg/src/arrow/delete_filter.rs | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/crates/iceberg/src/arrow/delete_filter.rs b/crates/iceberg/src/arrow/delete_filter.rs
index cef81afda..6f13be71d 100644
--- a/crates/iceberg/src/arrow/delete_filter.rs
+++ b/crates/iceberg/src/arrow/delete_filter.rs
@@ -168,17 +168,22 @@ impl DeleteFilter {
&self,
file_path: &str,
) -> Option<Predicate> {
- let notifier = {
+ // Build the `Notified` while holding the read lock. `notified_owned()` records tokio's
+ // `notify_waiters_calls` counter at construction and completes on first poll if that
+ // counter has since advanced. Reading the counter under the lock guarantees it is taken
+ // before `insert_equality_delete` can advance it via `notify_waiters()`, so the
+ // notification is never missed even though we `.await` after releasing the lock.
+ let notified = {
match self.state.read().unwrap().equality_deletes.get(file_path) {
None => return None,
- Some(EqDelState::Loading(notifier)) => notifier.clone(),
+ Some(EqDelState::Loading(notifier)) => notifier.clone().notified_owned(),
Some(EqDelState::Loaded(predicate)) => {
return Some(predicate.clone());
}
}
};
- notifier.notified().await;
+ notified.await;
match self.state.read().unwrap().equality_deletes.get(file_path) {
Some(EqDelState::Loaded(predicate)) => Some(predicate.clone()),