Skip to content

perf: edit grouped ZSet pages without per-member allocations - #359

Merged
thweetkomputer merged 3 commits into
eloqdata:mainfrom
thweetkomputer:perf/zset-direct-edit-20261019
Oct 19, 2026
Merged

thweetkomputer merged 3 commits into
eloqdata:mainfrom
thweetkomputer:perf/zset-direct-edit-20261019

Conversation

@thweetkomputer

@thweetkomputer thweetkomputer commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Context

A single-member grouped ZSet update currently materializes a string for every member in the affected score pages. This adds allocation and copying even when the edit preserves page IDs and links.

Behavior before and after

Single-member mutations can now keep a fully validated, owned encoded page and construct its after-image without per-member string allocations. Empty or overflowing pages still use the existing mutable retirement, redistribution and split planner. Durable formats, Redis semantics, TTL, dual-index publication and recovery boundaries are unchanged.

Implementation

  • Add immutable encoded-page ownership, checked point edits and explicit materialization for topology changes. Use LocalSharedPtr for the shared byte block: snapshots stay on their key owner worker through decoding, staging, suspension and destruction, so no atomic reference count is needed. Debug builds check this thread affinity.
  • Apply the path to grouped single-member score updates, additions and removals, including cross-page moves.
  • Update Bycorf from 86d686724ddd1c5617fb1b62f8131e05571e8423 to 587a9e776f9f64729456d6772596d53597f4a983, incorporating the receive-ring change in Use a resizable receive ring with one inline descriptor bycorf#17.

Design decisions and alternatives

Keep complete input validation and copy each loaded page into owned storage so no physical read lease survives planning. Materialize member strings only when the existing topology-changing planner needs them. Batch and pop paths retain owned-member snapshots.

Documentation and comments

Updated the grouped-collection architecture's mutation ownership description. API and implementation comments cover ownership, validation, fallback and failure behavior.

Test plan

  • pre-commit run clang-format --from-ref upstream/main --to-ref HEAD and git diff --check: passed.
  • Before the Bycorf update, GCC 13 Release/SPDK build and 179 selected Debug tests passed: 132 codec/collection unit tests, 13 compact write tests and 34 grouped ZSet/demotion tests. New cases exercise encoded-page ownership, point-edit equivalence, malformed input, fallback, TTL and recovery.
  • Final head 99cc65ef with Bycorf 587a9e7: GCC 13 Debug and Release/SPDK builds passed, as did all 192 selected tests (the same 179 Lavik cases, 11 LocalSharedPtr ownership/affinity cases, and bycorf_received_buffer_queue_check / bycorf_tcp_buffered_read_check). Validation completed on 2026-10-19 at 13:53 UTC.

An 80-connection, 8,192-key crossover ran once per point, using the same data across versions. These measurements compare main 6a3d186c with candidate b0e79a05, both using the earlier Bycorf 86d68672, before the final dependency and worker-local ownership updates:

Payload Operation main → candidate throughput main → candidate p99.9
8 KiB ZINCRBY 86,377 → 85,938 ops/s 9.599 → 9.564 ms
8 KiB ZREM/ZADD 49,123 → 49,143 pairs/s 10.511 → 10.498 ms
1 MiB ZINCRBY 26,001 → 33,498 ops/s 29.212 → 26.937 ms
1 MiB ZREM/ZADD 19,874 → 20,431 pairs/s 34.438 → 32.275 ms

The ZINCRBY mean gain is not a demonstrated sustained improvement. Candidate throughput fell from 37,775 to 35,456 to 27,269 ops/s across the three 20-second windows; the last window was only 1.6% above main. ZREM/ZADD improved 2.8% in this single fixed-order run. The 8 KiB control, which does not use the new grouped path, was effectively unchanged. The final dependency and worker-local ownership updates have not been benchmarked; no stable performance claim is made for them.

Risk assessment

The main risk is ownership or framing mistakes when an encoded page crosses planning and publication. Full validation, owned storage, explicit fallback and recovery tests cover these boundaries. The dependency update also changes receive-buffer queue ownership and is validated separately.

Rollback plan

Revert this PR; no durable-format migration or data conversion is required.

Reviewer guide

Start with the encoded owner/editor in collection.h and collection.cpp, then the point-edit/fallback branch in zset.cpp and the publication/demotion adapters. Review the Bycorf gitlink separately from the benchmarked change.

Follow-up work

Investigate the late ZINCRBY throughput decline before claiming sustained gains. Existing measurements do not isolate device latency, completion scheduling or page-shape changes.

@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c2215b88-af30-4244-8e5f-d5253b442d7c
📥 Commits

Reviewing files that changed from the base of the PR and between 6a3d186 and 99cc65e.

📒 Files selected for processing: 10
  • bycorf
  • docs/architecture/09-grouped-collections.md
  • include/lavik/storage/detail/grouped/collection.h
  • src/storage/engine/grouped/collection.cpp
  • src/storage/engine/grouped/ordered_io.cpp
  • src/storage/engine/grouped/ordered_mutation.cpp
  • src/storage/engine/grouped/zset.cpp
  • src/storage/engine/impl.h
  • tests/grouped/collection_test.cpp
  • tests/grouped/zset_write_e2e_test.cpp
+----------------------------------------------------------------+
| 'Works on my machine' is not a QA strategy, it's a confession. |
+----------------------------------------------------------------+
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thweetkomputer
thweetkomputer merged commit 6e09bed into eloqdata:main Oct 19, 2026
15 of 18 checks passed
@thweetkomputer
thweetkomputer deleted the perf/zset-direct-edit-20261019 branch October 19, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant