Skip to content

Further optimize Spark hex byte encoding: reuse input NullBuffer and special-case the no-nulls path #23674

Description

@andygrove

Is your feature request related to a problem or challenge?

Follow-on from review feedback on #23473, which rewrote hex_encode_bytes (datafusion/spark/src/function/math/hex.rs) to write hex digits directly into a single value buffer. Two further optimizations were suggested during review but left out of that PR to keep it focused:

  1. Reuse the input NullBuffer instead of rebuilding one. The current implementation constructs a fresh NullBufferBuilder and calls append_null/append_non_null per row. Since hex encoding is 1:1 with the input rows (a null in maps to a null out), the output nulls are identical to the input's. We could clone the input array's NullBuffer directly instead of rebuilding it. This requires plumbing the input array (or its nulls) through to hex_encode_bytes, which currently only receives an Iterator<Item = Option<T>> and has no access to the underlying NullBuffer.

    we can probably avoid a null builder by just cloning the input nulls? though i guess need to plumb the functions to pass those through
    @Jefffrey, perf: avoid per-row copy in Spark hex byte encoding #23473 (comment)

  2. Special-case the "no nulls" path. When the input NullBuffer is None, there is no need to check each value for Some/None. We could split into two loops — one tight loop for the no-nulls case and one for the has-nulls case.

    Another optimization is to special case the "has nulls" path (aka if the input NullBuffer is None, there is no need to check each value for Some / None too -- instead we could have two loops
    @alamb, perf: avoid per-row copy in Spark hex byte encoding #23473 (comment)

Describe the solution you'd like

Refactor hex_encode_bytes in datafusion/spark/src/function/math/hex.rs to:

  • Accept the input array (or its NullBuffer) so the output nulls can be cloned directly rather than rebuilt via NullBufferBuilder.
  • Take separate code paths for the no-nulls and has-nulls cases, avoiding a per-value Option check when the input has no nulls.

Validate with the existing datafusion/spark/benches/hex.rs benchmark against main.

Describe alternatives you've considered

Leaving the implementation as-is; it already avoids the per-row copy that #23473 targeted. These are incremental improvements on top of that.

Additional context

Both suggestions came from review of #23473.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions