Skip to content

Commit 8a4303f

Browse files
authoredOct 9, 2020
Merge pull request #105 from ipfs/fix/no-txns-for-batch
Add Cancel function; add finalizer to cleanup abandoned batch
2 parents 61b3889 + 1a720f8 commit 8a4303f

File tree

2 files changed

+47
-7
lines changed

2 files changed

+47
-7
lines changed
 

‎datastore.go

+23-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package badger
33
import (
44
"errors"
55
"fmt"
6+
"runtime"
67
"strings"
78
"sync"
89
"time"
@@ -398,19 +399,19 @@ func (d *Datastore) Close() error {
398399

399400
// Batch creats a new Batch object. This provides a way to do many writes, when
400401
// there may be too many to fit into a single transaction.
401-
//
402-
// After writing to a Batch, always call Commit whether or not writing to the
403-
// batch was completed successfully or not. This is necessary to flush any
404-
// remaining data and free any resources associated with an incomplete
405-
// transaction.
406402
func (d *Datastore) Batch() (ds.Batch, error) {
407403
d.closeLk.RLock()
408404
defer d.closeLk.RUnlock()
409405
if d.closed {
410406
return nil, ErrClosed
411407
}
412408

413-
return &batch{d, d.DB.NewWriteBatch()}, nil
409+
b := &batch{d, d.DB.NewWriteBatch()}
410+
// Ensure that incomplete transaction resources are cleaned up in case
411+
// batch is abandoned.
412+
runtime.SetFinalizer(b, func(b *batch) { b.cancel() })
413+
414+
return b, nil
414415
}
415416

416417
func (d *Datastore) CollectGarbage() (err error) {
@@ -479,11 +480,26 @@ func (b *batch) commit() error {
479480
err := b.writeBatch.Flush()
480481
if err != nil {
481482
// Discard incomplete transaction held by b.writeBatch
482-
b.writeBatch.Cancel()
483+
b.cancel()
483484
}
484485
return err
485486
}
486487

488+
func (b *batch) Cancel() error {
489+
b.ds.closeLk.RLock()
490+
defer b.ds.closeLk.RUnlock()
491+
if b.ds.closed {
492+
return ErrClosed
493+
}
494+
495+
b.cancel()
496+
return nil
497+
}
498+
499+
func (b *batch) cancel() {
500+
b.writeBatch.Cancel()
501+
}
502+
487503
var _ ds.Datastore = (*txn)(nil)
488504
var _ ds.TTLDatastore = (*txn)(nil)
489505

‎ds_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,30 @@ func TestBatching(t *testing.T) {
307307
"/g",
308308
}, rs)
309309

310+
//Test cancel
311+
312+
b, err = d.Batch()
313+
if err != nil {
314+
t.Fatal(err)
315+
}
316+
317+
const key = "/xyz"
318+
319+
err = b.Put(ds.NewKey(key), []byte("/x/y/z"))
320+
if err != nil {
321+
t.Fatal(err)
322+
}
323+
324+
// TODO: remove type assertion once datastore.Batch interface has Cancel
325+
err = b.(*batch).Cancel()
326+
if err != nil {
327+
t.Fatal(err)
328+
}
329+
330+
_, err = d.Get(ds.NewKey(key))
331+
if err == nil {
332+
t.Fatal("expected error trying to get uncommited data")
333+
}
310334
}
311335

312336
func TestBatchingRequired(t *testing.T) {

0 commit comments

Comments
 (0)
Please sign in to comment.