Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
| Comment: | OCX's wait for those outside OCX holding what a write writes waits for readers as well as writers, BEGIN EXCLUSIVE in place of BEGIN IMMEDIATE, and, for a command in a checkout, on the checkout's own database as well as its repository
Intent: the adversarial review of 211a7d966b (scratchpad rv211, rv211-fix, rv211-e) found two things, each confirmed on Fossil 2.27: (1) a reader outside OCX, an open read transaction on the repository held on past 15 s, with no writer anywhere, lost a report write after 9 runs and 135 s: each run's COMMIT waited Fossil's 15 s for the reader and failed, "database is locked: {COMMIT}", but no reader holds back BEGIN IMMEDIATE, so each of OCX's waits went through at once and counted as one that ended as a writer let go, until the eight runs again were used up; (2) a writer outside OCX holding a checkout's own database, .fslckout, as a person's own fossil command there does, lost an add OCX made there in 0.19 s with no wait, since the wait named the repository alone, by -R, which no one held. With BEGIN EXCLUSIVE, in the review's trials, a reader holding 20 s let the write store after 19.69 s and one holding 150 s failed it after 105.19 s and four runs, the bound HISTORY.md decision 113 states, and an add in a checkout whose database a writer held 5 s waited 4.77 s and went through. Expression: src/ocx/fossil.cr: LET_GO is ".timeout 15000" "BEGIN EXCLUSIVE; ROLLBACK;", which waits for readers and writers both and, past its .timeout, says what BEGIN IMMEDIATE said, so such a wait counts as a try; Place#run tells Place#hosted whether a command is in a checkout (in_checkout: neither `on` nor `repository` names its repository, so its repository file came from the checkout `dir` is in), and hosted makes such a command's wait with no -R, in the checkout, where fossil sql opens the checkout's own database with its repository and waits on both; Locked's message says writers or a reader outside OCX held the repository, and, for a command in a checkout, or the checkout's own database, which of the two neither Fossil nor the wait says; the comments of Locked, LOCKED, LET_GO, TRIES, RERUNS, turn, run and hosted say so, and that while the wait waits for a reader new reads wait behind it, up to BUSY, as they did behind a COMMIT waiting for that reader. spec/support/stand_in_fossil.cr: Holder, who holds a database outside OCX: Writer, an open BEGIN IMMEDIATE on the repository, as before; Reader, an open read transaction on it, a command meeting it failed by the stand-in at once, in Fossil's words, in place of its COMMIT's wait of 15 s; Checkout, an open write on a checkout's own database alone; holding_past and holding_until take `by`; OCX's wait known as its last argument is LET_GO's last, as one in a checkout has no -R; holding_past's wait the real one with .timeout 0 in place of LET_GO's .timeout, whatever names the database. spec/ocx/create_spec.cr, spec/ocx/post_spec.cr, spec/ocx/remote_node_spec.cr and spec/ocx/fossil_spec.cr follow Locked's new words. Docs: HISTORY.md decision 114, amending decision 113 and naming the review; docs/fossil.md, "Forum posts", what was tried: a reader fails a write at its COMMIT after 15 s, BEGIN IMMEDIATE goes through at once past it, BEGIN EXCLUSIVE waits for it, returning as it let go at 1 s and saying "Error: stepping, database is locked (5)" after 2 s under .timeout 2000, and a read starting while it waits answers once it goes through; and a checkout's own database is locked apart from its repository: add and commit there failed at once while a wait by -R went through, and fossil sql in the checkout with no -R waits on both; docs/interfaces.md, fossil sql's row, and docs/backlog.md, its first row, name the new wait. The protocol's definitions are unchanged: failure case 35 and section 5 speak of writers, which stays true. Review: Gemma (gemma4:31b) read the change five times (scratchpad gemma-exclusive-1.txt to -5.txt, the whole diff). Held: first round, that Locked's message named a checkout's own database for a command with no repository file at all: it now does so only for a command in a checkout. Misread, each a clarity finding, the code changed and asked again: third round, that a directory holding a repository file but no checkout would read as a checkout: the -R arguments hosted was given, from which it inferred a checkout, became an explicit in_checkout, run's comment saying a command naming no repository has a repository file only from the checkout `dir` is in; fourth round, that LET_GO gaining a trailing argument would defeat the stand-in's match for OCX's wait: its comments now say it compares the last argument with LET_GO's last, which Place#hosted puts after whatever names the database. Wrong: first and fourth rounds, that matching the last argument is fragile: a wait the stand-in did not know would make the holding specs fail, not pass; second round, that "the repository or the checkout's own database" is imprecise: neither Fossil's error nor the wait says which of the two was held, and its proposed check was the same condition; fourth round, that the message conflates the two bounds: it names the runs in all and how each wait ended, unchanged here, as the review of 211a7d966b's own fifth round found; fifth round, that the message contradicts the specs: each spec's words match it, and each checks the part it names, the rest being what Fossil said. Demonstrates: spec/ocx/writers_spec.cr (a reader holding the repository while a report write runs: the report stored once the reader lets go during OCX's wait; a write failed after TRIES runs, three waits ending with it still held, storing nothing, while the reader holds on past each wait, which with BEGIN IMMEDIATE failed after RERUNS + 1 runs, each wait going through at once), spec/ocx/fossil_spec.cr (a writer holding a checkout's own database while add and then commit run there: each waits and goes through, the file committed; an add failed after TRIES runs, storing nothing, while it holds on past each wait, which with the wait by -R failed after RERUNS + 1; and Locked's new words), spec/ocx/create_spec.cr, spec/ocx/post_spec.cr and spec/ocx/remote_node_spec.cr (Locked's new words, a push in a checkout naming the checkout's own database), spec/support/stand_in_fossil.cr (Holder; holding_past and holding_until by a holder; OCX's wait known by its last argument), src/ocx/fossil.cr, spec/guards/size_spec.cr (each file at most 400 lines), spec/guards/causation_spec.cr (no timer added), spec/guards/interfaces_spec.cr and spec/guards/documents_spec.cr (the edited documents rendering with their links), spec/coverage/run.cr (every statement still covered). crystal run ci.cr green: 495 examples, 0 failures. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | agent-tools |
| Files: | files | file ages | folders |
| SHA3-256: |
39c646f7ad83965fec5e53e29d7bab6b |
| User & Date: | opus-ocx2 2026-10-23 04:35:56.511 |
|
2026-10-23
| ||
| 05:50 |
In a checkout, OCX's wait for those outside OCX holding what a write writes waits on the checkout's own database alone, then on its repository alone, so waiting for a writer holding the checkout's own database keeps no read or write from the repository
Intent: the adversarial review of 39c646f7ad (scratchpad rv211-e/x39) found, confirmed on Fossil 2.27: in a checkout, OCX's wait, fossil sql there with no -R and BEGIN EXCLUSIVE, opened the repository as its main database, then .fslckout, then Fossil's settings, and took their locks in that order, keeping each while it waited for the next, so with only .fslckout held by a writer outside OCX it took the repository's exclusive lock at once and kept it, at each of its waits: a read of the repository and /timeline took 14.36 s during it (0.01 s beside a wait by -R); while OCX's add met .fslckout held 70 s, 15 of 50 pages took over 15 s, the longest 29.99 s, with no one holding the repository; and a person's commit-like command in the checkout, holding .fslckout and reading the repository, lost its write of the repository, "database is locked (5)". HISTORY.md decision 114 and the comments of LET_GO and Place#hosted, which said the wait waited on both, were wrong for this case. With two waits, in the review's trials and again here: each of those 50 pages answered within 0.01 s; the person's write was kept and OCX's add went through after 2.77 s (2.76 s here); and a commit in a checkout whose repository a reader held 20 s was stored after 19.69 s (19.7 s here). Expression: src/ocx/fossil.cr: Place#hosted makes a command's wait, in a checkout, two: first fossil sql there with --no-repository and an empty main database (:memory:), which opens the checkout's own database with nothing but Fossil's settings after it, then, only once that has gone through, fossil sql -R on the repository alone, which opens no checkout database; the wait goes through only as both do, so the counting of tries and runs again is unchanged; a command naming its repository waits by -R alone, as before; a new private Place#let_go_of? makes one such wait; naming .fslckout itself as the main database opens it twice and the wait waits on itself, as tried; the comments of LET_GO, TRIES, hosted and let_go_of? say so, and that in a checkout a wait takes up to twice BUSY. spec/support/stand_in_fossil.cr: Holder::Person, a person's own fossil command in a checkout, as fossil commit is, writing the checkout's own database and reading its repository in one transaction, and, as it lets go, writing the repository's setting KEPT and committing (Holder#lets_go), where every other holder rolls back; Holder#waited_on, the shell test by which the stand-in knows OCX's wait is on the holder's database, a wait on the repository naming it by -R first and one on a checkout's own database naming no repository; the holder's sql shell keeps Fossil's settings in the stand-in's own directory, its HOME, since a writer's BEGIN IMMEDIATE takes the lock of every database its shell opens, the settings database among them, which OCX's first wait in a checkout opens too (spec/ocx/post_spec.cr's clone held at its write's first run failed so); holding_until's waited returns only once OCX's wait is asleep in SQLite's busy wait, as /proc/PID/wchan says, so it has taken each lock it takes before the holder's, where before it returned as the wait started and a read could come before the old wait locked the repository. spec/ocx/fossil_spec.cr: the new example. Docs: HISTORY.md decision 115, amending decision 114 and naming the review, decision 113's bound being in a checkout three waits of up to 30 s each; docs/fossil.md, "Forum posts", what was tried: the order fossil sql in a checkout opens and locks its databases, the stalled reads and the lost write, --no-repository :memory:, and .fslckout as the main database waiting on itself; docs/interfaces.md, fossil sql's row. The protocol's definitions are unchanged: section 5 and failure case 35 speak of a writer holding the repository, for which a wait in a checkout is still up to 15 s, its first wait going through at once where no one holds the checkout's own database. Review: Gemma (gemma4:31b) read the change four times (scratchpad gemma-split-1.txt to -4.txt, the whole diff). Held: none. Misread, each a clarity finding, the code changed and asked again: first and second rounds, each opening that the two waits' let_go was flawed, overwritten by the second wait, or the repository's wait skipped when the first did not go through, each taken back by Gemma itself: hosted's comment now says the second wait is made only once the first has gone through and that the wait goes through only as both do, and the two assignments became one expression, let_go = (!in_checkout || let_go_of?(["--no-repository", ":memory:"])) && let_go_of?(["-R", file]). Wrong: third round, about counting each run as a try or a run again at the loop's start, code unchanged here, which it read right in the end; fourth round, that a wait on the checkout's own database that does not go through leaves the repository never waited on: the run after it meets that holder first, and the repository's wait follows once the first goes through, as Gemma itself then said. Demonstrates: spec/ocx/fossil_spec.cr (in a checkout, a writer holding its own database alone, then a person's command holding it and reading the repository, while an add there waits: a read of the repository through the fossil program answers within a second, the add goes through once each lets go, and the person's write of the repository as it let go is kept; against 39c646f7ad's src/ocx/fossil.cr each read failed, nothing after a second, and the person's write was lost; and, as before, a writer holding the checkout's own database while add and commit run there, and past each wait), spec/ocx/writers_spec.cr (a read within a second while a report waits for a writer, and a reader holding the repository while a report write runs, OCX's waits known once asleep), spec/ocx/post_spec.cr (a post in a clone held at its write's first run, written whole and pushed once, the holder's settings apart from OCX's), spec/ocx/create_spec.cr (a run held past each wait of its write stores nothing), spec/support/stand_in_fossil.cr (Holder::Person, Holder#waited_on, the holder's own settings, holding_until answering once OCX's wait is asleep), src/ocx/fossil.cr, spec/guards/size_spec.cr (each file at most 400 lines), spec/guards/causation_spec.cr (no timer added), spec/guards/interfaces_spec.cr and spec/guards/documents_spec.cr (the edited documents rendering with their links), spec/coverage/run.cr (every statement still covered, Place#let_go_of? among them). crystal run ci.cr green: 496 examples, 0 failures. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs check-in: 4228a3de0b user: opus-ocx2 tags: agent-tools | |
| 04:35 |
OCX's wait for those outside OCX holding what a write writes waits for readers as well as writers, BEGIN EXCLUSIVE in place of BEGIN IMMEDIATE, and, for a command in a checkout, on the checkout's own database as well as its repository
Intent: the adversarial review of 211a7d966b (scratchpad rv211, rv211-fix, rv211-e) found two things, each confirmed on Fossil 2.27: (1) a reader outside OCX, an open read transaction on the repository held on past 15 s, with no writer anywhere, lost a report write after 9 runs and 135 s: each run's COMMIT waited Fossil's 15 s for the reader and failed, "database is locked: {COMMIT}", but no reader holds back BEGIN IMMEDIATE, so each of OCX's waits went through at once and counted as one that ended as a writer let go, until the eight runs again were used up; (2) a writer outside OCX holding a checkout's own database, .fslckout, as a person's own fossil command there does, lost an add OCX made there in 0.19 s with no wait, since the wait named the repository alone, by -R, which no one held. With BEGIN EXCLUSIVE, in the review's trials, a reader holding 20 s let the write store after 19.69 s and one holding 150 s failed it after 105.19 s and four runs, the bound HISTORY.md decision 113 states, and an add in a checkout whose database a writer held 5 s waited 4.77 s and went through. Expression: src/ocx/fossil.cr: LET_GO is ".timeout 15000" "BEGIN EXCLUSIVE; ROLLBACK;", which waits for readers and writers both and, past its .timeout, says what BEGIN IMMEDIATE said, so such a wait counts as a try; Place#run tells Place#hosted whether a command is in a checkout (in_checkout: neither `on` nor `repository` names its repository, so its repository file came from the checkout `dir` is in), and hosted makes such a command's wait with no -R, in the checkout, where fossil sql opens the checkout's own database with its repository and waits on both; Locked's message says writers or a reader outside OCX held the repository, and, for a command in a checkout, or the checkout's own database, which of the two neither Fossil nor the wait says; the comments of Locked, LOCKED, LET_GO, TRIES, RERUNS, turn, run and hosted say so, and that while the wait waits for a reader new reads wait behind it, up to BUSY, as they did behind a COMMIT waiting for that reader. spec/support/stand_in_fossil.cr: Holder, who holds a database outside OCX: Writer, an open BEGIN IMMEDIATE on the repository, as before; Reader, an open read transaction on it, a command meeting it failed by the stand-in at once, in Fossil's words, in place of its COMMIT's wait of 15 s; Checkout, an open write on a checkout's own database alone; holding_past and holding_until take `by`; OCX's wait known as its last argument is LET_GO's last, as one in a checkout has no -R; holding_past's wait the real one with .timeout 0 in place of LET_GO's .timeout, whatever names the database. spec/ocx/create_spec.cr, spec/ocx/post_spec.cr, spec/ocx/remote_node_spec.cr and spec/ocx/fossil_spec.cr follow Locked's new words. Docs: HISTORY.md decision 114, amending decision 113 and naming the review; docs/fossil.md, "Forum posts", what was tried: a reader fails a write at its COMMIT after 15 s, BEGIN IMMEDIATE goes through at once past it, BEGIN EXCLUSIVE waits for it, returning as it let go at 1 s and saying "Error: stepping, database is locked (5)" after 2 s under .timeout 2000, and a read starting while it waits answers once it goes through; and a checkout's own database is locked apart from its repository: add and commit there failed at once while a wait by -R went through, and fossil sql in the checkout with no -R waits on both; docs/interfaces.md, fossil sql's row, and docs/backlog.md, its first row, name the new wait. The protocol's definitions are unchanged: failure case 35 and section 5 speak of writers, which stays true. Review: Gemma (gemma4:31b) read the change five times (scratchpad gemma-exclusive-1.txt to -5.txt, the whole diff). Held: first round, that Locked's message named a checkout's own database for a command with no repository file at all: it now does so only for a command in a checkout. Misread, each a clarity finding, the code changed and asked again: third round, that a directory holding a repository file but no checkout would read as a checkout: the -R arguments hosted was given, from which it inferred a checkout, became an explicit in_checkout, run's comment saying a command naming no repository has a repository file only from the checkout `dir` is in; fourth round, that LET_GO gaining a trailing argument would defeat the stand-in's match for OCX's wait: its comments now say it compares the last argument with LET_GO's last, which Place#hosted puts after whatever names the database. Wrong: first and fourth rounds, that matching the last argument is fragile: a wait the stand-in did not know would make the holding specs fail, not pass; second round, that "the repository or the checkout's own database" is imprecise: neither Fossil's error nor the wait says which of the two was held, and its proposed check was the same condition; fourth round, that the message conflates the two bounds: it names the runs in all and how each wait ended, unchanged here, as the review of 211a7d966b's own fifth round found; fifth round, that the message contradicts the specs: each spec's words match it, and each checks the part it names, the rest being what Fossil said. Demonstrates: spec/ocx/writers_spec.cr (a reader holding the repository while a report write runs: the report stored once the reader lets go during OCX's wait; a write failed after TRIES runs, three waits ending with it still held, storing nothing, while the reader holds on past each wait, which with BEGIN IMMEDIATE failed after RERUNS + 1 runs, each wait going through at once), spec/ocx/fossil_spec.cr (a writer holding a checkout's own database while add and then commit run there: each waits and goes through, the file committed; an add failed after TRIES runs, storing nothing, while it holds on past each wait, which with the wait by -R failed after RERUNS + 1; and Locked's new words), spec/ocx/create_spec.cr, spec/ocx/post_spec.cr and spec/ocx/remote_node_spec.cr (Locked's new words, a push in a checkout naming the checkout's own database), spec/support/stand_in_fossil.cr (Holder; holding_past and holding_until by a holder; OCX's wait known by its last argument), src/ocx/fossil.cr, spec/guards/size_spec.cr (each file at most 400 lines), spec/guards/causation_spec.cr (no timer added), spec/guards/interfaces_spec.cr and spec/guards/documents_spec.cr (the edited documents rendering with their links), spec/coverage/run.cr (every statement still covered). crystal run ci.cr green: 495 examples, 0 failures. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs check-in: 39c646f7ad user: opus-ocx2 tags: agent-tools | |
| 03:42 |
A write that meets a writer outside OCX waits for it outside OCX's own lock beside the repository, which each run of the write takes alone, so OCX's pages read on while it waits; and a run again after a wait that ended as the writer let go counts against a stated cap of eight, not the four tries
Intent: the adversarial review of 3c4c65c090 (scratchpad rv3c, rv3c-fix, rv3c-e) found: (1) confirmed, a write waiting for a writer outside OCX to let go held OCX's own lock beside the repository, since Place#run wrapped all of hosted, its waits included, in Fossil.turn, so every OCX page stalled while such a writer held the repository, against that lock's own rule, "never held while waiting on another lock": a /ext/ocx2-cgi/questions page took 9.13 s while one report write waited on a writer holding the repository 10 s, and 0.03 s otherwise; (2) plausible, the wait gives the lock back before the write runs again, so a writer starting in that moment, about 10 ms in the review's trial, used up one of the four runs, and a run was lost after 4.5 s of writes outside OCX, against the 45 s HISTORY.md decision 112 stated. The maintainer, 2026-10-18: "please don't go down any path with a possible race condition". Fossil 2.27 has no write from its command line that waits for the lock and keeps it, so (1) is fixed and (2) narrowed: only a wait that ended with the writer still holding counts toward the tries, a run again after one that went through counts against a cap of its own, and the claims that nothing depends on timing now say what remains; the full fix is a design question in docs/backlog.md. Expression: src/ocx/fossil.cr: Place#run takes the lock beside the repository (Fossil.turn) around a confined command alone; Place#hosted takes it around each run of a command and waits (LET_GO) outside it, counting each run as it starts, a try, the first and each after a wait that did not go through, the writer still holding once BUSY had passed, or a run again, after a wait that went through as the writer let go, and fails (Locked) at the TRIES-th try, four as before, or the RERUNS-th run again, RERUNS new, eight; Locked's message says how many runs it made and how each wait ended; the comments of Locked, LET_GO, TRIES, RERUNS, turn, run and hosted say so, and what remains: a writer starting between a wait and the next run takes the repository first, another of OCX's waits among them, and the check's mend, holding the lock across its commands, waits within it. spec/support/stand_in_fossil.cr: holding_once takes gaps, after each of that many of OCX's waits another writer taking the repository before the write runs again; holding_past, a writer holding the repository until the block ends, each of OCX's waits the real one made with no time to wait, ending as one past BUSY does; holding_until, a writer holding it until the spec lets it go, telling the spec once OCX waits; a private holding serving the three, whose writer, let go, the stand-in waits for as OCX waits. Docs: HISTORY.md decision 113, amending decision 112 and naming the review; docs/backlog.md, two rows, a write path that begins with BEGIN IMMEDIATE, and what still waits behind such a writer, status under the node's lock and the check's mend; docs/fossil.md, "Forum posts", what a wait past its .timeout says, tried at once under .timeout 0 and after 2 s under .timeout 2000, and the two bounds; docs/protocol-v1-fossil.md, section 5, docs/protocol-v1-failures.md, case 35, and docs/interfaces.md, fossil sql's row, the two bounds and reads going on while a write waits; docs/design/modules.json and its generated docs/design/modules.md, src/ocx/fossil.cr's purpose, and docs/survey/functionality.json, the shape of Fossil's operations, each saying four runs at most no more. Review: Gemma (gemma4:31b) read the change five times (scratchpad gemma-turn-1.txt to -5.txt, the whole diff but the generated docs/design/modules.md). Held: none. Misread, each a clarity finding, the code changed and asked again: first round, that a write a writer holds past each wait fails after three runs, reading the bound's check as made before the fourth run: the tries now count from the first run, the check reading tries == TRIES; second and third rounds, that the eighth run again is never made after the eighth wait, though its own trace counted nine runs and its corrected loop was the one written: each run now counts as it starts, a try or a run again, so at the check the counts are the runs made. Wrong: fourth round, after taking back two candidates itself, that the wait made outside OCX's lock may break that lock's rule: the lock keeps two of OCX's commands from meeting, and the wait writes nothing; it led hosted's comment, HISTORY.md and docs/backlog.md to say that another of OCX's waits, holding the write lock as it takes it and gives it back, counts as a writer between a wait and a run; fifth round, that Locked's message conflates the two bounds and that tries - 1 may be wrong: it names the runs in all and each kind of wait, as Gemma's own example shows, and tries is at least 1, the first run counting as one. Demonstrates: spec/ocx/writers_spec.cr (a read through the fossil program, as OCX's pages read the served repository, answering within a second while a report waits for a writer outside OCX to let go, and the report stored and tagged once it does, which failed with the lock held across the wait; a watcher's run whose started meets a writer at each of RERUNS runs, each after a wait that ended as one let go, ending exited, each report stored once, which ended lost under four runs; case 35 as before), spec/ocx/fossil_spec.cr (a writer holding the repository past each wait failing the write after TRIES runs, as before, and one at each run, letting go after it, failing it after RERUNS + 1, each message naming the command, the repository and how each wait ended, storing nothing), spec/ocx/create_spec.cr (a run held past each wait of its write stores nothing, written again whole), spec/ocx/post_spec.cr, spec/ocx/remote_node_spec.cr, spec/ocx/verdict_spec.cr, spec/ocx/sync_spec.cr and spec/ocx/checkout_tools_spec.cr (a push held at each run names what the clone holds), spec/support/stand_in_fossil.cr (holding_once's gaps, holding_past, holding_until), src/ocx/fossil.cr, spec/guards/size_spec.cr (each file at most 400 lines), spec/guards/causation_spec.cr (no timer added), spec/guards/derivation_spec.cr (docs/design/modules.md as docs/design/modules.json generates it), spec/guards/interfaces_spec.cr and spec/guards/documents_spec.cr (the edited documents rendering with their links), spec/coverage/run.cr (every statement still covered). crystal run ci.cr green: 493 examples, 0 failures. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs check-in: 211a7d966b user: opus-ocx2 tags: agent-tools | |