Skip to content

Commit 8fa3173

Browse files
committed
Simplify closeCh mutex
Add test validating safety of DB access after close
1 parent e3515b3 commit 8fa3173

File tree

2 files changed

+33
-9
lines changed

2 files changed

+33
-9
lines changed

datastore.go

+6-7
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ import (
1717

1818
type Datastore struct {
1919
*accessor
20-
DB *leveldb.DB
21-
path string
22-
closeLk sync.RWMutex
20+
DB *leveldb.DB
21+
path string
2322
}
2423

2524
var _ ds.Datastore = (*Datastore)(nil)
@@ -54,12 +53,12 @@ func NewDatastore(path string, opts *Options) (*Datastore, error) {
5453
return nil, err
5554
}
5655

56+
closeLk := sync.RWMutex{}
5757
ds := Datastore{
58-
accessor: &accessor{ldb: db, syncWrites: true},
58+
accessor: &accessor{ldb: db, syncWrites: true, closeLk: &closeLk},
5959
DB: db,
6060
path: path,
6161
}
62-
ds.accessor.closeLk = &ds.closeLk
6362
return &ds, nil
6463
}
6564

@@ -217,7 +216,7 @@ func (d *Datastore) Batch() (ds.Batch, error) {
217216
return &leveldbBatch{
218217
b: new(leveldb.Batch),
219218
db: d.DB,
220-
closeLk: &d.closeLk,
219+
closeLk: d.closeLk,
221220
syncWrites: d.syncWrites,
222221
}, nil
223222
}
@@ -263,6 +262,6 @@ func (d *Datastore) NewTransaction(readOnly bool) (ds.Txn, error) {
263262
if err != nil {
264263
return nil, err
265264
}
266-
accessor := &accessor{ldb: tx, syncWrites: false, closeLk: &d.closeLk}
265+
accessor := &accessor{ldb: tx, syncWrites: false, closeLk: d.closeLk}
267266
return &transaction{accessor, tx}, nil
268267
}

ds_test.go

+27-2
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,40 @@ func TestQueryRespectsProcess(t *testing.T) {
149149

150150
func TestCloseRace(t *testing.T) {
151151
d, close := newDS(t)
152-
for n := 0; n < 1000; n++ {
152+
for n := 0; n < 100; n++ {
153153
d.Put(ds.NewKey(fmt.Sprintf("%d", n)), []byte(fmt.Sprintf("test%d", n)))
154154
}
155155

156156
tx, _ := d.NewTransaction(false)
157-
go close()
157+
tx.Put(ds.NewKey("txnversion"), []byte("bump"))
158+
159+
closeCh := make(chan interface{})
160+
161+
go func() {
162+
close()
163+
closeCh <- nil
164+
}()
158165
for k := range testcases {
159166
tx.Get(ds.NewKey(k))
160167
}
168+
tx.Commit()
169+
<-closeCh
170+
}
171+
172+
func TestCloseSafety(t *testing.T) {
173+
d, close := newDS(t)
174+
addTestCases(t, d, testcases)
175+
176+
tx, _ := d.NewTransaction(false)
177+
err := tx.Put(ds.NewKey("test"), []byte("test"))
178+
if err != nil {
179+
t.Error("Failed to put in a txn.")
180+
}
181+
close()
182+
err = tx.Commit()
183+
if err == nil {
184+
t.Error("committing after close should fail.")
185+
}
161186
}
162187

163188
func TestQueryRespectsProcessMem(t *testing.T) {

0 commit comments

Comments
 (0)