Post-Patch Re-Capture
Windrose received a patch addressing the write
behavior described in the rest of this report. To gauge
what the developers actually changed, the same save
folder and engine log were re-captured after
approximately 36 minutes of co-op play on the patched
build (2026-04-30, 11:52 → 12:28 local). The world,
profile, map (GenlandiaMulty), and
co-op session shape were preserved so the comparison is
apples-to-apples; only the game build differs.
10.4.2, git sha
4c2fb586…, compile date
2026-04-17) is unchanged, and every
OPTIONS file produced by the patched build is
byte-identical to the pre-patch capture
(verified by md5sum). The 1 MB
shared WAL, 22 column families, and paranoid
verification flags described below all still
apply. What changed is the volume and shape of
the writes the game feeds into RocksDB.
What the data shows
| Signal | Pre-patch (4h 8min capture) | Post-patch (36 min capture) | Direction |
|---|---|---|---|
RocksDB OPTIONS contents |
md5 f35252ad… | md5 f35252ad… | identical |
| RocksDB binary (version / sha / compile date) | 10.4.2 / 4c2fb586 / 2026-04-17 | 10.4.2 / 4c2fb586 / 2026-04-17 | identical |
DAL queue DetectProblems firings |
3 (in 248 min) | 0 (in 36 min) | improved |
| "Slow task" / "Quite slow task" entries | 3 | 0 | improved |
| Worlds-DB file-number allocation rate | ~8.6 / sec | ~6.8 / sec (14,831 in 36.5 min) | ~21% lower |
| Backup retention window | 5 | 12 | 2.4× wider |
| WAL size at DB open (RocksDB info LOG) | 0 bytes | 3,486,703 bytes (3.3 MB) | persists across opens |
LogNet: Warning rate (co-op churn proxy) |
~0.88 / min | ~0.30 / min | ~65% lower |
What the changes mean
The clearest signal is the disappearance of
R5BLDalAsyncQueue::DetectProblems warnings.
In the pre-patch capture, the Players-DB queue grew
from 480 to 2,330 items over 75 minutes and fired
three latency alerts (one tagged
Warning, with a 690 ms commit). In the
post-patch capture, no DetectProblems
entry fires at all. The async write queue is keeping
up — work isn't accumulating faster than the worker
thread can drain it, which was the structural problem
the original report flagged for shared-host
operators.
The bumped backup window
(Existing backups num: 5 →
Existing backups num: 12) is the only
plainly intentional, easy-to-attribute change visible
in the artifacts. The retention bump is a
durability hedge layered on top of whatever the
write-side change was: more rolling restore points
for the same per-launch backup machinery
(see § 06 · Backup Procedure).
The persistent 3.3 MB WAL at DB open is the most
interesting indirect evidence. The pre-patch capture
showed the WAL drained to zero bytes at every open
(sessions ended with the memtable flushed and the WAL
truncated). The post-patch capture's RocksDB info LOG
records a 3.3 MB WAL still live at DB-open — meaning
pending writes were carried across sessions in the
log rather than flushed to SSTs at shutdown. Combined
with the dropped allocation rate and the unchanged
1 MB max_total_wal_size, the most
plausible reading is that the game is now batching
writes more aggressively at the application layer
(likely WriteBatch coalescing, redundant-
write elimination, or fewer per-tick saves), so each
physical commit carries more logical state and the
flush-cascade trigger fires less often in absolute
terms.
max_total_wal_size,
bytes_per_sync,
max_background_jobs,
level0_file_num_compaction_trigger)
moved.
Duty cycle and per-hour estimates
The post-patch SST timestamps reveal a sharply bursty write pattern that wasn't visible in the pre-patch capture. Surviving SSTs in the 36.5-min session cluster into about five active windows totaling roughly seven minutes — a ~19% duty cycle during mixed co-op gameplay, with long quiet stretches in between. The longest active window (12:12 → 12:28) coincides with a sailing segment in the captured run and sustains a file-number allocation rate of ~11.4/sec — higher than the pre-patch session-average of 8.6/sec, but applied to a much smaller fraction of wall time.
Translating to physical write volume needs the pre-patch baseline that the community video captured at the OS level (15–30 MB/s), since neither capture contains direct per-second byte counts. Combining peak burst rate with observed duty cycle:
| Scenario | Peak burst | Duty cycle | Hourly estimate |
|---|---|---|---|
| Pre-patch, mixed | ~20 MB/s | ~30–50% | ~22–36 GB/hr |
| Pre-patch, sailing | ~30 MB/s flat | near 100% | ~108 GB/hr |
| Post-patch, mixed | ~20 MB/s | ~19% (measured) | ~14 GB/hr |
| Post-patch, sailing | not OS-captured | partial | ~30–40 GB/hr (est.) |
The post-patch mixed-gameplay duty cycle is observed directly in this capture's SST timestamps. The sailing estimate carries the largest uncertainty — peak MB/s during a post-patch sailing burst was not captured at the OS level, so the entry assumes a similar peak rate to pre-patch and scales by the fraction of wall time the active windows occupy. A targeted procmon trace during a known sailing segment is the cleanest way to settle it.
The largest pre-to-post improvement is probably not the peak burst rate at all — it's that the queue no longer backs up, so the duty cycle stops creeping upward over a long session. A 4-hour pre-patch session was effectively running its tail at higher and higher utilization; an equivalent post-patch session should stay in the bursty regime throughout.
For practical SSD-endurance reasoning: at the post-patch mixed-gameplay number (~14 GB/hr), eight hours of daily play comes out to ~41 TB/year — well inside the warranty TBW of even low-end QLC drives (typically 100–300 TBW per TB of capacity). Sustained sailing is the case that still warrants attention: eight hours a day at the estimated post-patch rate lands near 90–115 TB/year, which is the same order of magnitude as a low-end QLC drive's spec endurance. Typical play patterns are mixed, not sailing-only, so the warranty-window concern is largely confined to dedicated long-distance sailors.
Why an application-side fix
The engine-log paths show the RocksDB integration
structured as an Unreal plugin
(R5BusinessLogicCore) with a deliberate
two-layer split: a generic
R5DataAbstractionLayer consumed by
gameplay code, and a backend-specific
R5RocksDAL implementation behind it.
Gameplay code only sees the abstract DAL; the plugin
owns the RocksDB option set. That architecture makes
several cost asymmetries visible, all of which point
toward the patch the developers shipped:
- Fixes the cause, not the symptom. If profiling identified redundant or per-tick writes, eliminating them at the source reduces the load that triggers amplification rather than tuning the absorber to handle more of it.
-
Preserves the durability contract.
Raising
max_total_wal_sizefrom 1 MB to 64 MB widens the worst-case crash-recovery replay from milliseconds to a player-visible startup delay. The 1 MB cap was likely chosen on purpose; touching it would change a player-facing behavior to fix a player-invisible one. - Fewer things to break. An application-side change touches gameplay code with the gameplay team's existing tests. A plugin tuning change applies to all three databases (Players, Accounts, Worlds) at once — different access patterns, one option set — and triggers revalidation across every DAL consumer.
- Existing saves on disk become test cases. Re-tuning options changes compaction behavior over already-built L0 / L1 / L2 layouts in player saves. Application batching leaves the on-disk state unchanged and only affects writes from this point forward.
- Code change was unavoidable either way. Both paths require code work; the application path simply has the narrower risk surface and ships under a normal feature patch rather than a storage-tier release.
Read this way, the bumped backup retention (5 → 12) is consistent: a cheap durability hedge that fits inside the same patch without touching RocksDB tuning. The four storage-side dials listed in § 07 remain available for a later pass, and would compound on top of the application-side reduction without altering the durability story.
Caveats on the comparison
- Sample sizes differ: 4h 8min pre-patch versus 36 min post-patch. Per-minute rates are the only defensible comparisons; absolute counts (e.g., "3 slow tasks vs. 0") need to be read with that in mind. A longer post-patch session would tighten the bound on whether the queue stays drained across hour-plus sailing or building bursts.
-
Both captures are co-op on
GenlandiaMulty, so co-op replication overhead is present in both — but theLogNet: Warningrate is ~65% lower per minute post-patch, suggesting some net replication churn dropped as well. The Worlds-DB allocator rate change is real even after that deduction, since DAL traffic is locally generated. -
The post-patch RocksDB info LOG was, again, rotated
out of the surviving
keep_log_file_num=3buffer by the launch backup cycle, so per-event flush and compaction byte counts are still not directly observable. The capture path described in § 08 would close that gap.
The rest of this report is preserved as-written: it describes the pre-patch state, which is the baseline the post-patch numbers compare against. Where the text below talks about "the game" or "the live capture," read that as the pre-patch behavior unless explicitly noted.
Executive Summary
A community video by Pixel Operative
flagged Windrose as writing 15–30 MB/s to the SSD
during normal gameplay, with sailing producing a
near-flat sustained 30 MB/s. The claim was based on Task
Manager disk activity graphs from a single client. This
report reaches the same underlying observation through a
different path: direct analysis of the RocksDB save folder
plus the Unreal Engine 5 client log
(R5.log), which captures the game's own
internal instrumentation.
The evidence is consistent with a persistence layer tuned for maximum durability at the cost of write volume, not a corruption risk. The game runs multiple RocksDB instances concurrently, each containing many column families behind a shared 1 MB write-ahead log. That combination forces frequent memtable flushes across column families, amplifying a modest stream of logical writes into a much larger stream of physical disk activity. Whether the tuning is a deliberate design choice or an unintentionally conservative default cannot be determined from this data alone — only the outcome is observable.
OPTIONS file alone
does not fully determine. The observable trade-off
is sustained background disk traffic that strains
shared server hosts, may shorten endurance on
hot-loop SSD hardware, and inflates perceived I/O
relative to logical gameplay state changes.
Analysis inputs
-
Live RocksDB save directory
(
Worlds/<world-id-a>…), 9 days of play, 66 live SST files plus MANIFEST, OPTIONS, and three rotatedLOGfiles. -
Matching UE5 client log
R5.logcovering a single 4h 8min session (2026-04-22 22:17 → 2026-04-23 02:25 local). - Session window is fully contained in the save's latest SST timestamp range, allowing direct correlation between log events and file-system artifacts.
Persistence Architecture
The game does not run a single save database. From the
R5LogBLDalAQ category in the engine log,
Windrose opens at least three concurrent RocksDB
instances, each behind its own async write queue and
worker thread.
| Instance | Path | Worker thread |
|---|---|---|
| Players | 0.10.0/Players/<player-id>… | 43252 → 2652 → 44492 |
| Accounts | 0.10.0/Accounts/<account-id>… | 28396 |
| Worlds | 0.10.0/Worlds/<world-id-a>… | (per-world worker) |
Each database runs through the same abstraction stack:
R5BLDalAsyncQueue enqueues work items, and
R5BLRocksAsyncQueue drains them into the
underlying RocksDB. The queues are independent, so disk
traffic observed in a single save folder represents only
one of multiple concurrent I/O sources. A player with
multiple islands adds one more Worlds instance per
island; the profile in this capture has two
(<world-id-a>… and <world-id-b>…).
instances
embedded in game
during active play
in 9 days (Worlds DB)
RocksDB file numbers are a reasonable activity proxy rather than an exact flush/compaction count — the same allocator is also used for WAL files, MANIFEST rotations, and other internal artifacts. Even taken as a proxy, the numbers are informative: the Worlds DB alone allocated roughly 1,065,000 file numbers over the 9-day span, while only 66 SSTs remain on disk. That ratio implies the large majority of emitted files have already been rewritten and deleted by compaction. During the measured 136-minute active session the allocation rate stabilized at roughly 8.6 events per second for the Worlds DB instance.
The 1 MB WAL Cap
The single most consequential tuning decision is the
maximum write-ahead log size. Every one of the
instances above is configured identically, via an
OPTIONS file written by RocksDB at DB
creation.
DBOptions (from OPTIONS-982899)
max_total_wal_size = 1048576 // 1 MB bytes_per_sync = 0 // no OS-level pacing wal_bytes_per_sync = 0 max_background_jobs = 2 // flush + compaction combined use_direct_io_for_flush_and_compaction = false use_fsync = false // fdatasync instead wal_recovery_mode = kPointInTimeRecovery paranoid_checks = true verify_sst_unique_id_in_manifest = true compaction_verify_record_count = true flush_verify_memtable_count = true ttl = 2592000 // 30 days rocksdb_version = 10.4.2
A 1 MB total WAL budget is extreme by any reasonable
baseline. Typical RocksDB deployments size the WAL
between 64 MB and 1 GB. Per the RocksDB documentation,
max_total_wal_size only takes effect when
the DB has more than one column family — otherwise WAL
sizing is dictated by write_buffer_size
alone. The Worlds DB in this capture has
22 column families, so the option is
empirically active:
default R5LargeObjects R5BLIsland R5BLBuilding R5BLIslandChest R5BLCrop R5BLActor_DamageableFoliage R5BLActor_DialogueActor R5BLActor_Drop R5BLActor_ExplodingBarrel R5BLDynamicGenericActor R5BLStaticGenericActor R5BLIslandShipDock R5BLActor_PickupResource R5BLPlayerInWorld R5BLActor_DigNode R5BLActor_DigVolume R5BLActor_MineralNode R5BLResourceSpawnPoint R5BLGameplaySpawner R5BLActorScenarioSave R5BLActor_BuildingBlock
Every column family has its own memtable and its own
write_buffer_size of 64 MB, but they share
a single WAL capped at 1 MB. When accumulated writes
across any column families push the WAL past
the cap, RocksDB force-flushes the memtables of the
column families whose data is present in the oldest
live WAL. With 22 column families sharing a 1 MB
budget, this condition is reached frequently, and each
forced flush can emit multiple L0 SSTs — one per
flushed column family.
The L0 outputs then feed the compaction pipeline. Leveled compaction in RocksDB typically shows a write-amplification factor in the range of 20–30× user data in published studies, which aligns with the order-of-magnitude gap between plausible in-game logical write rates and the 15–30 MB/s physical rates the community video captured.
Flush cascade
At a modest 1 MB/s of logical writes, this configuration forces approximately one flush per second. The flush emits an L0 SST that must eventually be merged into L1, then L2, then L3 — each level rewriting every byte it touches. With the LSM-tree's standard 10× per-level amplification, a 1 MB/s logical stream produces tens of MB/s of physical writes, which matches the disk activity the community video captured.
bytes_per_sync throttling, the engine
cannot batch writes into fewer, larger flushes. Each
MB of game state produces its own flush, its own SST,
and its own downstream compaction work — per
database instance.
Several other flags reinforce the durability bias:
paranoid_checks,
verify_sst_unique_id_in_manifest,
compaction_verify_record_count, and
flush_verify_memtable_count are all on. The
WAL recovery mode is
kPointInTimeRecovery, the strictest option.
The configuration is internally consistent with a
single goal: minimize the window of possible data loss,
at any disk cost.
Write Amplification on Disk
Write amplification is usually inferred from RocksDB's internal statistics. In this save, those statistics are not directly available (see § 06 · Backup Procedure for why), so the argument rests on three indirect indicators: the gap between file numbers allocated and files still live on disk, the size of the MANIFEST relative to the live data, and the distribution of SST sizes across compaction levels.
Live vs. allocated
currently on disk
payload
over 9 days
(compaction history)
The ratio of allocated-to-surviving file numbers exceeds 16,000:1. Even treating file numbers as a proxy rather than an exact flush/compaction count (see § 02), the gap is large enough to imply that the large majority of emitted files have been superseded by compaction. The MANIFEST itself, which records every file edit, has grown to 5.9 MB — unusually large for a live database holding fewer than 20 MB of actual data.
The Write Queue During Play
The RocksDB LOG files on disk capture only
DB open/shutdown banners (see
§ 06 · Backup Procedure), but the
UE5 client log preserves the DAL layer's view of the
same workload. The
R5BLDalAsyncQueue::DetectProblems handler
fires whenever a task exceeds its latency threshold.
Write queue growth (Players DB worker, single session)
| Timestamp | Elapsed | Queued items | Total task # | Avg rate |
|---|---|---|---|---|
| 02:53:05 | 35 min | 480 | 1,456 | ~42 / min |
| 03:37:53 | 80 min | 1,522 | 4,615 | ~70 / min |
| 04:07:56 | 110 min | 2,330 | 7,039 | ~81 / min |
Two things stand out. First, the rate of committed tasks climbs across the session — from 42/min to 81/min — so activity accelerates rather than stabilizing. Second, the queue depth nearly quintuples (480 → 2,330) over the same interval. The write pipeline is accepting work faster than it can drain, which is the structural condition that produces sustained background I/O long after an individual gameplay event has concluded.
Slow-commit detections in the same session
02:53:05 R5BLDalAQ: Quite slow task. Task was finished in 320 ms. commitT 03:37:53 R5BLDalAQ: Slow task. Task was finished in 690 ms. commitT (Warning) 04:07:56 R5BLDalAQ: Quite slow task. Task was finished in 292 ms. commitT
Commit latencies of 290–690 ms on a local SSD indicate
the RocksDB instance is periodically stalling — likely
during L0-to-L1 compaction bursts when
max_background_jobs=2 leaves no headroom
for concurrent flush and compaction. The devs have
built threshold-based detection for exactly this, and
it fired three times in four hours during the
captured session.
Co-op context caveat
The R5.log capture comes from a co-op session, not a
pure solo session. Log evidence:
R5LogIceProtocol creating STUN/TURN P2P
connections at session start, the co-op map
GenlandiaMulty loaded,
LogNet: Welcomed by server confirming a
peer-to-peer join, and 218 LogNet: Warning
entries over four hours showing co-op replication
churn (repeated
No owning connection for actor warnings
on ship and player-state actors). There was one
P2P handshake at session start and no additional
full-peer joins visible in the captured window.
Two implications for the numbers above: (1) the initial join burst is inside the first 35-minute sample, so the 35 → 110 min growth from 42 to 81 commits/min is not join-driven — it reflects steady-state co-op activity; but (2) absolute rates are co-op-inflated relative to a true solo session. A solo capture taken for comparison would let us separate "co-op replication overhead" from "base game persistence." That capture was not taken for this report.
Memory pressure concurrent with the I/O
In the first ten minutes of gameplay, the in-game
R5ResourcesMemoryLeakDetector fired five
times, flagging average memory growth rates above the
5 MB/s threshold:
02:25:15 growth 13.33 MB/s 02:32:26 growth 6.37 MB/s 02:33:27 growth 13.09 MB/s 02:35:21 growth 5.03 MB/s 02:36:22 growth 13.19 MB/s
Most of this is UE5 asset streaming on the
GenlandiaMulty map, not the RocksDB
queue. But the coexistence is worth noting:
unbounded in-memory growth plus a growing DAL queue is
the pattern that eventually produces the sustained
30 MB/s disk rate observed externally — the game
continuously generates more state to persist than the
tuned-for-durability write pipeline can drain in a
single pass.
Backup Procedure
The rotated RocksDB LOG files in the save
folder have misled at least one observer (including this
one, on first pass) into suspecting frequent DB
reopens during gameplay. The client log clarifies the
actual behavior.
R5LogCoopProxy at session start
02:17:17.518 UR5CoopProxy::RollBackups Existing backups num: 5 02:17:17.518 UR5CoopProxyClient::MakeBackup /_Backups/20260422_221717 02:17:17.518 MakeBackup R5BLIsland 02:17:17.584 Backup record R5BLIsland[<world-id-b>…] 02:17:17.585 MakeBackup R5BLAccount 02:17:17.593 MakeAccountDescriptionBackup 02:17:17.594 Backup record R5BLPlayer[<player-id>…] 02:17:17.602 Backup successfully created
- Backups run on each game launch, not on a wall-clock timer. The game keeps a rolling window of 5 previous backups.
-
Each backup iterates every root collection
(
R5BLIsland,R5BLAccount,R5BLPlayer) and opens each underlying RocksDB briefly. This is what creates the rapid open/shutdown cycles visible in the rotatedLOG.old.*files — three rotations in 325 ms. - A complete backup finishes in ~84 ms for the profile sampled. The operation is cheap; the side-effect on the RocksDB info log is what makes post-hoc analysis of the info log ineffective.
The evidence points to aggressive durability-oriented RocksDB tuning rather than corruption or a runaway write loop. The 1 MB shared WAL against 22 column families, paranoid verification flags, strict point-in-time recovery mode, and concurrent per-collection databases are all consistent with keeping the crash-recovery replay window small. Whether that tuning was a deliberate product choice or an accidental legacy default cannot be settled without developer comment; the observable outcome is the same either way.
What this means for players
- No corruption risk. The configuration is internally coherent with durability-first intent, and the video's own creator reports 60 hours of corruption-free play.
- SSD endurance is the real concern. Consumer TLC SSDs are rated for hundreds of TBW; sustained 15–30 MB/s during gameplay is well within normal consumer-drive budgets over typical ownership periods, but is meaningful on QLC drives or older drives near end of life.
- Shared hosting will struggle. The queue-growth pattern means cheap VPS and shared dedicated hosts with contended I/O are genuinely unsuitable for hosting this game. Self-hosted or reputable dedicated I/O are the viable options.
Tuning dials the devs could turn
-
max_total_wal_size1 MB → 64 MB would reduce flush frequency by ~64× with only a 64 MB worst-case recovery replay. -
bytes_per_sync0 → 1 MB would pace writes to the OS instead of bursting, smoothing disk utilization without affecting durability. -
max_background_jobs2 → 4 would eliminate most commit-latency stalls by letting flush and compaction proceed concurrently. -
level0_file_num_compaction_triggerraised from 4 would absorb more flushes before kicking off L0→L1 compaction work.
None of these changes require code work — only tuning. Each reduces disk pressure without weakening the durability model in any game-relevant way. The worst-case exposure after a 64 MB WAL switch is still measured in milliseconds of replayed writes.
Can players tune this themselves?
Likely no, based on the evidence available. The
OPTIONS-<N> files visible in the
save folder are written by RocksDB on
every DB open, not read; editing them in place
does not persist because the next open overwrites
with the values the game supplies in code. The
game's external Config directory on disk is
effectively empty — the R5 log shows
pakchunk3-release-steam-game-coop.pak
mounted at R5/Config/, so any INI
configuration ships inside the pak rather than as
loose files, and pak-packed config is not
user-editable without repack tooling.
A definitive test (not run for this report) takes
about a minute: edit
max_total_wal_size in the current
OPTIONS file to a larger value (for example
67108864 for 64 MB), launch the game
briefly and exit cleanly, then inspect the newly
written OPTIONS-<higher-number>
file. If the edited value persists, the game
respects external OPTIONS-file loading — rare but
possible. If it reverts to
1048576, the configuration is set
in code and user-side tuning is not available
without a mod. Harmless either way: RocksDB
writes a fresh OPTIONS file on every open, so the
experiment does not mutate live state.
Methodology note
This analysis was performed against a live save
snapshot plus a matching engine log from a single
session. The RocksDB info LOG files
on disk capture only the shutdown-time open/close
cycles — the game reopens the Players DB during
shutdown (confirmed by
R5BLRocksAsyncQueue close/reopen
events in the R5 log), rotating the gameplay
session's LOG out of the
keep_log_file_num = 3 buffer before
the folder can be copied. Both surviving
LOG.old.* rotation timestamps in this
capture land within a 325 ms window at session
shutdown, confirming the effect. There is no
copy-after-exit window that would recover the
gameplay LOG.
Per-event byte counts and exact compaction-level statistics therefore require live capture during gameplay rather than post-hoc file copying. Concrete capture paths, plus crash-recovery testing to verify the durability window, are outlined in § 08 · Further Investigation.
Further Investigation
This report rests on post-hoc file analysis plus one client log. Two directions would produce materially stronger evidence: live runtime tracing, to confirm the write-amplification mechanism event by event, and crash-recovery testing, to measure the durability window the tuning is designed to protect. Both are feasible on a consumer PC without game modifications.
Real-time I/O tracing
The missing signal is which bytes go to which file, when, and why. Three capture paths, in increasing effort:
-
Sidecar file watcher — PowerShell
FileSystemWatcheror Pythonwatchdog, logging.sstand.logsize deltas once per second. Lowest friction; confirms the 15–30 MB/s order of magnitude from the save folder directly and lets you correlate bursts with in-game events by timestamp. - Process Monitor (procmon) or ETW trace on the RocksDB save folder, filtered by game process and path. Produces per-write timestamps, sizes, and target filenames — enough to rebuild a full flush/compaction timeline from file-system activity alone.
-
RocksDB info LOG capture, if the game
honors external OPTIONS edits. Raising
keep_log_file_numpast 3 would preserve the gameplay-session info LOG across the shutdown backup cycle that currently rotates it out (see § 06). That log contains flush and compaction events with byte counts directly — the authoritative source. The OPTIONS-persistence test outlined in the Verdict settles whether this path is open.
A fourth, offline option:
sst_dump --output=compressed on surviving
SSTs surfaces key ranges and sequence numbers, which
settles whether the same-size files in
Appendix C are cross-level
rewrites of the same keys or independent outputs
targeting consistent block sizes.
Crash and sync behavior
kPointInTimeRecovery combined with
use_fsync=false defines a specific
durability model: durable against a process crash
while the OS continues running, but dependent on OS
page cache and disk cache behavior for power-loss
cases. The actual loss window is observable by
inducing failures and measuring what's lost.
- Process-crash test. During active gameplay — sailing, building, combat — End Task the game process from Task Manager. Relaunch and compare: how much recent progress is lost? What event types (inventory changes, world edits, player position) survive, and which don't?
-
Power-loss test. More aggressive:
hold the power button during gameplay. Tests
whether the OS page cache and disk cache preserve
pending writes. This is the case that reveals
whether
fdatasync-without-fsync is sufficient on the target hardware. - Use a known-state marker. Before each crash, set up something distinctive — build a specific structure, craft a unique item, park the ship at a precise location. The delta after recovery is only unambiguous with a reference point.
Ten minutes of setup plus a handful of crashes is
enough to bound the loss window empirically and verify
that kPointInTimeRecovery behaves as
documented in practice.
Baselines that would sharpen this report
- Solo-session capture. The R5.log used here is from a co-op session. A matching solo capture of similar length and activity would isolate co-op replication overhead from the base persistence cost.
- Server-side trace. All claims here are client-side. The same procmon or file-watcher capture on a rented dedicated server — ideally a shared VPS known to struggle — would move the "shared I/O hosts are unsuitable" claim from inferred to measured.
- Multi-island profile. This capture has two Worlds instances. A 4+ island profile would reveal whether per-world write rate scales linearly or whether shared compaction budgets create contention.
Evidence Appendix
The claims in this report rest on four artifact classes:
the live RocksDB save folder, the embedded
OPTIONS and MANIFEST files,
the rotated RocksDB info LOG files, and
the Unreal Engine 5 R5.log client log for
the correlated session. This appendix reproduces the
specific command outputs and excerpts the narrative
sections rely on.
A · RocksDB configuration (OPTIONS excerpt)
Values drawn verbatim from
OPTIONS-982899, the current OPTIONS file
for the Worlds DB.
[Version] rocksdb_version = 10.4.2 [DBOptions] max_total_wal_size = 1048576 // 1 MB bytes_per_sync = 0 wal_bytes_per_sync = 0 max_background_jobs = 2 max_background_compactions = -1 max_background_flushes = -1 use_direct_io_for_flush_and_compaction = false use_fsync = false wal_recovery_mode = kPointInTimeRecovery wal_compression = kNoCompression paranoid_checks = true verify_sst_unique_id_in_manifest = true compaction_verify_record_count = true flush_verify_memtable_count = true allow_concurrent_memtable_write = true [CFOptions "default"] (representative; same values repeat across all 22 CFs) write_buffer_size = 67108864 // 64 MB per CF max_write_buffer_number = 2 min_write_buffer_number_to_merge = 1 level0_file_num_compaction_trigger = 4 max_bytes_for_level_base = 268435456 // 256 MB max_bytes_for_level_multiplier = 10 ttl = 2592000 // 30 days soft_pending_compaction_bytes_limit = 68719476736 // 64 GB hard_pending_compaction_bytes_limit = 274877906944 // 256 GB
B · Column families (Worlds DB)
22 column families are defined in the OPTIONS file, one
[CFOptions "<name>"] section each.
This count satisfies RocksDB's documented requirement
for max_total_wal_size to be an effective
flush trigger.
default R5LargeObjects R5BLIsland R5BLBuilding R5BLIslandChest R5BLCrop R5BLActor_DamageableFoliage R5BLActor_DialogueActor R5BLActor_Drop R5BLActor_ExplodingBarrel R5BLDynamicGenericActor R5BLStaticGenericActor R5BLIslandShipDock R5BLActor_PickupResource R5BLPlayerInWorld R5BLActor_DigNode R5BLActor_DigVolume R5BLActor_MineralNode R5BLResourceSpawnPoint R5BLGameplaySpawner R5BLActorScenarioSave R5BLActor_BuildingBlock
C · SHA-256 verification of same-size SSTs
Three groups of surviving SSTs share identical byte sizes within the group. SHA-256 hashes are distinct within every group — same size, different content. Reported in full for reproducibility.
Group 1 — 1,661,300 bytes 1b3f0a014237442eb7ee6ae1d62958d2b77eb8104afec17d783f74f633cd8185 1086472.sst 5b89fd401530c2e00ded09bc9c7909e2e60f32f0513ce181a5d65817fc4adef1 1086495.sst ea1923ca6def5d0b2ebc93705cd531a0074a64a6aa36b441a91961fcf34272e7 1086518.sst Group 2 — 18,070 bytes 641ba328d51247e6b3b3ebce10cec507f74671c73c71e01777b2d8d9a97226fe 1086387.sst f6f49fe6251fcf8ab74df5a4ba74e1ae575f712c3c049ef19d998f762054bd08 1086483.sst 17227ef2c26b4aa52cd93cc0e9717d0f6d309c67642444eafb6235a641a4724f 1086527.sst Group 3 — 1,218 bytes b04c1064cd1a08664d2cb9f7d881c4c12b1d44d8d5fa2d8fee6236a4cfbb01e5 020909.sst f2320ac90378bfffeeaa838453e8d6de16311f3fb2d5ec791a030919e6fb37fd 300578.sst b8682c3251cd61689f68ba9663a8df8eb965d3fdcb3b049582ced40aa1f974a0 441321.sst 343c987639f3d1678acccab6c719a04440be97f03eae493d0dfc2b607fb961c6 1077894.sst 3a5206d6c1f7b30e4915abd42f3d6a48e5bc11be231fc25672bf1e1f8a38abf4 1078215.sst
The non-matching hashes rule out the initial hypothesis
that these were the same payload rewritten across
compaction levels. A plausible alternative is that
compaction is targeting consistent output sizes per
level — which is consistent with RocksDB's default
target-file-size behavior — and is unrelated to
repeated rewrites of the same key range. Settling the
question would require either sst_dump
output or key-range / sequence-number overlap analysis
from the MANIFEST.
D · File-system summary of the Worlds DB
Live SSTs on disk: 66
Total live SST bytes: 19,470,508 (18.57 MB)
MANIFEST size: 5,945,606 (5.67 MB)
File-number range: 020,861 → 1,086,528
File-number span: 1,065,667
SST timestamps (active window): 2026-04-23 00:09 → 02:25 local
Active-session allocations: 70,106 file numbers in 136 min
≈ 515 / min ≈ 8.6 / sec
E · DAL async-queue growth (Players DB, single session)
Extracted from R5LogBLDalAQ::DetectProblems
entries. Format in the log is
[s: queued: totalTaskID: taskType].
elapsed queued total-task# latency type ─────── ────── ─────────── ─────── ───── 35 min 480 1,456 320 ms commitT 80 min 1,522 4,615 690 ms commitT (Warning) 110 min 2,330 7,039 292 ms commitT Rate between samples: 0 → 35 min: 1,456 tasks in 35 min = ~42 / min 35 → 80 min: 3,159 tasks in 45 min = ~70 / min 80 → 110 min: 2,424 tasks in 30 min = ~81 / min
F · Memory-leak detector alerts (first 10 min of gameplay)
02:25:15 R5ResourcesMemoryLeakDetector growth 13.33 MB/s (threshold 5.00) 02:32:26 R5ResourcesMemoryLeakDetector growth 6.37 MB/s 02:33:27 R5ResourcesMemoryLeakDetector growth 13.09 MB/s 02:35:21 R5ResourcesMemoryLeakDetector growth 5.03 MB/s 02:36:22 R5ResourcesMemoryLeakDetector growth 13.19 MB/s World: Client -1 (/Game/Maps/GYM/Genlandia/GenlandiaMulty.GenlandiaMulty)
G · What this appendix does not contain
-
Per-event compaction byte counts. The RocksDB info
LOGrotated out during the launch backup procedure, leaving only DB-open/shutdown banners. A clean session exit followed by an immediate save-folder copy is the capture path for that data. -
Key-level content comparison of the same-size SSTs.
sst_dump --output=compressedwould surface key ranges and sequence numbers; it was not run here. -
A solo-session baseline. The R5.log capture is from
a co-op session (client joined a remote P2P host
at 02:23 into
GenlandiaMulty). Rates are therefore co-op-inflated relative to a true solo session, and the delta cannot be quantified without a matching solo capture. - Server-side traces. All data in this report is from a client installation; shared-host behavior on rented dedicated servers is inferred, not measured.