Restrict max RBF transaction size

This commit is contained in:
Ben Johnson 2020-11-10 08:14:14 -07:00
parent 78eb9e0711
commit 9eba299d35
3 changed files with 34 additions and 2 deletions

View file

@ -39,6 +39,25 @@ func TestDB_Open(t *testing.T) {
}
}
func TestDB_WAL(t *testing.T) {
t.Run("ErrTxTooLarge", func(t *testing.T) {
config := rbfcfg.NewDefaultConfig()
config.MaxWALSize = 4 * rbf.PageSize
db := MustOpenDB(t, config)
defer MustCloseDB(t, db)
tx := MustBegin(t, db, true)
defer tx.Rollback()
if err := tx.CreateBitmap("x"); err != nil {
t.Fatal(err)
} else if err := tx.CreateBitmap("y"); err != rbf.ErrTxTooLarge {
t.Fatalf("unexpected error: %v", err)
}
})
}
func TestDB_Recovery(t *testing.T) {
// Ensure a bitmap header written without a bitmap is truncated.
t.Run("TruncPartialWALBitmap", func(t *testing.T) {

View file

@ -105,6 +105,7 @@ var (
ErrBitmapNameRequired = errors.New("bitmap name required")
ErrBitmapNotFound = errors.New("bitmap not found")
ErrBitmapExists = errors.New("bitmap already exists")
ErrTxTooLarge = errors.New("rbf tx too large")
)
// Debug is just a temporary flag used for debugging.

View file

@ -69,7 +69,12 @@ func (tx *Tx) Writable() bool {
// dirty returns true if any pages have been updated in this tx.
func (tx *Tx) dirty() bool {
return len(tx.dirtyPages) != 0 || len(tx.dirtyBitmapPages) != 0
return tx.dirtyN() != 0
}
// dirtyN returns the number of dirty pages.
func (tx *Tx) dirtyN() int {
return len(tx.dirtyPages) + len(tx.dirtyBitmapPages)
}
// PageN returns the number of pages in the database as seen by this transaction.
@ -954,11 +959,18 @@ func (tx *Tx) readPage(pgno uint32) ([]byte, error) {
func (tx *Tx) writePage(page []byte) error {
tx.dirtyPages[readPageNo(page)] = page
return nil
return tx.checkTxSize()
}
func (tx *Tx) writeBitmapPage(pgno uint32, page []byte) error {
tx.dirtyBitmapPages[pgno] = page
return tx.checkTxSize()
}
func (tx *Tx) checkTxSize() error {
if (tx.walPageN+tx.dirtyN())*PageSize >= len(tx.db.wal) {
return ErrTxTooLarge
}
return nil
}