|
|
@@ -45,6 +45,13 @@ type batchTx struct {
|
|
|
pending int
|
|
|
}
|
|
|
|
|
|
+var nopLock sync.Locker = &nopLocker{}
|
|
|
+
|
|
|
+type nopLocker struct{}
|
|
|
+
|
|
|
+func (*nopLocker) Lock() {}
|
|
|
+func (*nopLocker) Unlock() {}
|
|
|
+
|
|
|
func (t *batchTx) UnsafeCreateBucket(name []byte) {
|
|
|
_, err := t.tx.CreateBucket(name)
|
|
|
if err != nil && err != bolt.ErrBucketExists {
|
|
|
@@ -81,28 +88,34 @@ func (t *batchTx) unsafePut(bucketName []byte, key []byte, value []byte, seq boo
|
|
|
|
|
|
// UnsafeRange must be called holding the lock on the tx.
|
|
|
func (t *batchTx) UnsafeRange(bucketName, key, endKey []byte, limit int64) ([][]byte, [][]byte) {
|
|
|
- k, v, err := unsafeRange(t.tx, bucketName, key, endKey, limit)
|
|
|
+ // nop lock since a write txn should already hold a lock over t.tx
|
|
|
+ k, v, err := unsafeRange(t.tx, bucketName, key, endKey, limit, nopLock)
|
|
|
if err != nil {
|
|
|
plog.Fatal(err)
|
|
|
}
|
|
|
return k, v
|
|
|
}
|
|
|
|
|
|
-func unsafeRange(tx *bolt.Tx, bucketName, key, endKey []byte, limit int64) (keys [][]byte, vs [][]byte, err error) {
|
|
|
+func unsafeRange(tx *bolt.Tx, bucketName, key, endKey []byte, limit int64, l sync.Locker) (keys [][]byte, vs [][]byte, err error) {
|
|
|
+ l.Lock()
|
|
|
bucket := tx.Bucket(bucketName)
|
|
|
if bucket == nil {
|
|
|
+ l.Unlock()
|
|
|
return nil, nil, fmt.Errorf("bucket %s does not exist", bucketName)
|
|
|
}
|
|
|
if len(endKey) == 0 {
|
|
|
- if v := bucket.Get(key); v != nil {
|
|
|
+ v := bucket.Get(key)
|
|
|
+ l.Unlock()
|
|
|
+ if v != nil {
|
|
|
return append(keys, key), append(vs, v), nil
|
|
|
}
|
|
|
return nil, nil, nil
|
|
|
}
|
|
|
+ c := bucket.Cursor()
|
|
|
+ l.Unlock()
|
|
|
if limit <= 0 {
|
|
|
limit = math.MaxInt64
|
|
|
}
|
|
|
- c := bucket.Cursor()
|
|
|
for ck, cv := c.Seek(key); ck != nil && bytes.Compare(ck, endKey) < 0; ck, cv = c.Next() {
|
|
|
vs = append(vs, cv)
|
|
|
keys = append(keys, ck)
|