Repository navigation
Conversation
Author
|
Closing — keeping these fixes local rather than upstreaming. Thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
vibetime quietly stopped keeping my sessions: between Oct 11 and Oct 16 it twice reset
~/.vibe/sessions.jsonto empty, dropping 106 and then 22 sessions, with nothing on screen to say so. Three bugs insrc/db.tslined up to do it. This fixes all three.What happened. On Oct 10 a process was killed while holding
~/.vibe/sessions.lock, leaving the dir with nopidfile in it.acquireLockonly treats a lock as stale when it finds apidfile older than 10 s, so this one was never cleared, and from then on every write waited out its 20 retries and took the unlocked fallback. Parallel hook processes then wrote at the same time, all through the onesessions.json.tmp, and tore it: one backup was a whole document followed by the tail of a longer one (JSON.parsefails with trailing bytes).readDbmoved each torn file to.corrupt.<ts>and returned an empty list, and the next write saved that empty list over the history. I recovered the sessions from both.corruptfiles by hand.Stale locks.
acquireLocknow askslockIsStale(). A lock with apidfile is stale when that file is older thanLOCK_STALE_MS, as before, or when its pid no longer names a running process (process.kill(pid, 0), withEPERMcounted as alive). A lock with nopidfile is stale once the dir itself is older thanLOCK_STALE_MS, which covers a holder killed betweenmkdirand writing its pid, or between removing its pid and the dir. A fresh pid-less lock is still respected, since its holder may be about to write the pid.One tmp file per write.
writeDbwrote every process's data tosessions.json.tmp. Two unlocked writers opened the same inode, interleaved their bytes, and one renamed the result into place while the other's rename failed withENOENTand threw. The tmp name is nowsessions.json.<pid>.<random>.tmp, asauth.tsalready does forauth.json, and a failed write removes its tmp file. Unlocked writers can still lose each other's update, last rename wins, but neither can tear the file.Recover instead of reset. When
sessions.jsondoes not parse,readDbnow looks for the brace that closes the top-level object (skipping braces inside strings) and parses up to it. JSON cannot continue past that brace, so it ends the only prefix that can parse, and a torn write leaves a whole document there. If that prefix holds asessionsarray, it is returned. Under the lock, the original is copied to.corrupt.<ts>and the recovered document is written back in one rename, so no reader finds the file missing. An unlocked reader (getSessions) only returns the recovered list and leaves the repair to the next locked write, because its rewrite could otherwise land after a locked writer and undo it. When nothing parses, behaviour is unchanged: the file is moved to.corrupt.<ts>and the list starts empty.Checks:
npm testpasses, 155 of 155.test/sessions-db.test.mjsadds six tests: a pid-less lock dir older than the stale window is cleared and the write takes the lock; a fresh pid-less lock dir is left alone; a lock whose pid has exited is cleared; six processes writing unlocked behind a live lock over a 3000-session file all exit 0, leave valid JSON holding more sessions than were seeded, no.corruptcopy and no tmp files; a torn file (braces and quotes inside strings, then a trailing tail) reads back with all its sessions, and the next write repairs it and keeps the original byte for byte in one.corruptcopy; an unrecoverable file is still moved aside. Onmainthe first, third, fourth and fifth fail, the fourth with theENOENTrename every run.