diff --git a/rbf/db.go b/rbf/db.go index 5976d5cc6..75f357e5b 100644 --- a/rbf/db.go +++ b/rbf/db.go @@ -496,6 +496,17 @@ func (db *DB) Begin(writable bool) (_ *Tx, err error) { // Track transaction with the DB. db.txs[tx] = struct{}{} + // If no root records are cached, build the cache the first time. + // Normally the cache is updated by successful write transactions but + // this avoids recomputing the cache if there are no write txs for a while. + if db.rootRecords == nil { + if db.rootRecords, err = tx.RootRecords(); err != nil { + db.mu.Unlock() + tx.Rollback() + return nil, err + } + } + db.mu.Unlock() return tx, nil } diff --git a/rbf/tx.go b/rbf/tx.go index deeb6a9ba..2996195bc 100644 --- a/rbf/tx.go +++ b/rbf/tx.go @@ -1217,7 +1217,9 @@ func (tx *Tx) Count(name string) (uint64, error) { } defer c.Close() - if err := c.First(); err != nil { + if err := c.First(); err == io.EOF { + return 0, nil + } else if err != nil { return 0, err } diff --git a/rbf/tx_test.go b/rbf/tx_test.go index be647a351..3ca9aaa1d 100644 --- a/rbf/tx_test.go +++ b/rbf/tx_test.go @@ -95,6 +95,30 @@ func TestTx_CommitRollback(t *testing.T) { } }) + t.Run("ReopenReadOnly", func(t *testing.T) { + db := MustOpenDB(t) + defer func() { MustCloseDB(t, db) }() + + // Create bitmap in transaction and commit. + if tx, err := db.Begin(true); err != nil { + t.Fatal(err) + } else if err := tx.CreateBitmap("x"); err != nil { + t.Fatal(err) + } else if err := tx.Commit(); err != nil { + t.Fatal(err) + } + db = MustReopenDB(t, db) + + // Create bitmap again but it should fail as it already exists. + if tx, err := db.Begin(false); err != nil { + t.Fatal(err) + } else if _, err := tx.Count("x"); err != nil { + t.Fatal(err) + } else if err := tx.Commit(); err != nil { + t.Fatal(err) + } + }) + t.Run("SingleWriter", func(t *testing.T) { db := MustOpenDB(t) defer MustCloseDB(t, db)