Skip to content

Commit 8fc6ca8

Browse files
committed
Core: Freshness-aware table loading in REST catalog
This is the client-side improvement for the freshness-aware table loading in REST catalog. The main design is the following: - REST server can send an ETag with the LoadTableResponse - The client can use this ETag to populate the IF_NONE_MATCH header with the next loadTable request - The server can send a 304-NOT_MODIFIED response without a body if the table has not been changed based on the ETag - The client when receives a 304, then returns the latest table object associated with the ETag from cache
1 parent 831b4ea commit 8fc6ca8

File tree

8 files changed

+960
-61
lines changed

8 files changed

+960
-61
lines changed

core/src/main/java/org/apache/iceberg/rest/HTTPClient.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,16 @@ protected <T extends RESTResponse> T execute(
326326

327327
// Skip parsing the response stream for any successful request not expecting a response body
328328
if (emptyBody(response, responseType)) {
329+
if (response.getCode() == HttpStatus.SC_NOT_MODIFIED
330+
&& !req.headers().contains(HttpHeaders.IF_NONE_MATCH)) {
331+
// 304-NOT_MODIFIED is used for freshness-aware loading and requires an ETag sent to the
332+
// server via IF_NONE_MATCH header in the request. If no ETag was sent, we shouldn't
333+
// receive a 304.
334+
throw new RESTException(
335+
"Invalid (NOT_MODIFIED) response for request: method=%s, path=%s",
336+
req.method(), req.path());
337+
}
338+
329339
return null;
330340
}
331341

core/src/main/java/org/apache/iceberg/rest/RESTCatalog.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.apache.iceberg.exceptions.NamespaceNotEmptyException;
4040
import org.apache.iceberg.exceptions.NoSuchNamespaceException;
4141
import org.apache.iceberg.hadoop.Configurable;
42+
import org.apache.iceberg.relocated.com.google.common.annotations.VisibleForTesting;
4243
import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
4344
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
4445
import org.apache.iceberg.view.View;
@@ -96,6 +97,11 @@ public void initialize(String name, Map<String, String> props) {
9697
sessionCatalog.initialize(name, props);
9798
}
9899

100+
@VisibleForTesting
101+
RESTSessionCatalog sessionCatalog() {
102+
return sessionCatalog;
103+
}
104+
99105
@Override
100106
public String name() {
101107
return sessionCatalog.name();

core/src/main/java/org/apache/iceberg/rest/RESTCatalogProperties.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919
package org.apache.iceberg.rest;
2020

21+
import java.util.concurrent.TimeUnit;
22+
2123
public final class RESTCatalogProperties {
2224

2325
private RESTCatalogProperties() {}
@@ -41,6 +43,14 @@ private RESTCatalogProperties() {}
4143
public static final String REST_SCAN_PLANNING_ENABLED = "rest-scan-planning-enabled";
4244
public static final boolean REST_SCAN_PLANNING_ENABLED_DEFAULT = false;
4345

46+
// Properties that control the behaviour of the table cache used for freshness-aware table
47+
// loading.
48+
public static final String TABLE_CACHE_EXPIRE_AFTER_WRITE_MS = "rest-table-cache-expire-after-ms";
49+
public static final long TABLE_CACHE_EXPIRE_AFTER_WRITE_MS_DEFAULT = TimeUnit.MINUTES.toMillis(5);
50+
51+
public static final String TABLE_CACHE_MAX_ENTRIES = "rest-table-cache-max-entries";
52+
public static final int TABLE_CACHE_MAX_ENTRIES_DEFAULT = 100;
53+
4454
public enum SnapshotMode {
4555
ALL,
4656
REFS

0 commit comments

Comments
 (0)