feat: Implement zstd checksums and other chunk corruption handling methods - #500
feat: Implement zstd checksums and other chunk corruption handling methods#500Saul5662 wants to merge 10 commits into
Conversation
|
Is there any way you can simulate one of these corruption states in game? |
|
Tests implemented in this PR should cover corruption handling. I don't exactly know how I would test corruption in-game? Let me experiment with that. Maybe just hex edit the zstd and see what happens. |
|
Created a bash script to test all this. Running through it. |
|
Forgot to add. All the tests I ran passed and confirmed chunks regenerate when they are supposed to and the server recovers from header corruption without losing data. |
df76bc4 to
41c3da1
Compare
|
Updated PR description to reflect the new fix within this PR. |
3dad9d9 to
268720c
Compare
kdcokenny
left a comment
There was a problem hiding this comment.
What happens if disk space runs out after a region has already been opened and also, should one invalid chunk-table entry cause the entire region to regenerate?
|
Ah I didnt catch these that is my fault for not testing these cases properly. Addressing these issues right now. Give me a sec. |
no worries at all. this is a complex area with a ton of edge cases haha |
|
I also noticed an issue where region writes dont fsync only |
not intentional, and i think you should fix it in this pr. ideally use vanilla’s sync-chunk-writes behavior, including writing chunk data durably before updating the header. Not sure if this would take a hit on perf tho. testing would be needed |
Gotcha. Running some benchmarks to test if this is a massive performance hit and will start implementing it. EDIT: Sync chunk writes are 1478 µs per chunk without batching on my NVMe so thats a no go. What I propose is batched saves. Basically we write all the payloads in the batch, sync, write dirty headers, sync. Per chunk it goes from 8.4 µs to 19.8 µs. Which IS slower than our current implementation |
|
Just adding a comment to say first comment's issues should be fixed. |
kdcokenny
left a comment
There was a problem hiding this comment.
I'm wondering what would happen if two chunk-table entries overlap, but the lower-index entry is the corrupt one? It seems to me that the current repair would keep that entry and delete the potentially valid one, no?
Type of change
Description
This PR implements zstd checksums for chunk corruption detection which passes corrupted chunks to regenerator along with other corruption related features which include:
Fullchunks causing further data loss.FORMAT_VERSION23 to reflect the structure change. This will cause older versioned worlds to NOT load.ErrorKind:InvalidDataand now useErrorKind:Unsupportedto prevent backup promotion from treating a version mismatch as invalid data.zstd::encode_allcalls.There are a lot of tests added with this PR but since this is quite critical as its persistent data I felt they were justified. Please review and change these at will.
Fix infinite chunk-load retry loop
This PR also fixes a critical issue where if any of the following happen it triggers an infinite loop pinning a CPU core and flooding log output:
The cause is an error generated from
storage.acquire_chunkwhich flows out of the spawned task and drops_status_claim. The claim'sDropis explicitly there to roll back abandoned work. Rolling back resetsstarted_workto its parent status so the chunk looks empty. The scheduler sees it, re-drives it, andopen_regionthen fails identically and the cycle repeats.Storage errors are now triaged so callers only ever see retryable ones:
StorageFull,QuotaExceeded,ReadOnlyFilesystem,PermissionDenied) nothing can be persisted again, so the server stops rather than silently discarding everything players do from that point on.InvalidData,UnexpectedEof) the region file is moved to.srg.corrupt.bakand rebuilt, matching what a format version mismatch already does.How this was tested
cargo buildcargo test --workspacecargo clippy --all-targets --all-featurescargo fmt --all --checkAll tests pass. Clippy passes with no warnings. Format passes with no suggestions.
Retry loop reproduced and measured with a corrupt region header and
PREGEN_SIZE=9: 2571 errors sustained over 11 seconds before, 256 (one per ticketed chunk) finishing within 2 seconds after. With a read-only region directory: one fatal line and a clean stop at 0.42s, zero retry spam. An undamaged world is unaffected.Screenshots / logs
Checklist
Additional notes
DISCLAIMER: This PR was AI assisted and manually reviewed.