Fix RBF root record cache build

This commit fixes an issue where the root record cache is only
built when a write transaction successfully commits. However, if
no write transactions are occurring then the the cache is never
built and saved so it is recomputed on every read tx.
This commit is contained in:
Ben Johnson 2021-05-07 11:10:47 -06:00
parent 1af85a818b
commit 8a161bc423
3 changed files with 38 additions and 1 deletions

View file

@ -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
}

View file

@ -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
}

View file

@ -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)