Skip to content

Inline encoding for small xsd:decimal values (index format evolution) #1325

Description

@bplatz

Context

Every typed xsd:decimal routes to the per-(graph, predicate) NumBig arena — even \"1\"^^xsd:decimal (fluree-db-indexer/src/run_index/resolve/resolver.rs, DecimalStr arm). That makes decimals handle-keyed and equality-only, costs an arena round-trip on decode, and is the root reason novelty decimals are hard to translate into V3 overlay ops (see #1324).

Integers already have the right shape: i64-fitting values encode inline (NUM_INT), only overflow goes to the arena. Decimals deserve the same split.

Proposal

Canonical xsd:decimal (trailing zeros stripped) gives every value a unique (unscaled mantissa, scale) pair, so a packed inline o_key is well-defined, e.g.:

1 bit sign | 6 bits scale (0–63) | 57 bits |mantissa|    fits-check: |m| < 2^56, scale <= 63

17 significant digits with up to 63 decimal places — fixed-point money (scale 2) inlines to ±$7e14. Decode rebuilds the exact BigDecimal, so precision math is unaffected. Values that don't fit keep the arena path, exactly like overflow integers.

Two design decisions to settle in spec:

  1. Equality-keyed vs order-preserving. Equality-keyed (packed canonical form) matches current decimal semantics — decimals already compare by decode, never by o_key order. An order-preserving variant (normalized scientific form: sign, biased exponent, mantissa) would additionally enable range/FILTER pushdown on decimals, at meaningfully higher design risk.
  2. Migration. (o_type, o_key) is persisted fact identity: the same value must never exist under two encodings within one index root, or retracts re-encoding inline would fail to match arena-stored base rows. This requires an index-format version gate with reindex as the migration path, and a sweep through resolver spool kinds, the o_type registry, decode paths, stats hooks, overlay translation, and filter-pushdown gating (which must not assume numeric order unless the order-preserving variant is chosen).

Out of scope

This is independent of #1324 (which needs no format change and covers existing ledgers); inline decimals are the long-term fix that removes the arena dependency for the common case.

Metadata

Metadata

Assignees

No one assigned

    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