This is an automated email from the ASF dual-hosted git repository.
Apache9 pushed a commit to branch branch-2.6
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-2.6 by this push:
new ae7c3b377b4 HBASE-30240 TestPrefetchPersistence fails because of a
file is not fully cached (#8386) (#8397)
ae7c3b377b4 is described below
commit ae7c3b377b490b6f96f4082234cf4228df99ee95
Author: Duo Zhang <[email protected]>
AuthorDate: Tue Jun 23 20:41:30 2026 +0800
HBASE-30240 TestPrefetchPersistence fails because of a file is not fully
cached (#8386) (#8397)
(cherry picked from commit e2218e0b589bbd9f0a82a8ceeae59fc16f746a6f)
Signed-off-by: Wellington Ramos Chevreuil <[email protected]>
---
.../hadoop/hbase/io/hfile/bucket/BucketCache.java | 92 ++++++++++++----------
.../io/hfile/bucket/TestPrefetchPersistence.java | 37 +++++----
2 files changed, 70 insertions(+), 59 deletions(-)
diff --git
a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/bucket/BucketCache.java
b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/bucket/BucketCache.java
index 36266ce111e..6eca38c6dd6 100644
---
a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/bucket/BucketCache.java
+++
b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/bucket/BucketCache.java
@@ -2382,6 +2382,34 @@ public class BucketCache implements BlockCache, HeapSize
{
return Optional.empty();
}
+ private int countBlocksForFile(Path fileName, List<ReentrantReadWriteLock>
locks) {
+ LOG.debug("iterating over {} entries in the backing map",
backingMap.size());
+ Set<BlockCacheKey> result = getAllCacheKeysForFile(fileName.getName(), 0,
Long.MAX_VALUE);
+ if (result.isEmpty() && StoreFileInfo.isReference(fileName)) {
+ result = getAllCacheKeysForFile(
+
StoreFileInfo.getReferredToRegionAndFile(fileName.getName()).getSecond(), 0,
+ Long.MAX_VALUE);
+ }
+ int count = 0;
+ for (BlockCacheKey entry : result) {
+ LOG.debug("found block for file {} in the backing map. Acquiring read
lock for offset {}",
+ fileName.getName(), entry.getOffset());
+ ReentrantReadWriteLock lock = offsetLock.getLock(entry.getOffset());
+ lock.readLock().lock();
+ locks.add(lock);
+ if (backingMap.containsKey(entry) && entry.getBlockType().isData()) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private void releaseAllLocks(List<ReentrantReadWriteLock> locks) {
+ for (ReentrantReadWriteLock lock : locks) {
+ lock.readLock().unlock();
+ }
+ }
+
@Override
public void notifyFileCachingCompleted(Path fileName, int totalBlockCount,
int dataBlockCount,
long size) {
@@ -2392,58 +2420,42 @@ public class BucketCache implements BlockCache,
HeapSize {
LOG.debug("Notifying caching completed for file {}, with total blocks {},
and data blocks {}",
fileName, totalBlockCount, dataBlockCount);
try {
- int count = 0;
- LOG.debug("iterating over {} entries in the backing map",
backingMap.size());
- Set<BlockCacheKey> result = getAllCacheKeysForFile(fileName.getName(),
0, Long.MAX_VALUE);
- if (result.isEmpty() && StoreFileInfo.isReference(fileName)) {
- result = getAllCacheKeysForFile(
-
StoreFileInfo.getReferredToRegionAndFile(fileName.getName()).getSecond(), 0,
- Long.MAX_VALUE);
- }
- for (BlockCacheKey entry : result) {
- LOG.debug("found block for file {} in the backing map. Acquiring read
lock for offset {}",
- fileName.getName(), entry.getOffset());
- ReentrantReadWriteLock lock = offsetLock.getLock(entry.getOffset());
- lock.readLock().lock();
- locks.add(lock);
- if (backingMap.containsKey(entry) && entry.getBlockType().isData()) {
- count++;
+ boolean lastTry = false;
+ for (;;) {
+ int count = countBlocksForFile(fileName, locks);
+ // BucketCache would only have data blocks
+ if (dataBlockCount == count) {
+ LOG.debug("File {} has now been fully cached.", fileName);
+ fileCacheCompleted(fileName, size);
+ break;
}
- }
- // BucketCache would only have data blocks
- if (dataBlockCount == count) {
- LOG.debug("File {} has now been fully cached.", fileName);
- fileCacheCompleted(fileName, size);
- } else {
- LOG.debug(
- "Prefetch executor completed for {}, but only {} data blocks were
cached. "
- + "Total data blocks for file: {}. "
- + "Checking for blocks pending cache in cache writer queue.",
- fileName, count, dataBlockCount);
- if (ramCache.hasBlocksForFile(fileName.getName())) {
- for (ReentrantReadWriteLock lock : locks) {
- lock.readLock().unlock();
- }
- locks.clear();
- LOG.debug("There are still blocks pending caching for file {}. Will
sleep 100ms "
- + "and try the verification again.", fileName.getName());
- Thread.sleep(100);
- notifyFileCachingCompleted(fileName, totalBlockCount,
dataBlockCount, size);
- } else {
+ if (lastTry) {
LOG.info(
"The total block count was {}. We found only {} data blocks cached
from "
+ "a total of {} data blocks for file {}, "
+ "but no blocks pending caching. Maybe cache is full or
evictions "
+ "happened concurrently to cache prefetch.",
totalBlockCount, count, dataBlockCount, fileName);
+ break;
+ }
+ if (ramCache.hasBlocksForFile(fileName.getName())) {
+ releaseAllLocks(locks);
+ locks.clear();
+ LOG.debug("There are still blocks pending caching for file {}. Will
sleep 100ms "
+ + "and try the verification again.", fileName);
+ Thread.sleep(100);
+ } else {
+ // there are no pending blocks, so count for the last time, if we
still can not get enough
+ // data blocks, quit
+ LOG.debug("There are no blocks pending cache for file {}. Will try
the verification "
+ + "for the last time.");
+ lastTry = true;
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
- for (ReentrantReadWriteLock lock : locks) {
- lock.readLock().unlock();
- }
+ releaseAllLocks(locks);
}
}
diff --git
a/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/bucket/TestPrefetchPersistence.java
b/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/bucket/TestPrefetchPersistence.java
index 32095ad578e..c461d30459b 100644
---
a/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/bucket/TestPrefetchPersistence.java
+++
b/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/bucket/TestPrefetchPersistence.java
@@ -17,6 +17,10 @@
*/
package org.apache.hadoop.hbase.io.hfile.bucket;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.both;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.io.FileMatchers.anExistingFile;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -42,21 +46,24 @@ import org.apache.hadoop.hbase.io.hfile.PrefetchExecutor;
import org.apache.hadoop.hbase.io.hfile.RandomKeyValueUtil;
import org.apache.hadoop.hbase.regionserver.StoreFileWriter;
import org.apache.hadoop.hbase.testclassification.IOTests;
-import org.apache.hadoop.hbase.testclassification.LargeTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.params.provider.Arguments;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Tag(IOTests.TAG)
-@Tag(LargeTests.TAG)
+@Tag(SmallTests.TAG)
@HBaseParameterizedTestTemplate(name = "{index}: blockSize={0},
bucketSizes={1}")
public class TestPrefetchPersistence {
- @SuppressWarnings("checkstyle:Indentation")
+ private static final HBaseTestingUtility TEST_UTIL = new
HBaseTestingUtility();
+
+ private static final int NUM_VALID_KEY_TYPES = KeyValue.Type.values().length
- 2;
+ private static final int DATA_BLOCK_SIZE = 2048;
+ private static final int NUM_KV = 1000;
+
public static Stream<Arguments> parameters() {
return Stream.of(Arguments.of(16 * 1024,
new int[] { 2 * 1024 + 1024, 4 * 1024 + 1024, 8 * 1024 + 1024, 16 * 1024
+ 1024,
@@ -64,22 +71,14 @@ public class TestPrefetchPersistence {
128 * 1024 + 1024 }));
}
- final int constructedBlockSize;
- final int[] constructedBlockSizes;
+ private final int constructedBlockSize;
+ private final int[] constructedBlockSizes;
public TestPrefetchPersistence(int constructedBlockSize, int[]
constructedBlockSizes) {
this.constructedBlockSize = constructedBlockSize;
this.constructedBlockSizes = constructedBlockSizes;
}
- private static final Logger LOG =
LoggerFactory.getLogger(TestPrefetchPersistence.class);
-
- private static final HBaseTestingUtility TEST_UTIL = new
HBaseTestingUtility();
-
- private static final int NUM_VALID_KEY_TYPES = KeyValue.Type.values().length
- 2;
- private static final int DATA_BLOCK_SIZE = 2048;
- private static final int NUM_KV = 1000;
-
private Configuration conf;
private CacheConfig cacheConf;
private FileSystem fs;
@@ -123,15 +122,15 @@ public class TestPrefetchPersistence {
assertNotEquals(0, usedSize);
bucketCache.shutdown();
- assertTrue(new File(testDir + "/bucket.persistence").exists());
+ assertThat(new File(testDir + "/bucket.persistence"), anExistingFile());
bucketCache = new BucketCache("file:" + testDir + "/bucket.cache",
capacitySize,
constructedBlockSize, constructedBlockSizes, writeThreads, writerQLen,
testDir + "/bucket.persistence", 60 * 1000, conf);
bucketCache.waitForCacheInitialization(10000);
cacheConf = new CacheConfig(conf, bucketCache);
- assertTrue(usedSize != 0);
- assertTrue(bucketCache.fullyCachedFiles.containsKey(storeFile.getName()));
- assertTrue(bucketCache.fullyCachedFiles.containsKey(storeFile2.getName()));
+ assertNotEquals(usedSize, 0);
+ assertThat(bucketCache.fullyCachedFiles,
+ both(hasKey(storeFile.getName())).and(hasKey(storeFile2.getName())));
}
@AfterEach