Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.
This repository was archived by the owner on May 29, 2026. It is now read-only.

wave-12 follow-up: bulk-save performance benchmark after per-row safeguards #2012

Description

@rubenvdlinde

Context

Wave-12 PR #2010 added per-row safeguards to the bulk-save path (PermissionHandler check, @self stripping, appendOnly enforcement, optional Opis validation). These run inside SaveObjects::applyBulkSafeguards() before the chunked upsert pipeline.

The wave-12 brief acknowledged correctness > raw throughput as the immediate trade-off. We now need to measure the actual impact and decide if any of the per-row checks need optimisation.

Baseline (pre wave-12)

Per the SaveObjects file docblock (lines 40-44):

  • 33k-object single-schema batches: ~5000 obj/s sustained throughput
  • Mixed-schema batches: ~30-40% lower

These numbers came from a path that skipped PermissionHandler + Opis validation + @self stripping entirely.

Expected impact

Per-row PermissionHandler::hasPermission():

  • First call per (schemaId, action, userId) hits resolveAuthorization (DB read for register fallback) + permission cache miss.
  • Subsequent calls in the same chunk hit $this->permissionCache (per-request memoisation).
  • Caveat: schemas with match rules bypass the cache (per-object eval) and rebuild on every row.

Empirical expectation: 2000-3000 obj/s on the same single-schema 33k-object benchmark. Mixed-schema worse.

Benchmark requirements

  1. Reproduce the historical 5000 obj/s baseline on the wave-9 HEAD (f92b128a) for comparison.
  2. Run the same benchmark on the wave-12 HEAD (post-merge of PR fix(security): wave-12 engine-primitive enforcement (readOnly, default-closed flag, bulk safeguards, dot-syntax, per-object authz) #2010) with:
    • _rbac: true (default; per-row PermissionHandler check active)
    • _validation: false (default)
  3. Run a third benchmark with _validation: true to measure Opis cost.
  4. Profile to identify the most expensive per-row check.

Optimisations to consider (if benchmark warrants)

  • PermissionHandler bulk pre-check: when the schema has NO match rules, evaluate once per chunk for (action, userId) instead of per-row — the verdict is identical and the cache already does this; the cost is the cache lookup itself.
  • @self strip vectorisation: replace per-row foreach with a single array_diff_key pass per chunk.
  • Opis validation chunk-batched: re-use a single Validator instance per chunk (currently per-row).
  • Skip PermissionHandler when _rbac: false AND caller is admin: already happens in Wave-12 code; verify no regression introduced.

Definition of done

  • Documented benchmark numbers comparing wave-9 vs wave-12 HEAD on representative single-schema and mixed-schema workloads.
  • If wave-12 drops below 1500 obj/s on the 33k single-schema benchmark, ship targeted optimisations to reach ≥2500 obj/s without removing any safeguard.
  • Update the SaveObjects file docblock with the new "PERFORMANCE GAINS" section.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No 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