Refactor backlog
Open Items
To Solve
Point-operation hot-path cleanup
Items 100.1 through 100.3 and 100.5 are complete. Item 100.4 is
intentionally deferred from this sequence; item 100.6 is the final active
step.
- [ ] 100.6 Re-profile the accepted sequence and stop at the measured boundary
(Risk: LOW). Owner:
benchmarksand refactoring docs. Outcome: run the canonical SegmentIndex comparison and focused JFR profiles, record accepted, rejected, and still-deferred candidates, and update architecture docs only for behavior that actually changed. Validation: benchmark comparison reports,python3 scripts/check_docs_nav.py,mkdocs build --strict, andgit diff --check. Status: blocked by the performance gate. The complete canonical profile now runs, but its one-fork comparison produced contradictory large deltas and severalworseresults. Two focused five-fork live-get A/B cycles retained overlapping throughput intervals and did not reproduce a stable whole-path allocation mean. Next safe action: rerun the same artifacts on a quiet, dedicated host before archiving this item.
[ ] 80. Make WAL durability explicit for non-fsync storage adapters so SYNC and GROUP_SYNC never claim guarantees that the active storage backend cannot provide.
[ ] 81. Split WalRuntime into focused writer, recovery, segment-catalog, and sync-policy responsibilities instead of keeping all lifecycle paths behind one shared monitor.
[ ] 82. Replace the slow generic WalStorageDirectory fallback with an explicit seekable/capability-aware storage path, or reject unsupported backends early.
[ ] 79.1 Freeze architecture, docs, and migration contract (Risk: HIGH)
[ ] 79.2 Introduce partition runtime and routing layer (Risk: HIGH)
[ ] 79.3 Switch SegmentIndexSession read/write/delete paths to partitions (Risk: HIGH)
[ ] 79.4 Implement drain, publish, flush, close, and WAL recovery (Risk: HIGH)
[ ] 79.6 Clean up config, metrics, control-plane tuning, and obsolete code (Risk: HIGH)
[ ] 79.7 Refresh unit tests, integration tests, and JMH gates (Risk: HIGH)
[ ] 78 Monitoring/Management platform rollout (Risk: HIGH)
Regular Maintenance
[ ] M37 Audit segment package for unused or test-only code (Risk: LOW)
[ ] M38 Review segment package for test and Javadoc coverage (Risk: LOW)
[ ] M39 Audit segmentindex package for unused or test-only code (Risk: LOW)
[ ] M40 Review segmentindex package for test and Javadoc coverage (Risk: LOW)
[ ] M41 Audit segmentregistry package for unused or test-only code (Risk: LOW)
[ ] M42 Review segmentregistry package for test and Javadoc coverage (Risk: LOW)
[ ] M43 Avoid pattern-name abstractions unless they own lifecycle, resource opening, or rollback-sensitive cleanup (Risk: LOW)
Unfinished Audit
- Deferred status-value reuse. Boundary:
enginepoint-operation and route leasing results. Reason: exploratory JFR did not identifyOperationResultorRouteLeaseAttemptas material allocation sources, and generic singleton reuse adds type-safety and semantic risk. Evidence still needed: a representative allocation profile with these constructors on a material hot stack. Item100.6JFR still did not show that evidence. Next safe action: revisit only after a new production-equivalent profile does. - Deferred 100.4 sampled point-operation latency recording. Boundary:
engineoperation monitoring. Reason: explicitly excluded from the current refactoring sequence; operation counts and latency observations remain unchanged. Item100.6sampled latency recording in execution stacks but recorded no live-get monitor contention. Next safe action: reconsider only after a production profile identifies material contention. - Deferred chunk-store cache redesign. Boundary:
engineLruChunkStoreCache. Reason: the implementation has one synchronized access-ordered map, but the persisted cache-enabled profile recorded no contention events, and item100.6JFR did not make it material. Evidence still needed: representative blocked-time or duplicate same-page load measurements. Next safe action: shard or add minimal per-key single-flight only for the demonstrated failure mode. - Canonical comparison gate remains blocked. Boundary:
benchmarkssegment-index-pr-smoke. The benchmark now completes for both baseline and candidate, but the one-fork report simultaneously marked all get paths22.07%to45.53%worse and hot-put/split-heavy paths roughly47%to57%better. Focused five-fork throughput intervals overlapped, and a reverse-order live-get repeat remained inconclusive. Evidence still needed: the same A/B artifacts on a quiet, dedicated host. Next safe action: rerun; do not tune code to these contradictory point estimates. - Repeated explicit maintenance during background split population can time
out. Boundary: multi-segment benchmark setup and the production
flushAndWait()/split interaction. The failure reproduced at 8,192 and 32,768 keys and with segment-cache limits from3through256; the stack timed out inMappedSegmentMaintenanceService.awaitSegmentReady(...)while reloading a closed segment. The read benchmark now performs one final settled flush so it can measure reads, but that does not fix the underlying maintenance interaction. Next safe action: investigate it as a dedicated lifecycle/concurrency issue outside item100.6. - Route-lease monitor contention needs production confirmation. Boundary:
RouteEntrylease acquisition/release. The item100.6JFR hot-put stress profile recorded 14 blocked monitor events totaling143 mswith twenty threads targeting one route; live get recorded none. Next safe action: redesign only if a production JFR shows the same monitor as material. - Deferred immutable segment-ID set. Boundary:
RouteMapSnapshot. Reason: direct map-value scanning removed the temporary list and improved the 50,000-route lookup from323.428 us/opto115.267 us/opwith effectively zero per-call allocation. Item100.6JFR did not show the remaining scan as material. Evidence still needed: an end-to-end exact-segment acquisition profile showing that it justifies duplicate snapshot state and extra publication cost.
Done (Archive)
Senku Index implementation
Item 101 implements the first version described by
Senku architecture and contracts. The sequence is
top-down: freeze the public contract first, then add the minimum storage and
merge machinery needed to make that contract executable, and finally prove the
whole index through its public API. Open or link one implementation issue before
starting the first production-code slice.
Package and implementation rules for every item:
- The supported public API belongs to
org.hestiastore.index.senku; initial implementation classes belong to the singleorg.hestiastore.index.senku.internalpackage. Do not add speculativeutil,spi, factory, adapter, or one-class subpackages. - Reuse
Directory,FileLock,PropertyStoreImpl,ChunkStoreFile,ChunkStoreWriterTx, the existing Snappy and magic-number filters,SingleChunkEntryWriterImpl,SingleChunkEntryIterator,Reader,EntryComparator,TypeDescriptor, andIndexConfigurationDefaults.DEFAULT_DISK_IO_BUFFER_SIZE_BYTES. Do not change existing storage or Segment Index code merely to make Senku fit. - Use
Vldtnfor every argument, state-independent configuration, constructor, and factory validation. Add a narrowly scopedVldtnoperation only when no existing operation expresses the required check; test that operation directly. Convert lower-level failures at the Senku boundary toIndexExceptionas specified by the architecture. - Prefer JDK
HashMap,PriorityQueue, locks, conditions, latches, streams, and executors. Do not introduce an interface with one implementation, a recovery framework, runtime monitoring, persisted configuration, or an asynchronous ingestion layer in this sequence.
Testing rules for every item:
- Add the matching JUnit 5
*Testfor every changed production class in the same package. A slice is not complete when only a later end-to-end test covers its new classes. - Use a real
MemDirectoryfor every Senku unit and integration test. Do not useFsDirectory, temporary filesystem directories, or mockedDirectoryobjects. A small test-onlyMemDirectorysubclass may inject one specific failure; do not build a generic fault-injection framework. - Put whole-index tests under
engine/src/integration-test/javawith an*ITsuffix and exercise only the public Senku API. Keep component tests underengine/src/test/java. - Cover empty, one-element, exact-boundary, boundary-plus-one, duplicate-key, malformed-input, repeated-call, and cleanup/resource-ownership cases wherever they apply. Assert both returned data and the resulting in-memory directory tree.
-
Make concurrency tests deterministic with latches, barriers, conditions, direct invocation of a package-private coordinator scan operation, and bounded awaits. Never use
Thread.sleep()and never make the three-second production scan interval configurable solely for tests. -
[x] 101. Implement the first Senku Index without changing existing low-level storage behavior (Risk: HIGH). Owner:
engineSenku package. Outcome: the documented write-once lifecycle, synchronous flushes, background sorted-run maintenance, finalization, and globally sorted ready stream are available through the new public API. Guardrails: all101.xslices and their tests are complete; deferred features remain in the architecture's limitations or technical-debt sections. Validation: items101.1through101.20, the Senku JMH gate,mvn clean verify, strict documentation build, and a clean static-analysis report for the new package.
Public contract and persisted format
-
[x] 101.1 Add the Senku public contracts and flat builder configuration (Risk: MEDIUM). Owner:
engine/src/main/java/org/hestiastore/index/senku. Outcome: add the documented merge function and registry, writing and ready handles, builder settings/defaults, and package Javadoc without placeholder operations that throwUnsupportedOperationException. Guardrails: expose no delete, abort-writing, writing close, monitoring, or persisted write tuning; keep object construction in the builder; useVldtnfor all inputs and every numeric boundary. Validation: direct tests for every default, missing required setting, null dependency, lower/upper boundary, overflow-sensitive capacity calculation, zero/duplicate merge-function registration, and repeated invalid calls. -
[x] 101.2 Implement deterministic path names and exact property codecs (Risk: HIGH). Owner: Senku internal metadata. Outcome: parse and write the documented
flush-N,shard-N,level-N,run-N, part, manifest, and ready formats using canonical numeric names with a minimum width of five digits andPropertyStoreImpl; publish every manifest last through the existing directory transaction and rename operations. Guardrails: property files contain only documented keys, are authoritative, and have no compatibility/version framework; unknown, missing, extra, malformed, negative, non-contiguous, or contradictory data fails fast. Validation: round-trip and invalid-input tests for empty and non-empty runs, flush manifests, ready metadata, name limits, extra/missing parts, temporary files, and exact directory layouts inMemDirectory.
Storage primitives
-
[x] 101.3 Implement the opaque packed
LargeFilePositionvalue (Risk: MEDIUM). Owner: Senku internal storage. Outcome: encode and decode the documented non-negativelonginto a physical part number and local signed-intCellPositionwithout exposing a page ID. Guardrails: use overflow-safeVldtnchecks and keep shifting/masking inside this class. Validation: direct tests for zero, maximum local position, maximum supported manifest part, round trips, numeric ordering, sign-bit preservation, negative inputs, and a position beyond the declared part count. -
[x] 101.4 Build
LargeFileWriterTxandLargeFileReaderover existing chunk stores (Risk: HIGH). Owner: Senku internal storage. Outcome: append versioned, compressed entry pages, rotate bymaxEntriesPerPart, commit contiguouspart-N.chunkfiles, and read sequentially or from an opaque position while crossing parts. Guardrails: reuse the documented filter order and transaction lifecycle; do not virtualizeDirectory, expose page IDs, split a page, add random mutation, or promise rollback after failure. Validation: direct tests for empty commit, one page, exact part boundary, rotation, multi-part reads, positioned reads, stable EOF, idempotent close, read/append after close or commit, page-version mismatch, invalid/missing/extra parts, early failure, and underlying reader/writer closure. -
[x] 101.5 Implement the compressed flush
shard-index.datcodec (Risk: HIGH). Owner: Senku internal storage. Outcome: write and read exactly one versioned 20-byte big-endian record for every configured shard containing shard ID, opaqueLargeFilePosition, and record count. Guardrails: use one existingChunkStoreFile; store no page IDs; use overflow-checking count arithmetic and reject a table that cannot fit the existing signed-intstorage API. Validation: round trips for one and many shards, empty shards, maximum shard count, malformed length/order/ID/count/position, wrong version, extra chunks, truncated payload, and count overflow.
Sorting and ingestion
-
[x] 101.6 Implement one reusable k-way sorted-entry merge loop (Risk: HIGH). Owner: Senku internal merge. Outcome: use a JDK
PriorityQueueand the configured key comparator to lazily merge sorted cursors and collapse every duplicate key through the one configured merge function. Guardrails: do not materialize an input or output run, preserve no write order, and add no merge-function dispatch abstraction. Validation: pure unit tests for zero, one, two, and many inputs; empty inputs; all-equal keys; duplicates within and across inputs; skewed lengths; comparator edge cases; count overflow; merge callback failure; and closure of all cursors on success, early consumer close, and failure. -
[x] 101.7 Implement
SenkuIngestorand synchronous flush publication (Risk: HIGH). Owner: Senku internal ingestion. Outcome: serializeput()andfinishWriting()with oneReentrantLock, merge duplicate values in oneHashMap, flush at the distinct-key limit on the caller thread, partition byMath.floorMod(hash, shardCount), sort each shard, and publish one flush generation with its sparse index and manifest. Guardrails: validate keys and values withVldtn, never useConcurrentHashMap, never publish an empty flush, and make no copy or mutation-safety promise for caller objects. Validation: direct tests for nulls, distinct versus duplicate threshold accounting, exact threshold flush, final partial flush, negative hashes includingInteger.MIN_VALUE, shard skew, sorted shard regions, page/part boundaries, concurrent caller serialization, merge callback failure, and manifest-last behavior under an injected in-memory write failure.
Maintenance data path
-
[x] 101.8 Implement one flush-to-level-zero batch (Risk: HIGH). Owner: Senku internal merge. Outcome: select up to
mergeFanIncommitted flush generations, validate their manifests and sparse indexes once, run one independent merge job for each shard, publish one level- zero run per shard including empty runs, and delete the shared flush inputs only after every shard completion is accepted. Guardrails: jobs read only their persisted shard ranges; no job owns or removes the permanentflush/directory; L0 jobs may run in parallel. Validation:MemDirectorytests for full and drain-mode partial batches, empty and non-empty shards, duplicate collapse, multi-page/part input, one failed shard, completion in different orders, no early input deletion, manifest-last output, and exact batch cleanup. -
[x] 101.9 Implement same-level sorted-run merge and promotion (Risk: HIGH). Owner: Senku internal merge. Outcome: merge up to
mergeFanInruns from one shard and one numeric level into the next level, including drain-mode partial groups and one-input rewrites needed to leave one terminal run. Guardrails: never merge different levels, never run two sorted- run jobs for the same shard, and use the shared lazy merge loop and exact manifest counts. Validation: tests for normal fan-in, partial groups, one-input promotion, empty runs, duplicate keys, record-count overflow, early/late EOF, mixed-level rejection, publication failure, input cleanup, and removal of empty run/level/shard directories only when unowned.
Coordinator and lifecycle
-
[x] 101.10 Implement the coordinator-owned source catalog and eligibility scan (Risk: HIGH). Owner: Senku internal maintenance. Outcome: one package-private
scanOnce()traverses only structural directories and property metadata, discovers committed sources, ignores incomplete sources, and computes deterministic bottom-up merge candidates. Guardrails: do not enumerate data parts during ordinary scans, read shard data, repair metadata, add a catalog lock, or depend on one atomic directory-tree snapshot. Validation: direct no-sleep tests for empty trees, new committed sources, incomplete temporary sources, authoritative metadata, missing/extra/conflicting catalog entries, stable repeated scans, level ordering, shard ordering, and old-run selection. -
[x] 101.11 Add bounded scheduling, reservations, and completion handling (Risk: HIGH). Owner: Senku internal maintenance. Outcome: reserve exact input and output directory IDs before placing jobs into the fixed worker pool and bounded FIFO queue; serialize scans and completion processing on the one coordinator thread; accept a worker-published output and eagerly delete its obsolete inputs. Guardrails: keep pending work in the catalog/L0 batch rather than creating unbounded job objects; allow L0 beside a sorted-run merge for the same shard, but only one sorted-run job per shard; workers publish and return immutable results but never edit the catalog. Validation: deterministic executor tests for full capacity, FIFO queueing, duplicate/conflicting reservations, output observed before completion, concurrent L0 and run work, unique run IDs, completion order, worker failure, cancellation, and exact reservation release.
-
[x] 101.12 Add queue-driven ingestion backpressure (Risk: HIGH). Owner: Senku internal maintenance and ingestion. Outcome: the coordinator pauses ingestion only when the bounded queue is full and known eligible work remains unqueued, and resumes it only when capacity exists and no eligible work remains pending. Guardrails: keep one boolean and one
Conditionunder the ingestion lock; perform no directory I/O while holding that lock; preserve caller interruption; do not add byte/disk-space prediction. Validation: latch-based tests for high/low water transitions, spurious/repeated scans, queue-full-without-backlog, backlog-with-capacity, multiple blocked callers, wake on finish/error, interrupt preservation, and no lost signal or put after writing ends. -
[x] 101.13 Implement writing runtime ownership and fail-fast shutdown (Risk: HIGH). Owner: Senku internal lifecycle. Outcome:
create()validates before mutation, acquires the single rootFileLock, creates non-daemon maintenance executors, records onefirstFailure, and performs the documented minimal shutdown without rollback or filesystem cleanup. Guardrails: catchException, neverThrowable; do not interrupt running merge jobs; release every owned resource exactly once; restore interrupt status after uninterruptible lifecycle waits. Validation: direct tests for create failure at each acquisition step, second-handle lock rejection, caller-thread and background failures, racing failures, queued/running jobs, schedule failure, worker termination, lock release, no leaked live thread, suppressed cleanup errors, and generic laterERRORrejections. -
[x] 101.14 Implement
finishWriting()and terminal layout publication (Risk: HIGH). Owner: Senku internal lifecycle and maintenance. Outcome: reject later writes, flush the remaining map, immediately enter drain mode, continue same-level merges until every configured shard owns exactly one terminal run, stop all maintenance threads, publishready.propertieslast, and transfer the still-held root lock toSenkuReady. Guardrails: create an empty terminal run for every empty shard, keepflush/present and empty, do not equalize terminal levels, and do not add a final full-data rewrite. Validation: deterministic tests for an empty index, partial flush group, partial run groups, one-input promotions, uneven terminal levels, concurrent puts and finish calls, awakened blocked puts, interrupted caller, failed drain, exact cleanup/layout, thread termination, and lock transfer.
Ready streaming
- [x] 101.15 Implement ready-index open, global streaming, and close
(Risk: HIGH). Owner: Senku public API and internal stream. Outcome:
open()acquires the root lock, validates the authoritative ready tree without creating missing directories, and exposes one lazy globally sorted m-way stream across the terminal shard runs using the established Segment Index stream-closing behavior. Guardrails: permit only one active stream, retain no background thread, never materialize the dataset, make ready close idempotent, and makeSenkuReady.close()break an active stream and release the lock. Validation: direct tests for empty and many-shard streams, global comparator order, laziness, early stream close, exhaustion, consumer failure, second stream rejection, repeated ready close, stream use after ready close, close during streaming, reopening after close, wrong I/O size behavior, and every missing/extra/malformed ready-layout case.
Whole-index proof and performance
-
[x] 101.16 Add public-API functional integration coverage (Risk: HIGH). Owner:
engine/src/integration-test/javaSenku tests. Outcome: drive create, unsorted puts, synchronous flushes, maintenance, finalization, stream, close, and reopen through the public API only and compare every entry with an independent sorted reference map. Guardrails: useMemDirectoryonly and configuration values small enough to cross every boundary in one test run. Validation:*ITcases for empty, one key, all duplicate keys, one and many shards, one and many flushes/pages/parts/levels, highly skewed hashes, exact thresholds, threshold-plus-one, and multiple merge fan-ins. -
[x] 101.17 Add public-API concurrency and lifecycle integration coverage (Risk: HIGH). Owner:
engine/src/integration-test/javaSenku tests. Outcome: prove that concurrent callers, maintenance, backpressure, finalization, streaming, and root locking compose without data loss, deadlock, or resource leaks. Guardrails: realMemDirectory, bounded waits, no sleeping, no private state assertions, and no unsupported crash-recovery expectations. Validation: repeated*ITcases for disjoint and duplicate keyspaces, maintenance overlapping ingestion, queue saturation, finish races, active- stream close, second-handle rejection, injected storage/merge failure, and eventual termination of every Senku-owned non-daemon thread. -
[x] 101.18 Add deterministic reference-model and boundary stress tests (Risk: MEDIUM). Owner: Senku unit and integration tests. Outcome: seeded randomized sequences compare the final stream and duplicate reductions with a small independent model across a matrix of shard counts, flush limits, page limits, part limits, fan-ins, thread counts, and queue sizes. Guardrails: log the seed on failure, cap the matrix for normal CI, and do not introduce a property-testing dependency. Validation: repeat the focused suite enough to cover zero/one/max-small boundaries and multiple completion interleavings, then run it as part of normal
mvn verify. -
[x] 101.19 Establish the first Senku performance baseline (Risk: MEDIUM). Owner:
benchmarksand Senku implementation. Outcome: add the smallest JMH coverage that measures ingestion throughput, synchronous flush, flush-to-L0 merge, sorted-run merge, ready-stream throughput, and end-to-end ingest-to-first-sorted-result latency usingMemDirectory. Guardrails: add no production tuning solely for the benchmark and claim no improvement without repeated forks and recorded confidence intervals. Validation: benchmark contract/smoke tests plus persisted baseline results for representative duplicate rates, shard skew, and boundary-crossing configurations. -
[x] 101.20 Complete the Senku implementation gate and documentation audit (Risk: MEDIUM). Owner:
engine,benchmarks, and documentation. Outcome: every production class has its direct test, the public API and lifecycle have complete Javadocs, the actual package/layout/defaults match the architecture, and resolved implementation discoveries are incorporated without populating speculative features. Guardrails: retain current limitations in the published architecture; remove unused code/imports and do not leave placeholder types or empty planning sections in published documentation. Validation: focused Senku tests,mvn clean verify,mvn clean site,python3 scripts/check_docs_nav.py,mkdocs build --strict, andgit diff --check. -
[x] 100.5 Replace list-building segment membership checks with direct snapshot lookup (Risk: MEDIUM).
RouteMapSnapshot.containsSegmentId(...)now scans immutable map values directly, andMappedSegmentLeaseServiceuses it for exact mapped-segment checks without constructing an unbounded list.- A focused one-thread JMH benchmark measured a successful middle-position lookup with five forks, three warmup iterations, five measurement iterations, and GC profiling on the same JDK 25 arm64 macOS environment.
- Results were
63.807 -> 5.627 ns/opat 10 routes,5.647 -> 1.649 us/opat 1,000,64.027 -> 22.364 us/opat 10,000,323.428 -> 115.267 us/opat 50,000, and660.687 -> 228.547 us/opat 100,000. Reported confidence intervals did not overlap at any tested size. - Allocation changed from
384 B/op,4,344 B/op,40,361 B/op,200,346 B/op, and400,355 B/op, respectively, to effectively zero. The improvement is measurable from 10 routes, the smallest tested size; no claim is made below 10. - Focused engine tests passed with 23 tests, benchmark contract/tooling tests
passed with 12 tests, and
mvn clean verifypassed across all 10 reactor modules.
- [x] 100.3 Publish and reuse one immutable
RouteMapSnapshotper route-map version (Risk: MEDIUM).PersistentSegmentRouteMapnow publishes copied routes and their version together through one volatileRouteMapSnapshotreference. Repeatedsnapshot()calls perform no locking or wrapper allocation, and only real mutations publish the next instance.- Focused identity, no-op mutation, version-transition, and concurrent split
publication coverage passed: 17 route-map tests.
mvn clean verifypassed across all 10 reactor modules. - Five-fork live-get JMH with GC data moved from
3.493 M ops/s,168.175 B/opto3.427 M ops/s,148.507 B/op. Throughput changed by-1.87%with overlapping confidence intervals; allocation fell by19.668 B/op(-11.70%) with non-overlapping reported confidence intervals. - Five-fork hot-put throughput moved from
2.853 M ops/sto3.170 M ops/s, but its confidence intervals overlapped. Allocation was bimodal across the candidate and repeat runs (136to216 B/op), so no hot-put allocation or throughput improvement is claimed. - The focused throughput summaries passed the canonical comparison tool
with no regression: live get was
neutraland hot put wasbetterunder its percentage thresholds. The broader canonical-profile setup failure is retained in the unfinished audit rather than hidden.
- [x] 100.2 Add production-equivalent context-logging benchmark coverage
(Risk: LOW).
SegmentIndexGetBenchmarkandSegmentIndexHotRoutePutBenchmarknow expose the same enabled/disabled context-logging parameter. Existing canonical profiles pin it off, whilesegment-index-context-logging.jsonruns the focused comparison with a Logback MDC backend and log emission disabled.- The profile runner now rejects empty JMH result files instead of publishing a successful summary after all forks fail.
- Benchmark profile contract and script smoke coverage passed with 11
tests; the packaged runner also passed a direct enabled-MDC smoke run.
mvn clean verifypassed across all 10 reactor modules. - Three forks with three warmup and five measurement iterations reported
live-get means of
3.487 M ops/s,171.884 B/opdisabled and3.122 M ops/s,204.007 B/openabled. Hot-put means were2.527 M ops/s,201.239 B/opdisabled and2.800 M ops/s,237.404 B/openabled. - Enabled-MDC allocation means were about
32.123 B/ophigher for live gets and36.165 B/ophigher for hot puts. Throughput and allocation confidence intervals overlapped in both comparisons, so this run alone does not establish either effect. Production logging behavior was unchanged.
- [x] 100.1 Close the losing
SegmentReadPathsearcher after concurrent first access (Risk: MEDIUM).SegmentReadPathnow closes a redundantly constructed searcher immediately after losing the cache CAS; the winner remains cached.- A deterministic two-thread
SegmentReadPathTestverifies that exactly one supplier closes after the race and the winner closes with the read path. mvn -pl engine -Dtest=SegmentReadPathTest testpassed with 7 tests.mvn clean verifypassed across all 10 reactor modules. [x] 99. ReplaceSessionOperationGateper-operation monitor contention with atomic in-flight tracking and bounded close-side drain polling (Risk: MEDIUM)- Focused session concurrency tests, benchmark module tests, and the full Maven verification pipeline pass.
- Targeted JMH stack sampling removed all
SessionOperationGateblocked frames and the per-operationObject.notifyAll()frame. - The targeted throughput result moved by -3.3%, with heavily overlapping
confidence intervals; the canonical smoke profile was also too noisy to
establish a throughput regression or improvement.
[x] 97. Clarify
core.sessionresponsibility boundaries by moving topology runtime composition to route/topology internals, giving core storage its own open spec and observer types, and preserving lifecycle behavior. [x] 98. Simplify SegmentIndex initialization after the broad assembly refactor by keeping explicit opening points for bootstrap, session startup, and runtime resources while removing pattern-only assembler/request/components layers. [x] 89. Rework split routing around a runtimeRouteTopologyso route handoff, draining, and split publish are owned by topology code whileSegmentRegistryremains responsible only for physical segment instances andSegmentRouteMapremains responsible only for persisted routing. [x] 90. Define theRouteTopologycontract with route states such asACTIVE,DRAINING, andRETIRED, plusRouteLeaseacquisition/release semantics and deterministic drain behavior for in-flight routed operations. [x] 91. Add topology bootstrap from the versionedSegmentRouteMapsnapshot so startup builds runtime route entries without changingSegmentRegistry,BlockingSegment, orSegmentcontracts. [x] 92. Refactor foreground routed operations to resolve aSegmentRouteMapsnapshot, acquire aRouteTopologylease for the resolved segment id and map version, use the existingSegmentRegistryto load the segment, and retry from the correct boundary on topology drain, stale version, registry unavailability, segmentBUSY, or segmentCLOSED. [x] 93. Add focused tests for topology lease acquire/release, drain waiting, stale map-version rejection, route retirement, and the retry boundaries used byput,deletethrough tombstone writes, andget. [x] 94. Rework split execution so the parent route moves toDRAININGbefore child materialization, in-flight leases drain, child materialization uses existing registry materialization, child routes publish inRouteTopology,SegmentRouteMapis updated and flushed, and the retired parent segment is cleaned up after publish. [x] 95. Define and test the split failure policy for topology publish,SegmentRouteMappersistence failure, child materialization cleanup, parent cleanup retry, and startup recovery from the persisted map. [x] 96. Remove the legacy split admission gate after routed operations and split publish useRouteTopologyleases, then update concurrency documentation to makeRouteTopology,SegmentRegistry, andSegmentRouteMapownership boundaries explicit. [x] 83. Define the new split runtime contract aroundhintSplitCandidate(...),awaitQuiescence(...), and managed lifecycle shutdown, and remove public scheduling concepts such as full-scan requests from the intended service shape. [x] 84. Introduce a managed split runtime skeleton with explicitOPENING -> RUNNING -> CLOSING -> CLOSEDstate transitions and fail-fast behavior for calls made outsideRUNNING. [x] 85. Replace the current split-policy work-state loop with a candidate registry built fromMap<SegmentId, State>plus a blocking ready queue so split hints are deduplicated and workers block instead of polling. [x] 86. Split policy evaluation from split execution so policy workers only validate mapping and threshold eligibility, then hand off accepted candidates to the dedicated split executor. [x] 87. Rebuild periodic reconciliation around the new candidate registry so the 250 ms scanner only offers over-threshold mapped segments that are not already queued or in process. [x] 88. Rework split runtime tests around lifecycle, deduplicated candidate scheduling, blocking worker wakeup, quiescence, and close-drain behavior before removing the remaining legacy split-policy orchestration. [x] 87 Decompose WAL into smaller durable-log subsystems (Risk: HIGH) - End-game achieved:
WalRuntimenow reads as a compatibility-facing orchestration facade instead of a monolithic durable-log implementation. - End-game achieved: WAL metadata/catalog, segment inventory, recovery,
append-path writing, durability policy, and metrics ownership now live in
dedicated collaborators under
segmentindex.wal. - End-game achieved: public
WalRuntimeoperations, metrics, and WAL on-disk compatibility remain stable while internal ownership boundaries are explicit and test-covered. [x] 87.1 FreezeWalRuntimecontract, state model, and migration invariants (Risk: HIGH) [x] 87.2 Add characterization coverage for the current WAL orchestration seams (Risk: HIGH) [x] 87.3 Extract WAL metadata/catalog state behind one internal model (Risk: HIGH) [x] 87.4 Extract segment inventory, retention, and cleanup ownership (Risk: HIGH) [x] 87.5 Extract recovery scan and corruption-repair ownership (Risk: HIGH) [x] 87.6 Extract append writer and sync policy execution (Risk: HIGH) [x] 87.7 ReduceWalRuntimeto orchestration and lifecycle assembly (Risk: HIGH) [x] 87.8 Refresh docs, benchmarks, and follow-on cleanup after extraction (Risk: HIGH)
[x] 83 Replace compatibility-shaped public model with domain-shaped public API (Risk: HIGH)
- End-game achieved: canonical public configuration now exposes
direct-to-segment write-path vocabulary via IndexWritePathConfiguration
instead of making legacy partition naming the source of truth.
- End-game achieved: canonical runtime metrics now expose a dedicated
SegmentIndexWritePathMetrics model.
- End-game achieved: legacy runtime configuration and partition/drain
compatibility surfaces were removed from the SegmentIndex API and
monitoring payloads.
[x] 82 Collapse split scheduling into a dedicated planner package (Risk: HIGH)
- End-game achieved: org.hestiastore.index.segmentindex.core.splitplanner
is now the control-plane package for split hint intake, periodic
reconciliation, candidate selection, and admission into the split worker
pool.
- End-game achieved: split execution stays separate from planning. The
planner owns "what should be scheduled"; split workers own "execute this
already admitted split".
- End-game achieved: planner is the only place allowed to submit split
work. Write paths, maintenance finalization, and timer ticks emit only
hints or rescan requests.
- End-game achieved: thread topology is reduced to one planner thread plus
one split worker pool, while route publish exclusivity, retry behavior,
and candidate deduplication remain explicit and test-covered.
[x] 82.1 Freeze target split-planner architecture and migration invariants (Risk: HIGH)
[x] 82.2 Add characterization tests for current split trigger and admission behavior (Risk: HIGH)
[x] 82.3 Introduce core.splitplanner package with behavior-preserving type moves (Risk: MEDIUM)
[x] 82.4 Extract explicit planner state and planner-facing API (Risk: MEDIUM)
[x] 82.5 Introduce a single split-task dispatch seam (Risk: HIGH)
[x] 82.6 Route all split triggers through planner requests only (Risk: HIGH)
[x] 82.7 Separate candidate discovery from split execution in code and tests (Risk: HIGH)
[x] 82.8 Replace dual policy executors with a single planner thread model (Risk: HIGH)
[x] 82.9 Simplify executor topology and runtime assembly (Risk: HIGH)
[x] 82.10 Remove obsolete policy vocabulary and close the migration (Risk: MEDIUM)
[x] 81 Replace technical segmentindex.core package vocabulary with domain ownership packages (Risk: HIGH)
[x] 81.1 Freeze the target package model and migration rules (Risk: HIGH)
[x] 81.2 Move root/session ownership into core.session (Risk: HIGH)
[x] 81.3 Collapse core.lifecycle into core.session (Risk: HIGH)
[x] 81.4 Move state types under core.session.state (Risk: MEDIUM)
[x] 81.5 Merge core.operation and core.split into core.routing (Risk: HIGH)
[x] 81.6 Move durability and storage integrity into core.storage (Risk: HIGH)
[x] 81.7 Dissolve core.runtime into session, routing, storage, and maintenance (Risk: HIGH)
[x] 81.8 Dissolve core.infrastructure into owning domains (Risk: MEDIUM)
[x] 81.9 Replace core.observability with segmentindex.monitoring (Risk: MEDIUM)
[x] 81.10 Remove core.internal and core.facade as final package names (Risk: MEDIUM)
[x] 81.11 Collapse leftover assembly and access vocabulary after package moves (Risk: HIGH)
[x] 81.12 Finish when segmentindex.core reads as domain boundaries, not framework plumbing (Risk: MEDIUM)