@@ -3,6 +3,7 @@ package badger
3
3
import (
4
4
"errors"
5
5
"fmt"
6
+ "runtime"
6
7
"strings"
7
8
"sync"
8
9
"time"
@@ -398,19 +399,19 @@ func (d *Datastore) Close() error {
398
399
399
400
// Batch creats a new Batch object. This provides a way to do many writes, when
400
401
// 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.
406
402
func (d * Datastore ) Batch () (ds.Batch , error ) {
407
403
d .closeLk .RLock ()
408
404
defer d .closeLk .RUnlock ()
409
405
if d .closed {
410
406
return nil , ErrClosed
411
407
}
412
408
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
414
415
}
415
416
416
417
func (d * Datastore ) CollectGarbage () (err error ) {
@@ -479,11 +480,26 @@ func (b *batch) commit() error {
479
480
err := b .writeBatch .Flush ()
480
481
if err != nil {
481
482
// Discard incomplete transaction held by b.writeBatch
482
- b .writeBatch . Cancel ()
483
+ b .cancel ()
483
484
}
484
485
return err
485
486
}
486
487
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
+
487
503
var _ ds.Datastore = (* txn )(nil )
488
504
var _ ds.TTLDatastore = (* txn )(nil )
489
505
0 commit comments