xrpld · NodeStore · online_delete
online_delete: measured write reductionToday every rotation copies the entire live state into a fresh NuDB file — write volume scales with total state. A generation ring copies only the cold nodes that the retiring generation still serves, so write volume scales with churn instead.
Today. SHAMapStoreImp::run() rotates by copying every live
node of the state map into a brand-new backend file, then dropping the old one. The copy is
O(total state) and it happens on every rotation, whether or not
anything changed — a node that has been cold for a year is rewritten every interval.
With a generation ring. Writes always land in the newest generation; reads
walk newest→oldest. When the ring exceeds its budget, the oldest generation is retired:
only nodes that are still live and still served by that generation get copied
forward, then the whole file is dropped. An evacuated node lands in the newest
generation, so it then has to age across the entire ring before it can be touched again —
a cold node is re-stored once per budget rotations instead of once per rotation.
| Cold nodes | Ring budget | Retirements | Re-stored | Per retirement | Today (full copy) | Reduction | Wall time |
|---|
The bench drives the real DatabaseRotatingImp rotation path —
advance(), beginRetire(), retireOldest() — against an
in-process backend ring, with the production evacuation pattern: a cold working set written
once, fresh churn every interval, and a fetch of every live node during each retire window
(what visitNodes(copyNode) does). The reported volume is
copyForwardCount(): nodes actually re-stored because the retiring generation was
the one serving them.
cd build
./xrpld --unittest=xrpl.app.SHAMapStoreBench
rotations × cold — because that is definitionally what copying every
live node on every rotation costs. The ring columns are measured.