Prevent crash in rocks_db on access after closure
@@ -39,6 +39,8 @@ const (
RocksDBBackend BackendType = "rocksdb"
)
+var ErrAlreadyClosed = errors.New("AlreadyClosed")
+
func init() {
dbCreator := func(name string, dir string) (Database, error) {
return NewRocksDB(name, dir)
@@ -47,7 +49,7 @@ func init() {
}
type RocksDB struct {
- lock sync.Mutex
+ lock sync.RWMutex
buckets map[BucketID]*RocksBucket
db *C.rocksdb_t
@@ -143,10 +145,17 @@ func NewRocksDB(name string, dir string) (*RocksDB, error) {
}
func (db *RocksDB) Close() error {
+ db.lock.Lock()
+ defer db.lock.Unlock()
+
+ if db.db == nil {
+ return ErrAlreadyClosed
+ }
for _, bk := range db.buckets {
C.rocksdb_column_family_handle_destroy(bk.cf)
}
C.rocksdb_close(db.db)
+ db.db = nil
return nil
}
@@ -154,6 +163,10 @@ func (db *RocksDB) GetBucket(id BucketID) (Bucket, error) {
db.lock.Lock()
defer db.lock.Unlock()
+ if db.db == nil {
+ return nil, ErrAlreadyClosed
+ }
+
if bk, ok := db.buckets[id]; ok {
return bk, nil
}
@@ -179,6 +192,12 @@ func (db *RocksDB) GetBucket(id BucketID) (Bucket, error) {
}
func (db *RocksDB) getValue(cf *C.rocksdb_column_family_handle_t, k []byte) ([]byte, error) {
+ db.lock.RLock()
+ defer db.lock.RUnlock()
+
+ if db.db == nil {
+ return nil, ErrAlreadyClosed
+ }
var (
cErr *C.char
cValLen C.size_t
@@ -202,6 +221,12 @@ func (db *RocksDB) getValue(cf *C.rocksdb_column_family_handle_t, k []byte) ([]b
}
func (db *RocksDB) hasValue(cf *C.rocksdb_column_family_handle_t, k []byte) (bool, error) {
+ db.lock.RLock()
+ defer db.lock.RUnlock()
+
+ if db.db == nil {
+ return false, ErrAlreadyClosed
+ }
var (
cErr *C.char
cValLen C.size_t
@@ -217,6 +242,12 @@ func (db *RocksDB) hasValue(cf *C.rocksdb_column_family_handle_t, k []byte) (boo
}
func (db *RocksDB) setValue(cf *C.rocksdb_column_family_handle_t, k, v []byte) error {
+ db.lock.RLock()
+ defer db.lock.RUnlock()
+
+ if db.db == nil {
+ return ErrAlreadyClosed
+ }
var (
cErr *C.char
cKey = (*C.char)(unsafe.Pointer(&k[0]))
@@ -234,6 +265,12 @@ func (db *RocksDB) setValue(cf *C.rocksdb_column_family_handle_t, k, v []byte) e
}
func (db *RocksDB) deleteValue(cf *C.rocksdb_column_family_handle_t, k []byte) error {
+ db.lock.RLock()
+ defer db.lock.RUnlock()
+
+ if db.db == nil {
+ return ErrAlreadyClosed
+ }
var (
cErr *C.char
cKey = (*C.char)(unsafe.Pointer(&k[0]))
