[PR #492] fix(config): replace serialized state atomically #494

Open
opened 2026-10-15 13:01:00 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/games-on-whales/wolf/pull/492
Author: @elibosley
Created: 8/29/2026
Status: 🔄 Open

Base: beta ← Head: fix/atomic-config-persistence


📝 Commits (2)

  • 4073feb fix(config): replace serialized state atomically
  • 6b260a2 style(config): apply clang-format

📊 Changes

3 files changed (+347 additions, -40 deletions)

View changed files

📝 src/moonlight-server/state/configTOML.cpp (+166 -40)
📝 tests/CMakeLists.txt (+1 -0)
➕ tests/testConfigPersistence.cpp (+180 -0)

📄 Description

Summary

Wolf config updates can leave stale TOML data or lose concurrent mutations; this serializes updates and publishes validated replacement files atomically.

Why This Exists

The current serializer writes to an existing destination without reliably truncating a longer previous document. When a config shrinks, stale array-table data can remain at the tail and make the next startup fail. Independent read-modify-write calls can also race and silently discard a pairing or profile update.

Resolution

Serialize each mutation under one process-local mutex, write to a unique sibling file, parse the completed file before publishing it, preserve permissions, retain a last-known-good copy, and replace the live config with one same-directory rename. Startup recovery is deliberately limited to the known stale-tail signature; unrelated malformed files still fail closed and remain untouched.

Reviewer Considerations

  • Atomic replacement relies on source and temporary files sharing a directory and filesystem.
  • The backup is refreshed only from a config that parses successfully, so a damaged live file cannot overwrite the recovery point.
  • Recovery preserves the damaged file for diagnosis and does not attempt to repair unrecognized TOML failures.
  • The mutex coordinates writers inside one Wolf process; it is not an inter-process lock.

Behavior Changes

Pairing, unpairing, client-setting, and profile updates no longer expose partially written files or lose same-process concurrent mutations. A config damaged by the known stale-tail bug is restored from its last-known-good copy, or regenerated from defaults when no valid backup exists.

Implementation Summary

  • Route all config mutations through a locked read-modify-validate-replace helper.
  • Preserve existing permissions and a validated .last-good sibling.
  • Add narrow startup recovery for stale encoder array tails.
  • Add focused persistence, concurrency, permission, backup, and recovery tests.

Verification

  • The complete [CONFIG] persistence and recovery suite passed in the Linux/amd64 Wolf image build.
  • The complete Wolf image regression suite passed with this change applied.
  • Changed C++ sources pass clang-format --dry-run --Werror with clang-format 21.1.8.
  • GitHub's fork workflows are awaiting maintainer approval; they have not reported a test failure.

Risk

Moderate; this changes persistence and recovery behavior, but each write is validated before publication and unrecognized corruption remains fail-closed.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/games-on-whales/wolf/pull/492 **Author:** [@elibosley](https://github.com/elibosley) **Created:** 8/29/2026 **Status:** 🔄 Open **Base:** `beta` ← **Head:** `fix/atomic-config-persistence` --- ### 📝 Commits (2) - [`4073feb`](https://github.com/games-on-whales/wolf/commit/4073feb5d62d3fe08248817332a57d4c59be1f02) fix(config): replace serialized state atomically - [`6b260a2`](https://github.com/games-on-whales/wolf/commit/6b260a2a3473e21585a0e6a4fc4f8eb90821c408) style(config): apply clang-format ### 📊 Changes **3 files changed** (+347 additions, -40 deletions) <details> <summary>View changed files</summary> 📝 `src/moonlight-server/state/configTOML.cpp` (+166 -40) 📝 `tests/CMakeLists.txt` (+1 -0) ➕ `tests/testConfigPersistence.cpp` (+180 -0) </details> ### 📄 Description ## Summary Wolf config updates can leave stale TOML data or lose concurrent mutations; this serializes updates and publishes validated replacement files atomically. ## Why This Exists The current serializer writes to an existing destination without reliably truncating a longer previous document. When a config shrinks, stale array-table data can remain at the tail and make the next startup fail. Independent read-modify-write calls can also race and silently discard a pairing or profile update. ## Resolution Serialize each mutation under one process-local mutex, write to a unique sibling file, parse the completed file before publishing it, preserve permissions, retain a last-known-good copy, and replace the live config with one same-directory rename. Startup recovery is deliberately limited to the known stale-tail signature; unrelated malformed files still fail closed and remain untouched. ## Reviewer Considerations - Atomic replacement relies on source and temporary files sharing a directory and filesystem. - The backup is refreshed only from a config that parses successfully, so a damaged live file cannot overwrite the recovery point. - Recovery preserves the damaged file for diagnosis and does not attempt to repair unrecognized TOML failures. - The mutex coordinates writers inside one Wolf process; it is not an inter-process lock. ## Behavior Changes Pairing, unpairing, client-setting, and profile updates no longer expose partially written files or lose same-process concurrent mutations. A config damaged by the known stale-tail bug is restored from its last-known-good copy, or regenerated from defaults when no valid backup exists. ## Implementation Summary - Route all config mutations through a locked read-modify-validate-replace helper. - Preserve existing permissions and a validated `.last-good` sibling. - Add narrow startup recovery for stale encoder array tails. - Add focused persistence, concurrency, permission, backup, and recovery tests. ## Verification - The complete `[CONFIG]` persistence and recovery suite passed in the Linux/amd64 Wolf image build. - The complete Wolf image regression suite passed with this change applied. - Changed C++ sources pass `clang-format --dry-run --Werror` with clang-format 21.1.8. - GitHub's fork workflows are awaiting maintainer approval; they have not reported a test failure. ## Risk Moderate; this changes persistence and recovery behavior, but each write is validated before publication and unrecognized corruption remains fail-closed. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
games-on-whales/wolf#494
No description provided.