You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by st...@apache.org on 2026/08/18 02:52:50 UTC

(impala) 02/02: IMPALA-15258: Fix race in buffer pool release

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

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git

commit 179ba072334ef336d26c08f74a3d69e95760b8db
Author: Michael Smith <mi...@cloudera.com>
AuthorDate: Tue Aug 11 09:13:42 2026 -0700

    IMPALA-15258: Fix race in buffer pool release
    
    target_dirty_bytes in buffer-pool can become negative, which causes the
    while loop at the end of CleanPages to never terminate. This appears to
    be a race condition in DestroyPageInternal, where we remove the page
    from pinned_pages_ while holding lock_, then release the lock and later
    update buffers_allocated_bytes_.
    
        I20260812 22:48:09.199885 141206 buffer-pool.cc:679]
        254fc219ed384ebf:227b64f700000010] target_dirty_bytes=-1048576
        reservation=17825792 buffers_allocated_bytes_=1048576
        pinned_pages_.bytes()=0 len=17825792
    
    Change-Id: Ia247792cbcca24ad2caa82f9b8edc43ddeeaa4f3
    Reviewed-on: http://gerrit.cloudera.org:8080/24689
    Reviewed-by: Michael Smith <mi...@cloudera.com>
    Tested-by: Impala Public Jenkins <im...@cloudera.com>
---
 be/src/runtime/bufferpool/buffer-pool.cc | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/be/src/runtime/bufferpool/buffer-pool.cc b/be/src/runtime/bufferpool/buffer-pool.cc
index a3b3c02a0..8b3dd69a0 100644
--- a/be/src/runtime/bufferpool/buffer-pool.cc
+++ b/be/src/runtime/bufferpool/buffer-pool.cc
@@ -481,6 +481,10 @@ void BufferPool::Client::DestroyPageInternal(
     }
     DCHECK(!page->in_queue());
     --num_pages_;
+    // The buffer is being extracted from the page, so it will be accounted for in
+    // buffers_allocated_bytes_ instead of pinned_pages_.bytes(). Count is updated early
+    // because it needs to be updated while holding lock_
+    if (out_buffer != nullptr) buffers_allocated_bytes_ += page->buffer.len();
   }
 
   if (page->write_handle != NULL) {
@@ -490,7 +494,7 @@ void BufferPool::Client::DestroyPageInternal(
   if (out_buffer != NULL) {
     DCHECK(page->buffer.is_open());
     *out_buffer = std::move(page->buffer);
-    buffers_allocated_bytes_ += out_buffer->len();
+    // buffers_allocated_bytes_ was updated above within the lock_.
   } else if (page->buffer.is_open()) {
     pool_->allocator_->Free(move(page->buffer));
   }
@@ -683,6 +687,10 @@ Status BufferPool::Client::CleanPages(
               << " len=" << len << "\n"
               << DebugStringLocked();
   }
+  DCHECK_GE(target_dirty_bytes, 0) << "target_dirty_bytes=" << target_dirty_bytes
+      << " reservation=" << reservation_.GetReservation()
+      << " buffers_allocated_bytes_=" << buffers_allocated_bytes_
+      << " pinned_pages_.bytes()=" << pinned_pages_.bytes() << " len=" << len;
   // Start enough writes to ensure that the loop condition below will eventually become
   // false (or a write error will be encountered).
   int64_t min_bytes_to_write =