diff --git a/core/src/main/java/org/apache/iceberg/CatalogProperties.java b/core/src/main/java/org/apache/iceberg/CatalogProperties.java
index c17ed59b2674..6f6b817a04f9 100644
--- a/core/src/main/java/org/apache/iceberg/CatalogProperties.java
+++ b/core/src/main/java/org/apache/iceberg/CatalogProperties.java
@@ -65,6 +65,60 @@ private CatalogProperties() {}
public static final long CACHE_EXPIRATION_INTERVAL_MS_DEFAULT = TimeUnit.SECONDS.toMillis(30);
public static final long CACHE_EXPIRATION_INTERVAL_MS_OFF = -1;
+ /**
+ * Controls whether to use caching during table metadata reads or not.
+ *
+ *
Enabling table metadata file caching require the following configuration constraints to be true:
+ *
+ *
+ *
{@link #IO_TABLE_METADATA_CACHE_EXPIRATION_INTERVAL_MS} must be a non-negative value.
+ *
{@link #IO_TABLE_METADATA_CACHE_MAX_TOTAL_BYTES} must be a positive value.
+ *
{@link #IO_TABLE_METADATA_CACHE_MAX_CONTENT_LENGTH} must be a positive value.
+ *
+ */
+ public static final String IO_TABLE_METADATA_CACHE_ENABLED = "io.table-metadata.cache-enabled";
+
+ public static final boolean IO_TABLE_METADATA_CACHE_ENABLED_DEFAULT = false;
+
+ /**
+ * Controls the maximum duration for which an entry stays in the table metadata cache.
+ *
+ *
Must be a non-negative value. Following are specific behaviors of this config:
+ *
+ *
+ *
Zero - Cache entries expires only if it gets evicted due to memory pressure from {@link
+ * #IO_TABLE_METADATA_CACHE_MAX_TOTAL_BYTES} setting.
+ *
Positive Values - Cache entries expire if not accessed via the cache after this many
+ * milliseconds
+ *
+ */
+ public static final String IO_TABLE_METADATA_CACHE_EXPIRATION_INTERVAL_MS =
+ "io.table-metadata.cache.expiration-interval-ms";
+
+ public static final long IO_TABLE_METADATA_CACHE_EXPIRATION_INTERVAL_MS_DEFAULT =
+ TimeUnit.MINUTES.toMillis(10);
+
+ /**
+ * Controls the maximum total amount of bytes to cache in the table metadata cache.
+ *
+ *
Must be a positive value.
+ */
+ public static final String IO_TABLE_METADATA_CACHE_MAX_TOTAL_BYTES =
+ "io.table-metadata.cache.max-total-bytes";
+
+ public static final long IO_TABLE_METADATA_CACHE_MAX_TOTAL_BYTES_DEFAULT = 100 * 1024 * 1024;
+
+ /**
+ * Controls the maximum length of file to be considered for caching a table metadata file.
+ *
+ *
An {@link org.apache.iceberg.io.InputFile} will not be cached if the length is longer than
+ * this limit. Must be a positive value.
+ */
+ public static final String IO_TABLE_METADATA_CACHE_MAX_CONTENT_LENGTH =
+ "io.table-metadata.cache.max-content-length";
+
+ public static final long IO_TABLE_METADATA_CACHE_MAX_CONTENT_LENGTH_DEFAULT = 8 * 1024 * 1024;
+
/**
* Controls whether to use caching during manifest reads or not.
*
@@ -109,7 +163,7 @@ private CatalogProperties() {}
public static final long IO_MANIFEST_CACHE_MAX_TOTAL_BYTES_DEFAULT = 100 * 1024 * 1024;
/**
- * Controls the maximum length of file to be considered for caching.
+ * Controls the maximum length of file to be considered for caching a manifest file.
*
*
An {@link org.apache.iceberg.io.InputFile} will not be cached if the length is longer than
* this limit. Must be a positive value.
diff --git a/core/src/main/java/org/apache/iceberg/SystemConfigs.java b/core/src/main/java/org/apache/iceberg/SystemConfigs.java
index ad40c17e3076..d0e5f5985a6b 100644
--- a/core/src/main/java/org/apache/iceberg/SystemConfigs.java
+++ b/core/src/main/java/org/apache/iceberg/SystemConfigs.java
@@ -71,7 +71,20 @@ private SystemConfigs() {}
/**
* Maximum number of distinct {@link org.apache.iceberg.io.FileIO} that is allowed to have
- * associated {@link org.apache.iceberg.io.ContentCache} in memory at a time.
+ * associated {@link org.apache.iceberg.io.ContentCache} in memory at a time in the table metadata
+ * cache.
+ */
+ public static final ConfigEntry IO_TABLE_METADATA_CACHE_MAX_FILEIO =
+ new ConfigEntry<>(
+ "iceberg.io.table-metadata.cache.fileio-max",
+ "ICEBERG_IO_TABLE_METADATA_CACHE_FILEIO_MAX",
+ 8,
+ Integer::parseUnsignedInt);
+
+ /**
+ * Maximum number of distinct {@link org.apache.iceberg.io.FileIO} that is allowed to have
+ * associated {@link org.apache.iceberg.io.ContentCache} in memory at a time in the manifest
+ * cache.
*/
public static final ConfigEntry IO_MANIFEST_CACHE_MAX_FILEIO =
new ConfigEntry<>(
diff --git a/core/src/main/java/org/apache/iceberg/TableMetadataParser.java b/core/src/main/java/org/apache/iceberg/TableMetadataParser.java
index eeeeeab8a699..220d88fe8534 100644
--- a/core/src/main/java/org/apache/iceberg/TableMetadataParser.java
+++ b/core/src/main/java/org/apache/iceberg/TableMetadataParser.java
@@ -20,6 +20,8 @@
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -36,14 +38,19 @@
import org.apache.iceberg.TableMetadata.SnapshotLogEntry;
import org.apache.iceberg.encryption.EncryptedKey;
import org.apache.iceberg.exceptions.RuntimeIOException;
+import org.apache.iceberg.io.ContentCache;
import org.apache.iceberg.io.FileIO;
import org.apache.iceberg.io.InputFile;
import org.apache.iceberg.io.OutputFile;
+import org.apache.iceberg.relocated.com.google.common.annotations.VisibleForTesting;
import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap;
import org.apache.iceberg.relocated.com.google.common.collect.Lists;
import org.apache.iceberg.util.JsonUtil;
+import org.apache.iceberg.util.PropertyUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class TableMetadataParser {
@@ -84,6 +91,8 @@ public static Codec fromFileName(String fileName) {
private TableMetadataParser() {}
+ private static final Logger LOG = LoggerFactory.getLogger(TableMetadataParser.class);
+
// visible for testing
static final String FORMAT_VERSION = "format-version";
static final String TABLE_UUID = "table-uuid";
@@ -115,6 +124,21 @@ private TableMetadataParser() {}
static final String NEXT_ROW_ID = "next-row-id";
static final int MIN_NULL_CURRENT_SNAPSHOT_VERSION = 3;
+ private static Caffeine