Skip to content

fix(exec): bound reopen and fixed-hop LIMIT query RSS at scale #904

Description

@DecisionNerd

Problem

The exact merged S20 Graph500 ladder on commit eccb6e06726d05cdef9e5242cad885be80565eee completed bounded ingest on a private 2-performance-vCPU / 4 GiB Fly machine, then was kernel-OOM-killed during the ordinary fixed-hop query proof.

Authoritative aggregate evidence:

  • generator: 4.80 s, about 80 MB peak RSS
  • ingest: 2,602.08 s, 15,698,918 live unique edges, about 688 MB peak RSS
  • reopen plus recount: passed in 231.40 s but raised process high-water RSS to 3,328,512,000 bytes
  • query phase: MATCH (a)-[r]->(b) RETURN b.node_uuid AS id ORDER BY id LIMIT 1000, followed by the two-hop equivalent if the first completes
  • last durable query journal: about 1.90 GB anonymous RSS resident and 3.33 GB process high-water
  • kernel victim: scale-g500-ladd, about 3.80 GB anonymous RSS and negligible file RSS
  • exit status: 137
  • volume: 52% used, so this was not storage exhaustion

The query journal is written before the one-hop request and only persisted again after both requests, so current evidence cannot yet distinguish whether the OOM occurred in the one-hop query or the two-hop query. That attribution gap is part of the required repair.

Objective

Make reopen/recount and fixed-hop ORDER BY ... LIMIT execution remain bounded by explicit batches/frontiers rather than graph cardinality or path-result cardinality. GraphForge is designed to be disk-bound at scale; a larger machine is not the repair.

Requirements

  • Measure RSS and operator state independently for project open, node count, edge count, one-hop expand, one-hop order/limit, two-hop first expansion, two-hop second expansion, and two-hop order/limit.
  • Identify retained allocations after reopen/recount and prove they are released or intentionally bounded before query execution.
  • Push terminal demand through fixed-hop expansion where semantics permit, while preserving deterministic global ORDER BY results.
  • Implement bounded top-k/spill for ordered LIMIT rather than materializing all candidate/path rows.
  • Keep adjacency/topology access streaming or shard/page selective; do not load the complete edge set into anonymous memory.
  • Preserve ordinary Rust facade execution. Do not add a ladder-only query path, skip, relaxed limit, or increased RAM requirement.

Acceptance criteria

  • S20 source reopen, recount, one-hop query, and two-hop query complete on the same 4 GiB machine class with phase/operator RSS evidence and reasonable headroom.
  • Peak anonymous RSS plateaus across lower rungs and remains bounded by documented operator budgets, not edge/path cardinality.
  • Ordered LIMIT results match the existing deterministic semantics.
  • Tests fail if a fixed-hop ordered LIMIT materializes the complete candidate set or if query allocations remain retained after completion.
  • The journal persists one-hop completion before starting two-hop work, so a host OOM identifies the exact query/operator.
  • Full source → export → verify → clean import → reopen proof completes without a benchmark-only fallback.

Root-cause boundaries

This issue is independent of #901. #901 owns superlinear topology publication I/O and retained-generation disk amplification. This issue owns post-ingest reopen/recount and execution memory. Both block the canonical S20 gate #900.

Observability

Record aggregate rows examined/emitted, expansion frontier size, top-k heap/spill bytes, Arrow batch rows, process RSS before/after each operator, and retained memory after each query. Do not record graph identities, values, paths, or credentials.

Testing

  • deterministic lower-scale tests with fixed batch/operator budgets across increasing graph cardinality
  • one-hop and two-hop ordered LIMIT plan and execution regressions
  • allocation-release regression between recount and query phases
  • exact changed-surface formatting, clippy, Cargo/Bazel drift, and authoritative CI

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions