Skip to content

Commit b263bc5

Browse files
[BugFix] Bound and expose the Iceberg partition cache memory (backport #76165) (#76181)
Co-authored-by: Youngwb <yangwenbo_mailbox@163.com>
1 parent 9b5c829 commit b263bc5

3 files changed

Lines changed: 62 additions & 4 deletions

File tree

fe/fe-core/src/main/java/com/starrocks/connector/iceberg/CachingIcebergCatalog.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,13 @@ public Table reload(IcebergTableName key, Table oldValue) {
144144
}
145145
}
146146
});
147-
this.partitionCache = newCacheBuilderWithMaximumSize(
148-
icebergProperties.getIcebergMetaCacheTtlSec(), NEVER_CACHE,
149-
enableCache ? DEFAULT_CACHE_NUM : NEVER_CACHE).build(
147+
long partitionCacheSize = Math.round(Runtime.getRuntime().maxMemory() *
148+
icebergProperties.getIcebergPartitionCacheMemoryUsageRatio());
149+
this.partitionCache = newCacheBuilder(icebergProperties.getIcebergMetaCacheTtlSec(), NEVER_CACHE)
150+
.executor(executorService)
151+
.maximumWeight(partitionCacheSize)
152+
.weigher((Weigher<IcebergTableName, Map<String, Partition>>) this::weighPartitionEntry)
153+
.build(
150154
new com.github.benmanes.caffeine.cache.CacheLoader<IcebergTableName, Map<String, Partition>>() {
151155
@Override
152156
public Map<String, Partition> load(IcebergTableName key) throws Exception {
@@ -610,6 +614,17 @@ private int weighTableEntry(IcebergTableName key, Table table) {
610614
return (int) size;
611615
}
612616

617+
// Each entry holds a whole table's partition map, which is unbounded in bytes (a table can have
618+
// millions of partitions). Sample the partition values so weighing stays cheap on large maps.
619+
private int weighPartitionEntry(IcebergTableName key, Map<String, Partition> partitions) {
620+
long size = Estimator.estimate(key) + Estimator.estimate(partitions, 3);
621+
if (size > Integer.MAX_VALUE) {
622+
LOG.warn("Partition cache entry size for key {} is too large: {} bytes", key, size);
623+
return Integer.MAX_VALUE;
624+
}
625+
return (int) size;
626+
}
627+
613628
private long estimateContentFilesSize(Set<? extends ContentFile<?>> files) {
614629
if (files == null || files.isEmpty()) {
615630
return 0L;
@@ -654,7 +669,11 @@ public long estimateSize() {
654669
return Estimator.estimate(tables.asMap(), 10) +
655670
Estimator.estimate(databases.asMap(), 10) +
656671
estimateDataFileCacheSize() +
657-
estimateDeleteFileCacheSize() + Estimator.estimate(metaFileCacheMap, 10);
672+
estimateDeleteFileCacheSize() +
673+
Estimator.estimate(partitionCache.asMap(), 10) +
674+
Estimator.estimate(metaFileCacheMap, 10) +
675+
Estimator.estimate(tableLatestAccessTime, 10) +
676+
Estimator.estimate(tableLatestRefreshTime, 10);
658677
}
659678

660679
private long estimateDataFileCacheSize() {

fe/fe-core/src/main/java/com/starrocks/connector/iceberg/IcebergCatalogProperties.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class IcebergCatalogProperties {
4545
public static final String ICEBERG_DATA_FILE_CACHE_MEMORY_SIZE_RATIO = "iceberg_data_file_cache_memory_usage_ratio";
4646
public static final String ICEBERG_DELETE_FILE_CACHE_MEMORY_SIZE_RATIO = "iceberg_delete_file_cache_memory_usage_ratio";
4747
public static final String ICEBERG_TABLE_CACHE_MEMORY_SIZE_RATIO = "iceberg_table_cache_memory_usage_ratio";
48+
public static final String ICEBERG_PARTITION_CACHE_MEMORY_SIZE_RATIO = "iceberg_partition_cache_memory_usage_ratio";
4849

4950
// internal config
5051
public static final String REFRESH_ICEBERG_MANIFEST_MIN_LENGTH = "refresh_iceberg_manifest_min_length";
@@ -70,6 +71,7 @@ public class IcebergCatalogProperties {
7071
private double icebergDataFileCacheMemoryUsageRatio;
7172
private double icebergDeleteFileCacheMemoryUsageRatio;
7273
private double icebergTableCacheMemoryUsageRatio;
74+
private double icebergPartitionCacheMemoryUsageRatio;
7375
private long icebergTableCacheRefreshIntervalSec;
7476

7577
public IcebergCatalogProperties(Map<String, String> catalogProperties) {
@@ -111,6 +113,8 @@ private void initIcebergMetadataCache() {
111113
properties, ICEBERG_DELETE_FILE_CACHE_MEMORY_SIZE_RATIO, 0.1);
112114
this.icebergTableCacheMemoryUsageRatio = PropertyUtil.propertyAsDouble(
113115
properties, ICEBERG_TABLE_CACHE_MEMORY_SIZE_RATIO, 0.1);
116+
this.icebergPartitionCacheMemoryUsageRatio = PropertyUtil.propertyAsDouble(
117+
properties, ICEBERG_PARTITION_CACHE_MEMORY_SIZE_RATIO, 0.1);
114118
this.icebergManifestCacheWithColumnStatistics = PropertyUtil.propertyAsBoolean(
115119
properties, ICEBERG_MANIFEST_CACHE_WITH_COLUMN_STATISTICS, true);
116120
this.refreshIcebergManifestMinLength = PropertyUtil.propertyAsLong(properties, REFRESH_ICEBERG_MANIFEST_MIN_LENGTH,
@@ -193,6 +197,10 @@ public double getIcebergTableCacheMemoryUsageRatio() {
193197
return icebergTableCacheMemoryUsageRatio;
194198
}
195199

200+
public double getIcebergPartitionCacheMemoryUsageRatio() {
201+
return icebergPartitionCacheMemoryUsageRatio;
202+
}
203+
196204
public long getRefreshIcebergManifestMinLength() {
197205
return refreshIcebergManifestMinLength;
198206
}

fe/fe-core/src/test/java/com/starrocks/connector/iceberg/CachingIcebergCatalogTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,37 @@ public Table getTable(ConnectContext context, String dbName, String tableName) {
214214
}
215215
}
216216

217+
@Test
218+
public void testPartitionCacheCountedInEstimateSize(@Mocked IcebergCatalog icebergCatalog) {
219+
PartitionSpec spec = Mockito.mock(PartitionSpec.class);
220+
Mockito.when(spec.isUnpartitioned()).thenReturn(false);
221+
Table nativeTable = createBaseTableWithManifests(1, 0, spec);
222+
Map<String, Partition> partitionMap = new HashMap<>();
223+
for (int i = 0; i < 1000; i++) {
224+
partitionMap.put("dt=part-" + i, new Partition(1234L, 1L));
225+
}
226+
new Expectations() {
227+
{
228+
icebergCatalog.getTable((ConnectContext) any, "db", "test");
229+
result = nativeTable;
230+
minTimes = 0;
231+
icebergCatalog.getPartitions((IcebergTable) any, anyLong, null);
232+
result = partitionMap;
233+
minTimes = 0;
234+
}
235+
};
236+
CachingIcebergCatalog cachingIcebergCatalog = new CachingIcebergCatalog(CATALOG_NAME, icebergCatalog,
237+
DEFAULT_CATALOG_PROPERTIES, Executors.newSingleThreadExecutor());
238+
IcebergTable table = IcebergTable.builder().setSrTableName("test")
239+
.setCatalogDBName("db").setCatalogTableName("test").setNativeTable(nativeTable).build();
240+
241+
long before = cachingIcebergCatalog.estimateSize();
242+
cachingIcebergCatalog.getPartitions(table, 1L, null);
243+
long after = cachingIcebergCatalog.estimateSize();
244+
Assertions.assertTrue(after > before,
245+
"partitionCache must be counted in estimateSize; before=" + before + " after=" + after);
246+
}
247+
217248
@Test
218249
public void testGetDB(@Mocked IcebergCatalog icebergCatalog, @Mocked Database db) {
219250
new Expectations() {

0 commit comments

Comments
 (0)