This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new de19a3986 fix: avoid lost-wakeup hang in 
get_equality_delete_predicate_for_delete_file_path (#3268)
de19a3986 is described below

commit de19a3986fbdf399f09f71cd8c08e2573630c80f
Author: Dhruv Arya <[email protected]>
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 <[email protected]>
    
    * 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 <[email protected]>
    
    ---------
    
    Signed-off-by: Dhruv Arya <[email protected]>
    Co-authored-by: Dhruv Arya <[email protected]>
---
 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()),

Reply via email to