dwsmith1983 commented on code in PR #5613:
URL: https://github.com/apache/datafusion-comet/pull/5613#discussion_r3930692784


##########
native/core/src/execution/memory_pools/fair_pool.rs:
##########
@@ -60,26 +100,102 @@ impl CometFairMemoryPool {
         task_memory_manager_handle: Arc<Global<JObject<'static>>>,
         pool_size: usize,
     ) -> CometFairMemoryPool {
+        Self::with_bridge(
+            Box::new(JniTaskMemoryBridge {
+                task_memory_manager_handle,
+            }),
+            pool_size,
+        )
+    }
+
+    fn with_bridge(bridge: Box<dyn TaskMemoryBridge>, pool_size: usize) -> 
CometFairMemoryPool {
         Self {
-            task_memory_manager_handle,
+            bridge,
             pool_size,
-            state: Mutex::new(CometFairPoolState { used: 0, num: 0 }),
+            state: Mutex::new(CometFairPoolState {
+                used: 0,
+                num: 0,
+                jvm_held: 0,
+                pending_acquires: 0,
+                deferred_release: 0,
+                paying_deferred: false,
+            }),
+            deferred_done: Condvar::new(),
         }
     }
 
     fn acquire(&self, additional: usize) -> CometResult<i64> {
-        let handle = self.task_memory_manager_handle.as_obj();
-        JVMClasses::with_env(|env| unsafe {
-            jni_call!(env,
-              comet_task_memory_manager(handle).acquire_memory(additional as 
i64) -> i64)
-        })
+        self.bridge.acquire(additional)
     }
 
     fn release(&self, size: usize) -> CometResult<()> {
-        let handle = self.task_memory_manager_handle.as_obj();
-        JVMClasses::with_env(|env| unsafe {
-            jni_call!(env, 
comet_task_memory_manager(handle).release_memory(size as i64) -> ())
-        })
+        self.bridge.release(size)
+    }
+
+    /// Debits a release from the JVM-side balance and returns how much to 
hand back now. A
+    /// release that would zero the balance while acquires are in flight keeps 
one byte back,
+    /// because Spark drops the task's accounting entry at zero and a parked 
acquire then indexes
+    /// the missing entry. Blocking instead could deadlock: the waiter may 
need this very memory.
+    /// The n-1 bytes freed here still wake Spark's waiter; the single held 
byte only matters
+    /// in a pool small enough that one byte decides the fair-share threshold, 
and even there
+    /// the deferred payoff releases it as soon as in-flight acquires drain.
+    fn plan_release(state: &mut CometFairPoolState, bytes: usize) -> usize {
+        state.jvm_held = state
+            .jvm_held
+            .checked_sub(bytes)
+            .expect("released more bytes than the JVM side holds");
+        if bytes > 0 && state.jvm_held == 0 && state.pending_acquires > 0 {

Review Comment:
   Fixed in db1f1bc6e. The deferral is gone: every release now goes to the JVM 
whole, so a parked acquire sees the full freed amount and Spark's minimum-share 
check passes. The task entry is kept alive by a permanent anchor instead. The 
first acquire asks for one extra byte and the pool holds it until it drops, so 
the balance never reaches zero mid task. That means the task stays in Spark's 
active-task set for the pool's lifetime and retains one byte, which the header 
comment now states.
   
   Your scenario is pinned as 
`min_share_wait_is_granted_after_the_holder_frees_its_memory_in_full`. The stub 
now models `ExecutionMemoryPool.acquireMemory` from 4.1.3 with the per-task 
entry lifecycle, the 1/N and 1/(2N) shares, the wait loop, and `notifyAll` on 
release, with a bounded wait that fails the test instead of hanging. It failed 
on the previous head with the waiter timing out and passes now.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to