| Comment: | fix: DSN _txlock=immediate to serialize writers at BEGIN (#33) (#34)
Two concurrent libfossil.Repo handles on the same SQLite file fail their writes with SQLITE_BUSY immediately, well under the configured busy_timeout=5000 window. Reproduces ~50% of the time on contended manifest.Checkin paths. Root cause: db.WithTx opens BEGIN DEFERRED. Under WAL, a deferred transaction acquires SHARED on first read, then upgrades SHARED→RESERVED on first write. If two connections race that upgrade, SQLite's deadlock-avoidance returns SQLITE_BUSY *immediately*, bypassing busy_timeout entirely (documented behavior, sqlite.org/c3ref/busy_timeout.html). Fix: prepend _txlock=immediate to the DSN in both modernc and ncruces drivers. Every BEGIN now acquires RESERVED upfront, so the second writer blocks at BEGIN — where busy_timeout *does* apply — and the two transactions serialize cleanly. Regression tests added to both driver packages: - TestBuildDSN_TxlockImmediate covers the DSN shape across empty/non-empty pragma maps. - TestConcurrentWritersDoNotRace reproduces the issue-#33 contention pattern (two conns, SELECT then INSERT under DEFERRED) over 25 iterations and asserts zero SQLITE_BUSY. Without the fix, this test fails 25/25; with the fix, 0/25. Closes #33. |
|---|---|
| Timelines: | family | ancestors | descendants | both | trunk | v0.6.3 | db/driver/ncruces/v0.2.0 | db/driver/modernc/v0.2.0 |
| Files: | files | file ages | folders |
| SHA3-256: |
202576c58c87d35a6253ce96e9032a54 |
| User & Date: | [email protected] on 2026-05-13 19:09:49.000 |
| Other Links: | manifest | tags |
|
2026-06-09
| ||
| 06:11 | fix checkout portability under ncruces (#39) check-in: 6abfdc7c25 user: [email protected] tags: trunk | |
|
2026-05-13
| ||
| 19:09 |
fix: DSN _txlock=immediate to serialize writers at BEGIN (#33) (#34)
Two concurrent libfossil.Repo handles on the same SQLite file fail their writes with SQLITE_BUSY immediately, well under the configured busy_timeout=5000 window. Reproduces ~50% of the time on contended manifest.Checkin paths. Root cause: db.WithTx opens BEGIN DEFERRED. Under WAL, a deferred transaction acquires SHARED on first read, then upgrades SHARED→RESERVED on first write. If two connections race that upgrade, SQLite's deadlock-avoidance returns SQLITE_BUSY *immediately*, bypassing busy_timeout entirely (documented behavior, sqlite.org/c3ref/busy_timeout.html). Fix: prepend _txlock=immediate to the DSN in both modernc and ncruces drivers. Every BEGIN now acquires RESERVED upfront, so the second writer blocks at BEGIN — where busy_timeout *does* apply — and the two transactions serialize cleanly. Regression tests added to both driver packages: - TestBuildDSN_TxlockImmediate covers the DSN shape across empty/non-empty pragma maps. - TestConcurrentWritersDoNotRace reproduces the issue-#33 contention pattern (two conns, SELECT then INSERT under DEFERRED) over 25 iterations and asserts zero SQLITE_BUSY. Without the fix, this test fails 25/25; with the fix, 0/25. Closes #33. check-in: 202576c58c user: [email protected] tags: trunk, v0.6.3, db/driver/ncruces/v0.2.0, db/driver/modernc/v0.2.0 | |
|
2026-05-12
| ||
| 23:48 |
fix: Repo.Commit preserves parent's tracked files (#30) (#32)
Repo.Commit was a thin pass-through to manifest.Checkin: callers who supplied a subset of the parent's tracked files got a partial manifest, so files tracked at the parent silently disappeared from the new commit. A checkout at the child's rev saw only the supplied subset — bones, EdgeSync, and sesh all hit this as silent data loss across slot commits. Default behavior now matches `fossil ci`: when ParentID > 0 the parent's F-cards are merged into the commit's file set (caller wins on name collision; untouched parent files are loaded by UUID and carried forward). For the rare case where a caller intentionally wants omission to mean deletion, CommitOpts.PartialManifest opts out of the merge. The internal diff/deletion tests that previously relied on the partial behavior now set this flag explicitly. A first-class deletion API may replace the escape hatch later. Adds TestCommitPreservesParentFiles as the regression: parent [a,b,c], child supplies only [b'], child's ListFiles must return [a,b',c] with a and c keeping the parent's blob UUIDs. check-in: 862dcb20c3 user: [email protected] tags: trunk, v0.6.2 | |