adutra commented on code in PR #15428:
URL: https://github.com/apache/iceberg/pull/15428#discussion_r2895212304


##########
aws/src/integration/java/org/apache/iceberg/aws/s3/signer/TestS3RestSigner.java:
##########
@@ -202,24 +209,65 @@ private static Server initHttpServer() throws Exception {
     return server;
   }
 
+  /**
+   * Assert the cache hits and misses match the values.
+   *
+   * @param hits expected hits
+   * @param misses expected misses
+   */
+  private void assertCacheHitsAndMisses(int hits, int misses) {
+    assertThat(S3V4RestSignerClient.cacheHits()).describedAs("Cache 
hits").isEqualTo(hits);
+    assertThat(S3V4RestSignerClient.cacheMisses()).describedAs("Cache 
misses").isEqualTo(misses);
+  }
+
   @Test
   public void validateGetObject() {
     
s3.getObject(GetObjectRequest.builder().bucket(BUCKET).key("random/key").build());
-    // signer caching should kick in when repeating the same request
-    
s3.getObject(GetObjectRequest.builder().bucket(BUCKET).key("random/key").build());
+    assertCacheHitsAndMisses(0, 1);
+
+    // signer caching should kick in when repeating the same request with a 
range
+    
s3.getObject(GetObjectRequest.builder().bucket(BUCKET).key("random/key").range("0-10").build());
+    assertCacheHitsAndMisses(1, 1);
+  }
+
+  @Test
+  public void validateHeadObjectUnsignedHeaders() {
+    final HeadObjectResponse response =
+        
s3.headObject(HeadObjectRequest.builder().bucket(BUCKET).key("random/key").build());
+    assertCacheHitsAndMisses(0, 1);
+
+    // the etag is passed in: the same object is returned and the same cached 
signature is retained.
+    // if the ifMatch header was cached, this would have resulted in a failure 
as there would
+    // be a signature mismatch.
+    s3.headObject(
+        HeadObjectRequest.builder()
+            .bucket(BUCKET)
+            .key("random/key")
+            .ifMatch(response.eTag())
+            .build());
+    assertCacheHitsAndMisses(1, 1);
   }
 
   @Test
   public void validatePutObject() {
+    int hits = S3V4RestSignerClient.cacheHits();

Review Comment:
   ```suggestion
   ```



##########
aws/src/integration/java/org/apache/iceberg/aws/s3/signer/TestS3RestSigner.java:
##########
@@ -202,24 +209,65 @@ private static Server initHttpServer() throws Exception {
     return server;
   }
 
+  /**
+   * Assert the cache hits and misses match the values.
+   *
+   * @param hits expected hits
+   * @param misses expected misses
+   */
+  private void assertCacheHitsAndMisses(int hits, int misses) {
+    assertThat(S3V4RestSignerClient.cacheHits()).describedAs("Cache 
hits").isEqualTo(hits);
+    assertThat(S3V4RestSignerClient.cacheMisses()).describedAs("Cache 
misses").isEqualTo(misses);
+  }
+
   @Test
   public void validateGetObject() {
     
s3.getObject(GetObjectRequest.builder().bucket(BUCKET).key("random/key").build());
-    // signer caching should kick in when repeating the same request
-    
s3.getObject(GetObjectRequest.builder().bucket(BUCKET).key("random/key").build());
+    assertCacheHitsAndMisses(0, 1);
+
+    // signer caching should kick in when repeating the same request with a 
range
+    
s3.getObject(GetObjectRequest.builder().bucket(BUCKET).key("random/key").range("0-10").build());
+    assertCacheHitsAndMisses(1, 1);
+  }
+
+  @Test
+  public void validateHeadObjectUnsignedHeaders() {
+    final HeadObjectResponse response =
+        
s3.headObject(HeadObjectRequest.builder().bucket(BUCKET).key("random/key").build());
+    assertCacheHitsAndMisses(0, 1);
+
+    // the etag is passed in: the same object is returned and the same cached 
signature is retained.
+    // if the ifMatch header was cached, this would have resulted in a failure 
as there would
+    // be a signature mismatch.
+    s3.headObject(
+        HeadObjectRequest.builder()
+            .bucket(BUCKET)
+            .key("random/key")
+            .ifMatch(response.eTag())
+            .build());
+    assertCacheHitsAndMisses(1, 1);
   }
 
   @Test
   public void validatePutObject() {
+    int hits = S3V4RestSignerClient.cacheHits();
     s3.putObject(
         PutObjectRequest.builder().bucket(BUCKET).key("some/key").build(), 
Paths.get("/etc/hosts"));
+    assertCacheHitsAndMisses(0, 1);
+    s3.putObject(
+        PutObjectRequest.builder().bucket(BUCKET).key("some/key").build(),
+        RequestBody.fromString("update"));
+    assertCacheHitsAndMisses(0, 2);
   }
 
   @Test
   public void validateDeleteObjects() {
+    int hits = S3V4RestSignerClient.cacheHits();
+    int misses = S3V4RestSignerClient.cacheMisses();

Review Comment:
   ```suggestion
   ```



##########
aws/src/main/java/org/apache/iceberg/aws/s3/signer/S3V4RestSignerClient.java:
##########
@@ -72,11 +78,57 @@ public abstract class S3V4RestSignerClient
   static final String CACHE_CONTROL_PRIVATE = "private";
   static final String CACHE_CONTROL_NO_CACHE = "no-cache";
 
-  private static final Cache<Key, SignedComponent> SIGNED_COMPONENT_CACHE =
+  @VisibleForTesting
+  static final Cache<S3SignRequest, SignedComponent> SIGNED_COMPONENT_CACHE =
       Caffeine.newBuilder().expireAfterWrite(30, 
TimeUnit.SECONDS).maximumSize(100).build();
 
+  private static final AtomicInteger CACHE_HITS = new AtomicInteger();

Review Comment:
   Can't we use Caffeine's `.recordStats()` instead? And ideally, we would call 
`.recordStats()` only when running tests.



##########
aws/src/integration/java/org/apache/iceberg/aws/s3/signer/TestS3RestSigner.java:
##########
@@ -228,19 +276,36 @@ public void validateDeleteObjects() {
                 ObjectIdentifier.builder().key("some/key2").build())
             .build();
 
-    
s3.deleteObjects(DeleteObjectsRequest.builder().bucket(BUCKET).delete(objectsToDelete).build());
+    final DeleteObjectsRequest request =
+        
DeleteObjectsRequest.builder().bucket(BUCKET).delete(objectsToDelete).build();
+    s3.deleteObjects(request);
+    assertCacheHitsAndMisses(0, 1);
+
+    // issue exactly the same object. DELETE must never be cached as all paths
+    // need review by the remote service.
+    s3.deleteObjects(request);
+    assertCacheHitsAndMisses(0, 2);
   }
 
   @Test
   public void validateListPrefix() {
     
s3.listObjectsV2(ListObjectsV2Request.builder().bucket(BUCKET).prefix("some/prefix/").build());
+    assertCacheHitsAndMisses(0, 1);
+    
s3.listObjectsV2(ListObjectsV2Request.builder().bucket(BUCKET).prefix("some/prefix/").build());
+    // list is a GET.
+    assertCacheHitsAndMisses(1, 1);
+    assertCacheHitsAndMisses(1, 1);

Review Comment:
   ```suggestion
   ```



##########
aws/src/integration/java/org/apache/iceberg/aws/s3/signer/TestS3RestSigner.java:
##########
@@ -202,24 +209,65 @@ private static Server initHttpServer() throws Exception {
     return server;
   }
 
+  /**
+   * Assert the cache hits and misses match the values.
+   *
+   * @param hits expected hits
+   * @param misses expected misses
+   */
+  private void assertCacheHitsAndMisses(int hits, int misses) {
+    assertThat(S3V4RestSignerClient.cacheHits()).describedAs("Cache 
hits").isEqualTo(hits);
+    assertThat(S3V4RestSignerClient.cacheMisses()).describedAs("Cache 
misses").isEqualTo(misses);
+  }
+
   @Test
   public void validateGetObject() {
     
s3.getObject(GetObjectRequest.builder().bucket(BUCKET).key("random/key").build());
-    // signer caching should kick in when repeating the same request
-    
s3.getObject(GetObjectRequest.builder().bucket(BUCKET).key("random/key").build());
+    assertCacheHitsAndMisses(0, 1);
+
+    // signer caching should kick in when repeating the same request with a 
range
+    
s3.getObject(GetObjectRequest.builder().bucket(BUCKET).key("random/key").range("0-10").build());
+    assertCacheHitsAndMisses(1, 1);
+  }
+
+  @Test
+  public void validateHeadObjectUnsignedHeaders() {
+    final HeadObjectResponse response =
+        
s3.headObject(HeadObjectRequest.builder().bucket(BUCKET).key("random/key").build());
+    assertCacheHitsAndMisses(0, 1);
+
+    // the etag is passed in: the same object is returned and the same cached 
signature is retained.
+    // if the ifMatch header was cached, this would have resulted in a failure 
as there would

Review Comment:
   ```suggestion
       // if the ifMatch header was signed, this would have resulted in a 
failure as there would
   ```



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to