Skip to content

Avoid redundant memory access in ArrowBytesViewMap for inline values#20807

Open
CuteChuanChuan wants to merge 2 commits intoapache:mainfrom
CuteChuanChuan:raymond/issue-20054-avoid-extra-memory-access
Open

Avoid redundant memory access in ArrowBytesViewMap for inline values#20807
CuteChuanChuan wants to merge 2 commits intoapache:mainfrom
CuteChuanChuan:raymond/issue-20054-avoid-extra-memory-access

Conversation

@CuteChuanChuan
Copy link
Contributor

@CuteChuanChuan CuteChuanChuan commented Mar 8, 2026

Which issue does this PR close?

Rationale for this change

ArrowBytesViewMap::insert_if_new_inner calls values.value(i) redundantly:

  1. Inside the find closure
  2. Again during insertion when the value is new

For inline strings (<=12 bytes), values.value(i) is unnecessary since the data is embedded directly in the view.
For non-inline strings (>12 bytes), it should only be called once.

What changes are included in this PR?

  • Inline strings (<=12 bytes): Extract bytes directly instead of calling values.value(i). During insertion, push the original view_u128 directly.
  • Non-inline strings (>12 bytes): Fetch values.value(i) once before the find closure and reuse the result for both hash resolution and insertion.

Are these changes tested?

Yes, covered by existing tests by running cargo test -p datafusion-physical-expr-common

Are there any user-facing changes?

No. This is an internal performance optimization with no API changes.

@github-actions github-actions bot added the physical-expr Changes to the physical-expr crates label Mar 8, 2026
@CuteChuanChuan CuteChuanChuan marked this pull request as ready for review March 8, 2026 15:51
@CuteChuanChuan CuteChuanChuan force-pushed the raymond/issue-20054-avoid-extra-memory-access branch from 9330fd7 to dd4cc0b Compare March 8, 2026 16:06
@CuteChuanChuan
Copy link
Contributor Author

Hi @Dandandan ,
could you PTAL when you have chances? Thanks! 🙏

// For non-inline strings (>12 bytes), fetch once from the array.
let view_bytes = view_u128.to_le_bytes();
let input_value: &[u8] = if is_inline {
&view_bytes[4..4 + len as usize]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don'nt need this for the inline path (we use the u128 directly)

} else {
// to avoid redundant memory access during hash resolution and insertion.
// Inline strings (<= 12 bytes) use u128 directly.
let input_value: &[u8] = if !is_inline {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm can we just values.value(i).as_ref() to where it is used instead in the else branch ?

let (payload, new_view) = if is_inline {
// Extract inline bytes from view (only for new values)
let view_bytes = view_u128.to_le_bytes();
let payload = make_payload_fn(Some(&view_bytes[4..4 + len as usize]));
Copy link
Contributor

@Dandandan Dandandan Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like this param to the payload fn is not really used anymore, could we remove it?

The three actual implementations just ignore the param:

        fn make_payload_fn(_value: Option<&[u8]>) {}
            |_value| {
                // assign new group index on each insert
                let group_idx = self.num_groups;
                self.num_groups += 1;
                group_idx
            },
            |_value| {
                // assign new group index on each insert
                let group_idx = self.num_groups;
                self.num_groups += 1;
                group_idx
            },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

physical-expr Changes to the physical-expr crates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Avoid extra memory access in ArrowByteViewMap

2 participants