From c5089d25cb60d7c4b819c4eab3cdbf2090ef192c Mon Sep 17 00:00:00 2001 From: Lester Caine Date: Thu, 18 Jun 2026 16:42:20 +0100 Subject: Add CLAUDE.md: document BitPage::store() missing RollbackTrans bug Intermittent "page not found" traced to open Firebird transaction when an exception escapes store() before CompleteTrans() runs. Includes diagnostic query and proposed fix pattern. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..97b1393 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,36 @@ +# Wiki Package — Developer Notes + +## BitPage::store() — missing RollbackTrans +`BitPage::store()` (line 220) wraps the entire save in `StartTrans()` / `CompleteTrans()` +but has no `RollbackTrans()` fallback. If an exception escapes — e.g. from the nested +`LibertyMime::store()` call at line 222, which has its own `StartTrans()` — `CompleteTrans()` +never runs and Firebird is left with an open transaction holding locks on `wiki_pages` +and/or `liberty_content` rows. + +Symptom: wiki pages return "page not found" until Firebird is restarted. The failed save +appears to cause no visible error, but the stuck transaction blocks subsequent access to +the affected rows. + +**Diagnostic** — run in isql when stuck: +```sql +SELECT t.MON$TRANSACTION_ID, t.MON$TIMESTAMP, + s.MON$SQL_TEXT, s.MON$STATE +FROM MON$TRANSACTIONS t +LEFT JOIN MON$STATEMENTS s ON s.MON$TRANSACTION_ID = t.MON$TRANSACTION_ID +WHERE t.MON$STATE = 1; +``` + +**Fix** — wrap the body of `store()` in a try/catch with `RollbackTrans()`: +```php +$this->StartTrans(); +try { + // ... existing body ... + $this->CompleteTrans(); +} catch( \Exception $e ) { + $this->mDb->RollbackTrans(); + $this->mErrors['store'] = $e->getMessage(); +} +``` + +Do not action until confirmed via `MON$TRANSACTIONS` — use xdebug or the monitoring +query above to verify this is the actual call stack before patching. -- cgit v1.3