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

lhotari pushed a commit to branch branch-4.16
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git


The following commit(s) were added to refs/heads/branch-4.16 by this push:
     new 3795f559e0 Fix the coredump that occurs when calling 
KeyValueStorageRocksDB.count after rocksdb has been closed (#4581)
3795f559e0 is described below

commit 3795f559e006726cc0d500e5f98386693b47bdb5
Author: zzb <48124861+zhaizh...@users.noreply.github.com>
AuthorDate: Thu Apr 17 16:33:04 2025 +0800

    Fix the coredump that occurs when calling KeyValueStorageRocksDB.count 
after rocksdb has been closed (#4581)
    
    * Fix the coredump that occurs when calling KeyValueStorageRocksDB.count() 
(possibly triggered by Prometheus) after RocksDB has been closed(#4243)
    
    * fix race when count op in process and db gets closed.
    
    ---------
    
    Co-authored-by: zhaizhibo <zhaizh...@kuaishou.com>
    (cherry picked from commit 2831ed3405069f2212e2c6204f645e503319ba69)
---
 .../bookie/storage/ldb/KeyValueStorageRocksDB.java | 25 ++++++++++++++++++++--
 .../storage/ldb/KeyValueStorageRocksDBTest.java    | 17 +++++++++++++++
 2 files changed, 40 insertions(+), 2 deletions(-)

diff --git 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDB.java
 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDB.java
index c9e72847fb..b870fb5939 100644
--- 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDB.java
+++ 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDB.java
@@ -38,6 +38,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 import 
org.apache.bookkeeper.bookie.storage.ldb.KeyValueStorageFactory.DbConfigType;
 import org.apache.bookkeeper.conf.ServerConfiguration;
 import org.apache.commons.lang3.StringUtils;
@@ -74,6 +75,8 @@ public class KeyValueStorageRocksDB implements 
KeyValueStorage {
     static KeyValueStorageFactory factory = (defaultBasePath, subPath, 
dbConfigType, conf) ->
             new KeyValueStorageRocksDB(defaultBasePath, subPath, dbConfigType, 
conf);
 
+    private volatile boolean closed = true;
+    private final ReentrantReadWriteLock closedLock = new 
ReentrantReadWriteLock();
     private final RocksDB db;
     private RocksObject options;
     private List<ColumnFamilyDescriptor> columnFamilyDescriptors;
@@ -147,6 +150,7 @@ public class KeyValueStorageRocksDB implements 
KeyValueStorage {
         optionDontCache.setFillCache(false);
 
         this.writeBatchMaxSize = 
conf.getMaxOperationNumbersInSingleRocksDBBatch();
+        this.closed = false;
     }
 
     private RocksDB initializeRocksDBWithConfFile(String basePath, String 
subPath, DbConfigType dbConfigType,
@@ -287,7 +291,13 @@ public class KeyValueStorageRocksDB implements 
KeyValueStorage {
 
     @Override
     public void close() throws IOException {
-        db.close();
+        try {
+            closedLock.writeLock().lock();
+            closed = true;
+            db.close();
+        } finally {
+            closedLock.writeLock().unlock();
+        }
         if (cache != null) {
             cache.close();
         }
@@ -513,7 +523,18 @@ public class KeyValueStorageRocksDB implements 
KeyValueStorage {
     @Override
     public long count() throws IOException {
         try {
-            return db.getLongProperty("rocksdb.estimate-num-keys");
+            if (closed) {
+                throw new IOException("RocksDB is closed");
+            }
+            try {
+                closedLock.readLock().lock();
+                if (!closed) {
+                    return db.getLongProperty("rocksdb.estimate-num-keys");
+                }
+                throw new IOException("RocksDB is closed");
+            } finally {
+                closedLock.readLock().unlock();
+            }
         } catch (RocksDBException e) {
             throw new IOException("Error in getting records count", e);
         }
diff --git 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDBTest.java
 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDBTest.java
index 2ef3e010f8..97be7ae7c7 100644
--- 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDBTest.java
+++ 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/storage/ldb/KeyValueStorageRocksDBTest.java
@@ -21,9 +21,11 @@ package org.apache.bookkeeper.bookie.storage.ldb;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
+import java.io.IOException;
 import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Paths;
@@ -131,4 +133,19 @@ public class KeyValueStorageRocksDBTest {
         ColumnFamilyOptions familyOptions = 
columnFamilyDescriptorList.get(0).getOptions();
         assertEquals(true, familyOptions.levelCompactionDynamicLevelBytes());
     }
+
+    @Test
+    public void testCallCountAfterClose() throws IOException {
+        ServerConfiguration configuration = new ServerConfiguration();
+        URL url = 
getClass().getClassLoader().getResource("test_entry_location_rocksdb.conf");
+        configuration.setEntryLocationRocksdbConf(url.getPath());
+        File tmpDir = 
Files.createTempDirectory("bk-kv-rocksdbtest-file").toFile();
+        Files.createDirectory(Paths.get(tmpDir.toString(), "subDir"));
+        KeyValueStorageRocksDB rocksDB = new 
KeyValueStorageRocksDB(tmpDir.toString(), "subDir",
+                KeyValueStorageFactory.DbConfigType.EntryLocation, 
configuration);
+        assertNotNull(rocksDB.getColumnFamilyDescriptors());
+        rocksDB.close();
+        IOException exception = assertThrows(IOException.class, 
rocksDB::count);
+        assertEquals("RocksDB is closed", exception.getMessage());
+    }
 }

Reply via email to