This is an automated email from the ASF dual-hosted git repository.

voonhous pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hudi.git


The following commit(s) were added to refs/heads/master by this push:
     new 0a7db9598de6 test(storage-format): cover point lookups and 
incompressible values in the multi-block HFile scan test (#20547)
0a7db9598de6 is described below

commit 0a7db9598de6c7c21c1aa6ed387c3084070f20fe
Author: Y Ethan Guo <[email protected]>
AuthorDate: Fri Nov 6 20:25:31 2026 -0800

    test(storage-format): cover point lookups and incompressible values in the 
multi-block HFile scan test (#20547)
    
    With GZIP and compressible values the checksum stays shorter than the last
    entry of a block, so the existing GZIP cases pass even when the content-end
    bound drops trailing key-values. Add a GZIP case with incompressible values,
    and look up every key with seekTo(key) on a fresh reader, so a regression in
    either the scan or the point-lookup path fails regardless of codec.
    
    Co-authored-by: Lin Liu <[email protected]>
---
 .../hudi/io/hfile/TestHFileMultiBlockScan.java     | 40 +++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git 
a/hudi-io/src/test/java/org/apache/hudi/io/hfile/TestHFileMultiBlockScan.java 
b/hudi-io/src/test/java/org/apache/hudi/io/hfile/TestHFileMultiBlockScan.java
index e36410f856b5..fc1134293865 100644
--- 
a/hudi-io/src/test/java/org/apache/hudi/io/hfile/TestHFileMultiBlockScan.java
+++ 
b/hudi-io/src/test/java/org/apache/hudi/io/hfile/TestHFileMultiBlockScan.java
@@ -27,9 +27,12 @@ import org.junit.jupiter.params.provider.CsvSource;
 
 import java.io.ByteArrayOutputStream;
 import java.util.Locale;
+import java.util.Random;
+import java.util.function.IntFunction;
 
 import static org.apache.hudi.common.util.StringUtils.getUTF8Bytes;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Reproduces a full-scan record drop on native-writer HFiles that span many 
data blocks. A large
@@ -47,6 +50,29 @@ public class TestHFileMultiBlockScan {
       "NONE, 65536, 200000", "GZIP, 65536, 200000"
   })
   public void fullScanReturnsAllRecords(String codec, int blockSize, int 
numRecords) throws Exception {
+    assertFullScanReturnsAllRecords(codec, blockSize, numRecords, i -> 
getUTF8Bytes(value(i)));
+  }
+
+  /**
+   * GZIP masks the drop for compressible values: the checksum covers the 
small on-disk block, so it
+   * stays shorter than the last record. With incompressible values the 
on-disk block stays near the
+   * block size, the checksum grows past a short record, and every full block 
loses its trailing entries.
+   */
+  @ParameterizedTest
+  @CsvSource({"GZIP, 1048576, 50000, 100"})
+  public void fullScanReturnsAllRecordsWithIncompressibleValues(
+      String codec, int blockSize, int numRecords, int valueLength) throws 
Exception {
+    Random random = new Random(42);
+    byte[][] values = new byte[numRecords][];
+    for (int i = 0; i < numRecords; i++) {
+      values[i] = new byte[valueLength];
+      random.nextBytes(values[i]);
+    }
+    assertFullScanReturnsAllRecords(codec, blockSize, numRecords, i -> 
values[i]);
+  }
+
+  private static void assertFullScanReturnsAllRecords(
+      String codec, int blockSize, int numRecords, IntFunction<byte[]> 
valueOf) throws Exception {
     HFileContext context = new HFileContext.Builder()
         .blockSize(blockSize)
         .compressionCodec(CompressionCodec.valueOf(codec))
@@ -54,7 +80,7 @@ public class TestHFileMultiBlockScan {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     try (HFileWriter writer = new HFileWriterImpl(context, baos)) {
       for (int i = 0; i < numRecords; i++) {
-        writer.append(key(i), getUTF8Bytes(value(i)));
+        writer.append(key(i), valueOf.apply(i));
       }
     }
     byte[] fileBytes = baos.toByteArray();
@@ -82,6 +108,18 @@ public class TestHFileMultiBlockScan {
           "forward scan returned fewer records than written; " + scenario
               + " firstSkipAtPosition=" + firstSkipAt);
     }
+
+    // Seeks only move forward, so point lookups use a fresh reader.
+    try (HFileReader reader = new HFileReaderImpl(
+        new ByteArraySeekableDataInputStream(new 
ByteBufferBackedInputStream(fileBytes)),
+        fileBytes.length)) {
+      reader.initializeMetadata();
+      assertTrue(reader.seekTo());
+      for (int i = 0; i < numRecords; i++) {
+        assertEquals(HFileReader.SEEK_TO_FOUND, reader.seekTo(new 
UTF8StringKey(key(i))),
+            "point lookup missed key " + key(i) + "; codec=" + codec + " 
blockSize=" + blockSize);
+      }
+    }
   }
 
   private static String key(int i) {

Reply via email to