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

aleksey pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new fb9e74a  Fix buffer pool NPE with concurrent release due to 
in-progress tiny pool eviction
fb9e74a is described below

commit fb9e74a4fe26eda988c0e98d578f7ded80a8c390
Author: Zhao Yang <[email protected]>
AuthorDate: Tue Apr 14 17:50:21 2020 +0800

    Fix buffer pool NPE with concurrent release due to in-progress tiny pool 
eviction
    
    patch by Zhao Yang; reviewed by Aleksey Yeschenko for CASSANDRA-15726
---
 CHANGES.txt                                        |   1 +
 .../apache/cassandra/utils/memory/BufferPool.java  | 128 ++++++++++++---------
 2 files changed, 73 insertions(+), 56 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index f2d1a1f..d25ba64 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 4.0-alpha5
+ * Fix buffer pool NPE with concurrent release due to in-progress tiny pool 
eviction (CASSANDRA-15726)
  * Avoid race condition when completing stream sessions (CASSANDRA-15666)
  * Flush with fast compressors by default (CASSANDRA-15379)
  * Fix CqlInputFormat regression from the switch to system.size_estimates 
(CASSANDRA-15637)
diff --git a/src/java/org/apache/cassandra/utils/memory/BufferPool.java 
b/src/java/org/apache/cassandra/utils/memory/BufferPool.java
index 3fc7992..c0686c4 100644
--- a/src/java/org/apache/cassandra/utils/memory/BufferPool.java
+++ b/src/java/org/apache/cassandra/utils/memory/BufferPool.java
@@ -438,65 +438,81 @@ public class BufferPool
 
         private <T> void removeIf(BiPredicate<Chunk, T> predicate, T value)
         {
-            switch (count)
+            // do not release matching chunks before we move null chunks to 
the back of the queue;
+            // because, with current buffer release from another thread, 
"chunk#release()" may eventually come back to
+            // "removeIf" causing NPE as null chunks are not at the back of 
the queue.
+            Chunk toRelease0 = null, toRelease1 = null, toRelease2 = null;
+
+            try
             {
-                case 3:
-                    if (predicate.test(chunk2, value))
-                    {
-                        --count;
-                        Chunk chunk = chunk2;
-                        chunk2 = null;
-                        chunk.release();
-                    }
-                case 2:
-                    if (predicate.test(chunk1, value))
-                    {
-                        --count;
-                        Chunk chunk = chunk1;
-                        chunk1 = null;
-                        chunk.release();
-                    }
-                case 1:
-                    if (predicate.test(chunk0, value))
-                    {
-                        --count;
-                        Chunk chunk = chunk0;
-                        chunk0 = null;
-                        chunk.release();
-                    }
-                    break;
-                case 0:
-                    return;
+                switch (count)
+                {
+                    case 3:
+                        if (predicate.test(chunk2, value))
+                        {
+                            --count;
+                            toRelease2 = chunk2;
+                            chunk2 = null;
+                        }
+                    case 2:
+                        if (predicate.test(chunk1, value))
+                        {
+                            --count;
+                            toRelease1 = chunk1;
+                            chunk1 = null;
+                        }
+                    case 1:
+                        if (predicate.test(chunk0, value))
+                        {
+                            --count;
+                            toRelease0 = chunk0;
+                            chunk0 = null;
+                        }
+                        break;
+                    case 0:
+                        return;
+                }
+                switch (count)
+                {
+                    case 2:
+                        // Find the only null item, and shift non-null so that 
null is at chunk2
+                        if (chunk0 == null)
+                        {
+                            chunk0 = chunk1;
+                            chunk1 = chunk2;
+                            chunk2 = null;
+                        }
+                        else if (chunk1 == null)
+                        {
+                            chunk1 = chunk2;
+                            chunk2 = null;
+                        }
+                        break;
+                    case 1:
+                        // Find the only non-null item, and shift it to chunk0
+                        if (chunk1 != null)
+                        {
+                            chunk0 = chunk1;
+                            chunk1 = null;
+                        }
+                        else if (chunk2 != null)
+                        {
+                            chunk0 = chunk2;
+                            chunk2 = null;
+                        }
+                        break;
+                }
             }
-            switch (count)
+            finally
             {
-                case 2:
-                    // Find the only null item, and shift non-null so that 
null is at chunk2
-                    if (chunk0 == null)
-                    {
-                        chunk0 = chunk1;
-                        chunk1 = chunk2;
-                        chunk2 = null;
-                    }
-                    else if (chunk1 == null)
-                    {
-                        chunk1 = chunk2;
-                        chunk2 = null;
-                    }
-                    break;
-                case 1:
-                    // Find the only non-null item, and shift it to chunk0
-                    if (chunk1 != null)
-                    {
-                        chunk0 = chunk1;
-                        chunk1 = null;
-                    }
-                    else if (chunk2 != null)
-                    {
-                        chunk0 = chunk2;
-                        chunk2 = null;
-                    }
-                    break;
+                if (toRelease0 != null)
+                    toRelease0.release();
+
+                if (toRelease1 != null)
+                    toRelease1.release();
+
+                if (toRelease2 != null)
+                    toRelease2.release();
             }
         }
 


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

Reply via email to