Skip to content

Commit

Permalink
Discard database txn if user callback panics (#1250)
Browse files Browse the repository at this point in the history
  • Loading branch information
omerfirmak authored Sep 19, 2023
1 parent e4491c3 commit 9323339
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
14 changes: 14 additions & 0 deletions db/pebble/db.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package pebble

import (
"fmt"
"os"
"sync"

"github.com/NethermindEth/juno/db"
Expand Down Expand Up @@ -93,12 +95,14 @@ func (d *DB) Close() error {
// View : see db.DB.View
func (d *DB) View(fn func(txn db.Transaction) error) error {
txn := d.NewTransaction(false)
defer discardTxnOnPanic(txn)
return utils.RunAndWrapOnError(txn.Discard, fn(txn))
}

// Update : see db.DB.Update
func (d *DB) Update(fn func(txn db.Transaction) error) error {
txn := d.NewTransaction(true)
defer discardTxnOnPanic(txn)
if err := fn(txn); err != nil {
return utils.RunAndWrapOnError(txn.Discard, err)
}
Expand All @@ -109,3 +113,13 @@ func (d *DB) Update(fn func(txn db.Transaction) error) error {
func (d *DB) Impl() any {
return d.pebble
}

func discardTxnOnPanic(txn db.Transaction) {
p := recover()
if p != nil {
if err := txn.Discard(); err != nil {
fmt.Fprintf(os.Stderr, "failed discarding panicing txn err: %s", err)
}
panic(p)
}
}
38 changes: 38 additions & 0 deletions db/pebble/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,41 @@ func TestNext(t *testing.T) {
require.NoError(t, it.Close())
})
}

func TestPanic(t *testing.T) {
testDB := pebble.NewMemTest()
t.Cleanup(func() {
require.NoError(t, testDB.Close())
})

t.Run("view", func(t *testing.T) {
defer func() {
p := recover()
require.NotNil(t, p)
}()

require.NoError(t, testDB.View(func(txn db.Transaction) error {
panic("view")
}))
})

t.Run("update", func(t *testing.T) {
var panicingTxn db.Transaction
defer func() {
p := recover()
require.NotNil(t, p)

require.ErrorIs(t, testDB.View(func(txn db.Transaction) error {
return txn.Get([]byte{0}, func(b []byte) error { return nil })
}), db.ErrKeyNotFound)
require.EqualError(t, panicingTxn.Get([]byte{0}, func(b []byte) error { return nil }), "discarded txn")
}()

require.NoError(t, testDB.Update(func(txn db.Transaction) error {
panicingTxn = txn
require.ErrorIs(t, txn.Get([]byte{0}, func(b []byte) error { return nil }), db.ErrKeyNotFound)
require.NoError(t, txn.Set([]byte{0}, []byte{0}))
panic("update")
}))
})
}

0 comments on commit 9323339

Please sign in to comment.