Repository navigation
perf: reduce allocation and copying in compact point writes - #357
Conversation
Splice compact collection edits and encode bounded after-images directly into staging. Release worker state while preparing compact String updates, with retained key intent, snapshot validation, and read-pool pressure fallbacks.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughThe change adds bounded compact-edit planning and borrowed inline payload encoding for collection and String writes. It extends the append pipeline to accept compact encoders, adds compact Hash, List, and Sorted Set edit paths, changes ordinary compact String preparation, and adds codec and write-path tests. ChangesCompact Write Preparation
Priority: ⬇️ Low Estimated code review effort: 4 (Complex) | ~45 minutes Change: Refactor Sequence Diagram(s)sequenceDiagram
participant HSET
participant ExecuteHashLikeLocked
participant PlanCompactHashEdit
participant AppendLocked
participant WriteRecordLocked
HSET->>ExecuteHashLikeLocked: submit Hash mutation
ExecuteHashLikeLocked->>PlanCompactHashEdit: plan bounded edit
PlanCompactHashEdit-->>ExecuteHashLikeLocked: return changed payload plan
ExecuteHashLikeLocked->>AppendLocked: pass inline payload
AppendLocked->>WriteRecordLocked: pass compact encoder
Suggested reviewers: Merge Risk: ⚪ Minimal · up to
|
Context
Updating one element of an approximately 8 KiB compact collection can allocate strings for unchanged elements and rebuild a complete encoded image. Compact String range writes also hold worker store state while reading and preparing their replacement. These costs contribute to the small-write gap investigated in the large-object benchmark report.
Behavior before and after
Implementation
CompactPayloadowns framing and borrows unchanged encoded intervals and command operands. The existingInlineRecordPayloadwriter now accepts bounded compact records and consumes the plan after its final suspension, before publication and checksum handling. A checked borrowed List/Sorted Set reader validates complete framing without per-element ownership.Read leases remain alive through append waits. Remote leases and local read-pool exhaustion use owned output so queued writers do not retain the last read slot needed by another operation. Existing TTL, WATCH, transaction, replication, promotion and durable-format machinery remains the publication boundary.
Design decisions and alternatives
Use byte-level edit plans for common bounded point writes and keep owned builders for promotion and other operations. This avoids introducing a mutable hot-object cache or another durable representation. Transactional String preparation retains its existing state-lock boundary.
Documentation and comments
Updated
docs/architecture/09-grouped-collections.mdfor borrowed after-image ownership and compact String preparation. Added API/lifetime, publication-failure and read-pool fallback comments near the implementation.Test plan
Validation ran on Linux ARM64 with Clang 18 Debug and GCC 13 Release (
LAVIK_ENABLE_TRACE=ON). The existing local Bycorf checkout wasa37ed7d19885275472b707461dc2eddf4dccfbcd; its update is excluded from this PR, which retains the pinned gitlink86d686724ddd1c5617fb1b62f8131e05571e8423. CI must also validate the pinned dependency.Final checks passed:
The focused unit run passed 22 tests; the compact E2E run passed 13 tests; all five Valkey type suites passed. New coverage includes 8 KiB mixed edits and recovery, SETRANGE concurrency, ordinary and EXEC encoding failures preserving old values/WATCH, single-read-slot/indirect-key fallback, malformed/truncated framing, and randomized Set deletion plans. Additional legacy memory-limit and transaction rollback cases passed. A startup timeout and a timing-sensitive blocking assertion seen during concurrent builds passed when rerun after build contention ended.
The complete repository test suite and comparable QPS benchmarks have not been run.
Risk assessment
The main correctness risk is borrowed-source lifetime across append suspension, especially under read-pool pressure. The encoder remains private until successful consumption, and fault-injection/recovery tests cover failed publication. The stored encoding and promotion thresholds remain compatible.
Rollback plan
Revert this change; no data migration is required.
Reviewer guide
Start with
compact_payload.hand the borrowed readers, then the type-specific planners inhash_codec.cpp,list_tree.cpp, andgrouped/zset.cpp. Review the String lock boundary andcompact_api.cpp/write.cpplifetime and publication changes together. The compact E2E tests exercise the shared failure boundary.Follow-up work
Rerun the comparable 8 KiB workload and collect CPU/allocation profiles to quantify QPS and allocation improvements. This PR makes no measured throughput claim.
Summary by CodeRabbit
Performance
Reliability