This is an automated email from the ASF dual-hosted git repository.
JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push:
new 881e924398 [core] Support off-heap lookup cache (#8867)
881e924398 is described below
commit 881e92439843fd5b627de1046dbca92e238831be
Author: Jingsong Lee <[email protected]>
AuthorDate: Tue Jul 28 08:17:37 2026 +0800
[core] Support off-heap lookup cache (#8867)
---
.../org/apache/paimon/io/cache/CacheManager.java | 35 ++++++++++++++++++++--
.../apache/paimon/io/cache/CacheManagerTest.java | 17 +++++++++++
2 files changed, 49 insertions(+), 3 deletions(-)
diff --git
a/paimon-common/src/main/java/org/apache/paimon/io/cache/CacheManager.java
b/paimon-common/src/main/java/org/apache/paimon/io/cache/CacheManager.java
index 073c3db6c3..e8cd314725 100644
--- a/paimon-common/src/main/java/org/apache/paimon/io/cache/CacheManager.java
+++ b/paimon-common/src/main/java/org/apache/paimon/io/cache/CacheManager.java
@@ -31,7 +31,7 @@ import java.io.IOException;
import static org.apache.paimon.utils.Preconditions.checkNotNull;
/** Cache manager to cache bytes to paged {@link MemorySegment}s. */
-public class CacheManager {
+public class CacheManager implements AutoCloseable {
private static final Logger LOG =
LoggerFactory.getLogger(CacheManager.class);
@@ -43,8 +43,13 @@ public class CacheManager {
private final Cache dataCache;
private final Cache indexCache;
+ private final boolean offHeap;
public CacheManager(MemorySize maxMemorySize, double
highPriorityPoolRatio) {
+ this(maxMemorySize, highPriorityPoolRatio, false);
+ }
+
+ private CacheManager(MemorySize maxMemorySize, double
highPriorityPoolRatio, boolean offHeap) {
Preconditions.checkArgument(
highPriorityPoolRatio >= 0 && highPriorityPoolRatio < 1,
"The high priority pool ratio should in the range [0, 1).");
@@ -58,12 +63,19 @@ public class CacheManager {
} else {
this.indexCache =
CacheBuilder.newBuilder().maximumWeight(indexCacheSize).build();
}
+ this.offHeap = offHeap;
LOG.info(
- "Initialize cache manager with data cache of {} and index
cache of {}.",
+ "Initialize {} cache manager with data cache of {} and index
cache of {}.",
+ offHeap ? "off-heap" : "heap",
dataCacheSize,
indexCacheSize);
}
+ public static CacheManager createOffHeap(
+ MemorySize maxMemorySize, double highPriorityPoolRatio) {
+ return new CacheManager(maxMemorySize, highPriorityPoolRatio, true);
+ }
+
@VisibleForTesting
public Cache dataCache() {
return dataCache;
@@ -82,7 +94,7 @@ public class CacheManager {
k -> {
try {
return new Cache.CacheValue(
- MemorySegment.wrap(reader.read(key)),
callback);
+ toMemorySegment(reader.read(key)),
callback);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -98,6 +110,23 @@ public class CacheManager {
}
}
+ private MemorySegment toMemorySegment(byte[] bytes) {
+ if (!offHeap) {
+ return MemorySegment.wrap(bytes);
+ }
+ MemorySegment segment =
MemorySegment.allocateOffHeapMemory(bytes.length);
+ segment.put(0, bytes);
+ return segment;
+ }
+
+ @Override
+ public void close() {
+ dataCache.invalidateAll();
+ if (indexCache != dataCache) {
+ indexCache.invalidateAll();
+ }
+ }
+
/** The container for the segment. */
public static class SegmentContainer {
diff --git
a/paimon-common/src/test/java/org/apache/paimon/io/cache/CacheManagerTest.java
b/paimon-common/src/test/java/org/apache/paimon/io/cache/CacheManagerTest.java
index 6045956a6d..e8ca35271e 100644
---
a/paimon-common/src/test/java/org/apache/paimon/io/cache/CacheManagerTest.java
+++
b/paimon-common/src/test/java/org/apache/paimon/io/cache/CacheManagerTest.java
@@ -66,4 +66,21 @@ public class CacheManagerTest {
}
}
}
+
+ @Test
+ void testOffHeapCache() throws Exception {
+ File file = new File(tempDir.toFile(), "test.off-heap");
+ assertThat(file.createNewFile()).isTrue();
+ CacheKey key = CacheKey.forPageIndex(new RandomAccessFile(file, "r"),
0, 0);
+
+ try (CacheManager cacheManager =
CacheManager.createOffHeap(MemorySize.ofBytes(10), 0)) {
+ MemorySegment segment =
+ cacheManager.getPage(key, ignored -> new byte[] {1, 2, 3},
ignored -> {});
+
+ assertThat(segment.isOffHeap()).isTrue();
+ byte[] bytes = new byte[3];
+ segment.get(0, bytes);
+ assertThat(bytes).containsExactly(1, 2, 3);
+ }
+ }
}