Skip to content

Commit 7c22e3a

Browse files
smart-notes: take the write lock at BEGIN for state commits
commitSmartNoteState read (lease check) then wrote inside a deferred transaction; the read-to-write lock upgrade returns SQLITE_BUSY without waiting on busy_timeout, so concurrent processes hit spurious 'database is locked' failures. BEGIN IMMEDIATE acquires the write lock up front and waits under busy_timeout like every other writer. Co-authored-by: Alfonso [Magic Context] <288211368+alfonso-magic-context@users.noreply.github.com>
1 parent 872a481 commit 7c22e3a

2 files changed

Lines changed: 25 additions & 4 deletions

File tree

.alfonso/release-notes/v0.31.1.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,9 @@ Patch release: the TUI sidebar no longer breaks when OpenCode changes its embedd
88
The plugin previously shipped its own copies of `@opentui/core`, `@opentui/solid`, and `solid-js`, pinned to match a specific OpenCode release. Every time OpenCode upgraded or reverted its embedded OpenTUI, that pin went stale and the sidebar could fail to load until we shipped a matching release.
99

1010
OpenCode's TUI loader actually supplies its own OpenTUI and Solid instances to raw-TSX plugins, so the local copies were unnecessary. They are no longer installed as runtime dependencies; the host's versions are used directly. The sidebar now works across OpenCode's OpenTUI upgrades (0.3.x through 0.4.x) without a plugin update, and installs get slightly smaller.
11+
12+
### Smart-note background checks no longer spill errors to stderr
13+
A smart-note network check that hit the response size limit (or timed out) printed an uncaught `SmartNoteNetworkError` stack trace to OpenCode's stderr on every occurrence. The error is now handled on the response stream and reported through the normal check-failure path.
14+
15+
### Smart-note state writes no longer fail with "database is locked"
16+
Smart-note scheduling updates used a transaction shape that could not wait for a concurrent writer, producing spurious `database is locked` errors when several OpenCode instances shared the database. They now take the write lock up front and wait like every other writer.

packages/plugin/src/features/magic-context/smart-notes/storage.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,32 @@ export function commitSmartNoteState(
2626
write: () => void;
2727
},
2828
): void {
29+
// BEGIN IMMEDIATE, not a plain (deferred) transaction: the lease check reads
30+
// before the write, and a deferred read→write lock upgrade returns
31+
// SQLITE_BUSY immediately when another writer holds the lock — busy_timeout
32+
// does not apply to upgrades, so concurrent processes produced spurious
33+
// "database is locked" failures here. Taking the write lock at BEGIN time
34+
// waits under busy_timeout like every other writer.
35+
db.exec("BEGIN IMMEDIATE");
2936
let leaseLost = false;
30-
db.transaction(() => {
37+
try {
3138
// State transitions surface notes or change future scheduling. The lease
3239
// check must be inside the same write transaction so ownership cannot be
3340
// lost between a pre-check and the durable update.
3441
if (args.leaseHeld && !args.leaseHeld()) {
3542
leaseLost = true;
36-
return;
43+
} else {
44+
args.write();
3745
}
38-
args.write();
39-
})();
46+
db.exec("COMMIT");
47+
} catch (error) {
48+
try {
49+
db.exec("ROLLBACK");
50+
} catch {
51+
// Connection-level failures leave nothing to roll back.
52+
}
53+
throw error;
54+
}
4055
if (leaseLost) {
4156
throw new Error(`Dream lease lost during smart-note ${args.phase} commit`);
4257
}

0 commit comments

Comments
 (0)