Repository navigation
perf: skip unchanged estate receipt writes and extra directory flushes - #47
Conversation
The hourly table-estate reconcile re-settles every decided estate. A retained (non-character) estate rewrote its unchanged receipt each time, and every DurableFiles write flushed each ancestor directory up to the filesystem root. On Main that was a 0.7 s main-thread pause per hour, growing as decided estates accumulate. - DurableFiles.write flushes the target's parent, plus the parents of directories this write created, instead of every ancestor. - DurableFiles.writeIfChanged skips the write when the file already holds the same bytes; the retained-receipt path uses it. Outcomes are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Summary
Merge Risk: ⚪ Minimal · up to
|
Sol review: a folder created by mkdirs elsewhere, or by a write whose ancestor flush failed, still needs its ancestors flushed. Track directories (by file key) whose whole chain has been flushed; flush the chain on the first write there and again after any failure, and only the parent afterwards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sol review round 2: file keys can be reused after a folder is deleted, so key the flushed-folder cache by path and forget a folder (and everything under it) when a durable write or Games' own mkdirs creates it, instead of trusting the key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@coderabbitai review |
✅ Action performedReview finished.
|
Summary
Stops the hourly table-estate pass from rewriting estate receipts that haven't changed.
TableEstate.reconcileruns every 72000 ticks (and on estate/revive events) and settles every decided estate again. For a retained estate (no character recipient)settlerewrote the receipt withDurableFiles.writeevery time, even though the content was identical. Each write made a temp file, forced it to disk, moved it into place, and then forced every folder up to the filesystem root to disk.On Main, all 13 receipts in
plugins/Games/estates/tablesget new timestamps every hour. In a spark profile (2026-10-22 21:13 UTC) this cost 0.7 s on the server thread in one go (TableEstate.reconcile→DurableFiles.write/sync). Decided estates only accumulate, so the hitch would keep growing, like Magic's 20–30 s freezes fixed in Magic 0.12.0.Changes:
DurableFiles.writeIfChangedpublishes only when the file doesn't already hold exactly these bytes. When the content is identical it still flushes the parent folder entry, so a receipt moved into place by an earlier write whose folder flush failed is still made durable. The retained-estate path uses it.DurableFiles.writeflushes the parent folder, plus only the folders this write created. It no longer flushes every ancestor up to/. The temp-file + force + atomic-move guarantee is unchanged.Outcomes reported to Estates are unchanged. Estates that are already finished are still settled each hour: that pass is how "Completed table reappeared at the testator" and history conflicts are detected. It just no longer writes anything.
Testing
TableEstateTest: newrepeatedRetainedSettlementKeepsItsUnchangedReceiptFilesettles twice and checks the outcome is equal and the receipt's bytes and last-modified time are unchanged.DurableFilesTest(new): creating missing folders, no.pending-leftovers,writeIfChangedskips only identical bytes, delete.TableEstateTest+DurableFilesTest: 26/26 pass locally.TableManagerPersistenceTest/TableManagerLifecycleTest. They're identical onmain: Windows refuses to force a directory to disk. Linux CI is the reference.Part of the 2026-10-22 ping/lag investigation, together with VehicleFramework and RPCharacters PRs.
🤖 Generated with Claude Code