-
Notifications
You must be signed in to change notification settings - Fork 30
Release v1.7.2 — operator self-time fix + decimal benefit % #256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7fbdf3e
719d861
fabf59d
ce1fd8a
b945eba
3a40ada
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| using System.IO; | ||
|
|
||
| namespace PlanViewer.App.Services; | ||
|
|
||
| /// <summary> | ||
| /// Helper for atomic text-file writes: write to a sibling .tmp and rename | ||
| /// into place so a crash mid-write can't truncate the target file. Callers | ||
| /// are responsible for creating the parent directory first. | ||
| /// </summary> | ||
| internal static class AtomicFile | ||
| { | ||
| /// <summary> | ||
| /// Writes <paramref name="contents"/> to <paramref name="path"/> atomically | ||
| /// with respect to process crashes. If the process dies before the rename, | ||
| /// <paramref name="path"/> keeps its previous contents and a stray | ||
| /// <c>.tmp</c> sibling is left behind (cleaned up on the next call). | ||
| /// </summary> | ||
| public static void WriteAllText(string path, string contents) | ||
| { | ||
| var tmp = path + ".tmp"; | ||
| File.WriteAllText(tmp, contents); | ||
| // File.Move with overwrite:true maps to MoveFileEx(MOVEFILE_REPLACE_EXISTING) | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two concurrent writers (two Studio processes saving settings at once) both race on Generated by Claude Code |
||
| // on Windows and rename(2) on Unix — both atomic when source and destination | ||
| // live on the same filesystem, which is always the case here. | ||
| File.Move(tmp, path, overwrite: true); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Race with
IsAllowed: a caller that already resolved_requests.GetOrAdd(key, ...) → timestampscan be blocked onlock (timestamps)whileSweepholds the same lock, observesCount == 0, andTryRemoves the kvp. When the caller then acquires the lock it adds its timestamp to a list that's no longer in the dictionary — the nextIsAllowed(key)call creates a fresh list, so that one request effectively bypasses the rate limit.Not catastrophic at 10/min, but worth either (a) re-checking that
_requests[key]still points atkvp.Valueafter the remove, or (b) adding a sentinel/"tombstoned" flag on the list so a late arrival can detect the eviction and retry viaGetOrAdd.Generated by Claude Code