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

yihua pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hudi-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new db4aabf8 perf(core): write hfile structured keys straight into the 
block buffer (#912)
db4aabf8 is described below

commit db4aabf8f0ee71207da592ca8fb6dedb90bfb816
Author: Y Ethan Guo <[email protected]>
AuthorDate: Thu Oct 29 22:05:14 2026 -0700

    perf(core): write hfile structured keys straight into the block buffer 
(#912)
    
    `HFileWriter::write` now appends each structured key's parts (the `u16` 
length, the content, the family and timestamp bytes, the type byte) straight 
into the data block buffer instead of building a `Vec` per key and copying it 
in. The bytes written are the same, and the 64 KiB key check still rejects the 
same keys with the same error. On a 10M-key record index build this removes one 
allocation and one copy per entry.
---
 crates/core/src/hfile/writer.rs | 30 ++++++++++++++++++++----------
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/crates/core/src/hfile/writer.rs b/crates/core/src/hfile/writer.rs
index 0136a78d..e83d8477 100644
--- a/crates/core/src/hfile/writer.rs
+++ b/crates/core/src/hfile/writer.rs
@@ -63,14 +63,13 @@ impl HFileWriter {
                 .sum(),
         );
         for (key, value) in &entries {
-            let key = structured_key(key)?;
-            let key_len = i32::try_from(key.len())
+            let key_len = i32::try_from(key.len() + STRUCTURED_KEY_OVERHEAD)
                 .map_err(|_| HFileError::InvalidFormat("HFile key is too 
large".to_string()))?;
             let value_len = i32::try_from(value.len())
                 .map_err(|_| HFileError::InvalidFormat("HFile value is too 
large".to_string()))?;
             data.extend_from_slice(&key_len.to_be_bytes());
             data.extend_from_slice(&value_len.to_be_bytes());
-            data.extend_from_slice(&key);
+            push_structured_key(&mut data, key)?;
             data.extend_from_slice(value);
             data.push(0);
         }
@@ -154,7 +153,19 @@ impl HFileWriter {
     }
 }
 
+/// Bytes a structured key adds around its content: the u16 length, the
+/// family terminator, the i64 timestamp and the type byte.
+const STRUCTURED_KEY_OVERHEAD: usize = 2 + 1 + 8 + 1;
+
 fn structured_key(content: &str) -> crate::hfile::error::Result<Vec<u8>> {
+    let mut key = Vec::with_capacity(content.len() + STRUCTURED_KEY_OVERHEAD);
+    push_structured_key(&mut key, content)?;
+    Ok(key)
+}
+
+/// Appends the structured key for `content` to `out`, so a data block is built
+/// without a buffer per entry.
+fn push_structured_key(out: &mut Vec<u8>, content: &str) -> 
crate::hfile::error::Result<()> {
     // The KeyValue row-length field is u16; truncating would corrupt framing.
     let len = u16::try_from(content.len()).map_err(|_| {
         crate::hfile::error::HFileError::InvalidFormat(format!(
@@ -162,13 +173,12 @@ fn structured_key(content: &str) -> 
crate::hfile::error::Result<Vec<u8>> {
             content.len()
         ))
     })?;
-    let mut key = Vec::with_capacity(content.len() + 12);
-    key.extend_from_slice(&len.to_be_bytes());
-    key.extend_from_slice(content.as_bytes());
-    key.push(0);
-    key.extend_from_slice(&i64::MAX.to_be_bytes());
-    key.push(4);
-    Ok(key)
+    out.extend_from_slice(&len.to_be_bytes());
+    out.extend_from_slice(content.as_bytes());
+    out.push(0);
+    out.extend_from_slice(&i64::MAX.to_be_bytes());
+    out.push(4);
+    Ok(())
 }
 
 fn write_block(block_type: HFileBlockType, data: &[u8], previous_offset: i64) 
-> Result<Vec<u8>> {

Reply via email to