@@ -70,8 +70,9 @@ type Database struct {
70
70
seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt
71
71
manualMemAllocGauge metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated
72
72
73
- quitLock sync.Mutex // Mutex protecting the quit channel access
73
+ quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag
74
74
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
75
+ closed bool // keep track of whether we're Closed
75
76
76
77
log log.Logger // Contextual logger tracking the database path
77
78
@@ -221,23 +222,29 @@ func New(file string, cache int, handles int, namespace string, readonly bool) (
221
222
func (d * Database ) Close () error {
222
223
d .quitLock .Lock ()
223
224
defer d .quitLock .Unlock ()
224
-
225
225
// Allow double closing, simplifies things
226
- if d .quitChan == nil {
226
+ if d .closed {
227
227
return nil
228
228
}
229
- errc := make (chan error )
230
- d .quitChan <- errc
231
- if err := <- errc ; err != nil {
232
- d .log .Error ("Metrics collection failed" , "err" , err )
229
+ d .closed = true
230
+ if d .quitChan != nil {
231
+ errc := make (chan error )
232
+ d .quitChan <- errc
233
+ if err := <- errc ; err != nil {
234
+ d .log .Error ("Metrics collection failed" , "err" , err )
235
+ }
236
+ d .quitChan = nil
233
237
}
234
- d .quitChan = nil
235
-
236
238
return d .db .Close ()
237
239
}
238
240
239
241
// Has retrieves if a key is present in the key-value store.
240
242
func (d * Database ) Has (key []byte ) (bool , error ) {
243
+ d .quitLock .RLock ()
244
+ defer d .quitLock .RUnlock ()
245
+ if d .closed {
246
+ return false , pebble .ErrClosed
247
+ }
241
248
_ , closer , err := d .db .Get (key )
242
249
if err == pebble .ErrNotFound {
243
250
return false , nil
@@ -250,6 +257,11 @@ func (d *Database) Has(key []byte) (bool, error) {
250
257
251
258
// Get retrieves the given key if it's present in the key-value store.
252
259
func (d * Database ) Get (key []byte ) ([]byte , error ) {
260
+ d .quitLock .RLock ()
261
+ defer d .quitLock .RUnlock ()
262
+ if d .closed {
263
+ return nil , pebble .ErrClosed
264
+ }
253
265
dat , closer , err := d .db .Get (key )
254
266
if err != nil {
255
267
return nil , err
@@ -262,19 +274,30 @@ func (d *Database) Get(key []byte) ([]byte, error) {
262
274
263
275
// Put inserts the given value into the key-value store.
264
276
func (d * Database ) Put (key []byte , value []byte ) error {
277
+ d .quitLock .RLock ()
278
+ defer d .quitLock .RUnlock ()
279
+ if d .closed {
280
+ return pebble .ErrClosed
281
+ }
265
282
return d .db .Set (key , value , pebble .NoSync )
266
283
}
267
284
268
285
// Delete removes the key from the key-value store.
269
286
func (d * Database ) Delete (key []byte ) error {
287
+ d .quitLock .RLock ()
288
+ defer d .quitLock .RUnlock ()
289
+ if d .closed {
290
+ return pebble .ErrClosed
291
+ }
270
292
return d .db .Delete (key , nil )
271
293
}
272
294
273
295
// NewBatch creates a write-only key-value store that buffers changes to its host
274
296
// database until a final write is called.
275
297
func (d * Database ) NewBatch () ethdb.Batch {
276
298
return & batch {
277
- b : d .db .NewBatch (),
299
+ b : d .db .NewBatch (),
300
+ db : d ,
278
301
}
279
302
}
280
303
@@ -481,6 +504,7 @@ func (d *Database) meter(refresh time.Duration) {
481
504
// when Write is called. A batch cannot be used concurrently.
482
505
type batch struct {
483
506
b * pebble.Batch
507
+ db * Database
484
508
size int
485
509
}
486
510
@@ -505,6 +529,11 @@ func (b *batch) ValueSize() int {
505
529
506
530
// Write flushes any accumulated data to disk.
507
531
func (b * batch ) Write () error {
532
+ b .db .quitLock .RLock ()
533
+ defer b .db .quitLock .RUnlock ()
534
+ if b .db .closed {
535
+ return pebble .ErrClosed
536
+ }
508
537
return b .b .Commit (pebble .NoSync )
509
538
}
510
539
0 commit comments