laserninja commented on code in PR #10498:
URL: https://github.com/apache/gravitino/pull/10498#discussion_r2978867458
##########
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java:
##########
@@ -508,6 +522,95 @@ public Response planTableScan(
}
}
+ /**
+ * Builds an OK response with the ETag header derived from the table
metadata location.
+ *
+ * @param loadTableResponse the table response to include in the body
+ * @return a Response with ETag header set
+ */
+ private static Response buildResponseWithETag(LoadTableResponse
loadTableResponse) {
+ EntityTag etag =
+ generateETag(loadTableResponse.tableMetadata().metadataFileLocation(),
DEFAULT_SNAPSHOTS);
+ return buildResponseWithETag(loadTableResponse, etag);
+ }
+
+ /**
+ * Builds an OK response with the given ETag header.
+ *
+ * @param loadTableResponse the table response to include in the body
+ * @param etag the pre-computed ETag, may be null
+ * @return a Response with ETag header set if etag is non-null
+ */
+ private static Response buildResponseWithETag(
+ LoadTableResponse loadTableResponse, EntityTag etag) {
+ Response.ResponseBuilder responseBuilder =
+ Response.ok(loadTableResponse, MediaType.APPLICATION_JSON_TYPE);
+ if (etag != null) {
+ responseBuilder.tag(etag);
+ }
+ return responseBuilder.build();
+ }
+
+ /**
+ * Generates an ETag based on the table metadata file location and snapshot
mode. The ETag is a
+ * SHA-256 hash that incorporates both the metadata location and the
snapshots parameter, ensuring
+ * distinct ETags for different representations of the same table version
(e.g., snapshots=all vs
+ * snapshots=refs).
+ *
+ * @param metadataLocation the metadata file location
+ * @param snapshots the snapshots query parameter value (e.g., "all", "refs")
+ * @return the generated ETag, or null if generation fails
+ */
+ @VisibleForTesting
+ static EntityTag generateETag(String metadataLocation, String snapshots) {
+ if (metadataLocation == null) {
+ return null;
+ }
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ digest.update(metadataLocation.getBytes(StandardCharsets.UTF_8));
+ if (snapshots != null) {
+ digest.update(snapshots.getBytes(StandardCharsets.UTF_8));
+ }
+ byte[] hash = digest.digest();
+ StringBuilder hexString = new StringBuilder();
+ for (byte b : hash) {
+ String hex = Integer.toHexString(0xff & b);
+ if (hex.length() == 1) {
+ hexString.append('0');
+ }
+ hexString.append(hex);
+ }
+ return new EntityTag(hexString.toString());
+ } catch (NoSuchAlgorithmException e) {
+ LOG.warn("Failed to generate ETag for metadata location: {}",
metadataLocation, e);
+ return null;
+ }
+ }
+
+ /**
+ * Checks if the client's If-None-Match header value matches the current
ETag.
+ *
+ * @param ifNoneMatch the If-None-Match header value from the client
+ * @param etag the current ETag
+ * @return true if the ETag matches (table unchanged), false otherwise
+ */
+ private static boolean etagMatches(String ifNoneMatch, EntityTag etag) {
+ if (ifNoneMatch == null || ifNoneMatch.isEmpty()) {
+ return false;
+ }
+ // Handle wildcard
+ if ("*".equals(ifNoneMatch.trim())) {
Review Comment:
done
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]