Skip to content

Commit

Permalink
mvcc: fix panic on *bolt.Tx.Size after commit
Browse files Browse the repository at this point in the history
1. batchTx.commit(false) from newBatchTx
2. batchTx.commit(true) from stopping backend
3. batchTx.commit(false) from ongoing mvcc Hash call

would panic because *bolt.Tx.Commit in batchTx.commit
initializes *bolt.Tx.db and *bolt.Tx.meta as nil,
and subsequent *bolt.Tx.Size() call refers to this nil
pointer (panic).
  • Loading branch information
gyuho committed Oct 18, 2016
1 parent 5c60478 commit dbd6a65
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 0 deletions.
6 changes: 6 additions & 0 deletions mvcc/backend/batch_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type batchTx struct {
tx *bolt.Tx
backend *backend
pending int
stopped bool
}

func newBatchTx(backend *backend) *batchTx {
Expand Down Expand Up @@ -145,6 +146,7 @@ func (t *batchTx) CommitAndStop() {
t.Lock()
defer t.Unlock()
t.commit(true)
t.stopped = true
}

func (t *batchTx) Unlock() {
Expand All @@ -156,6 +158,10 @@ func (t *batchTx) Unlock() {
}

func (t *batchTx) commit(stop bool) {
if t.stopped {
return
}

var err error
// commit the last tx
if t.tx != nil {
Expand Down
18 changes: 18 additions & 0 deletions mvcc/backend/batch_tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,21 @@ func TestBatchTxBatchLimitCommit(t *testing.T) {
return nil
})
}

// TestBatchTxCommitSize tests immediate stop of backend does not panic.
// *batchTx.Commit in newBatchTx calls *bolt.Tx.Commit, which clears
// *bolt.Tx.meta and *bolt.Tx.db reference after commit. Then following
// *bolt.Tx.Size call would panic with nil pointer reference.
// This can happen when backend closes with batchTx.CommitAndStop() with
// ongoing batchTx.Commit() from mvcc Hash call.
func TestBatchTxCommitSize(t *testing.T) {
// 1. call newBatchTx with batchTx.commit(false)
b, tmpPath := NewTmpBackend(300*time.Millisecond, 100)
defer cleanup(b, tmpPath)

// 2. call batchTx.commit(true)
b.batchTx.CommitAndStop()

// 3. backend.run() trigger batchTx.commit(false) from timer
time.Sleep(600 * time.Millisecond)
}

0 comments on commit dbd6a65

Please sign in to comment.