Skip to content

Commit 63d9309

Browse files
author
Ibrahim Jarif
authored
Revert "fix: Fix race condition in block.incRef (#1337)" (#1407)
This reverts commit 21735af. The commit is reverted because we have seen some crashes which could be caused by this change. We haven't been able to reproduce the crashes yet. Related to #1389, #1388, #1387 Also, see https://discuss.dgraph.io/t/current-state-of-badger-crashes/7602
1 parent e0d058c commit 63d9309

File tree

3 files changed

+13
-70
lines changed

3 files changed

+13
-70
lines changed

badger/cmd/bank.go

+3-26
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func toSlice(bal uint64) []byte {
125125
}
126126

127127
func getBalance(txn *badger.Txn, account int) (uint64, error) {
128-
item, err := get(txn, key(account))
128+
item, err := txn.Get(key(account))
129129
if err != nil {
130130
return 0, err
131131
}
@@ -197,33 +197,14 @@ func diff(a, b []account) string {
197197

198198
var errFailure = errors.New("test failed due to balance mismatch")
199199

200-
// get function will fetch the value for the key "k" either by using the
201-
// txn.Get API or the iterator.Seek API.
202-
func get(txn *badger.Txn, k []byte) (*badger.Item, error) {
203-
if rand.Int()%2 == 0 {
204-
return txn.Get(k)
205-
}
206-
207-
iopt := badger.DefaultIteratorOptions
208-
// PrefectValues is expensive. We don't need it here.
209-
iopt.PrefetchValues = false
210-
it := txn.NewIterator(iopt)
211-
defer it.Close()
212-
it.Seek(k)
213-
if it.Valid() {
214-
return it.Item(), nil
215-
}
216-
return nil, badger.ErrKeyNotFound
217-
}
218-
219200
// seekTotal retrives the total of all accounts by seeking for each account key.
220201
func seekTotal(txn *badger.Txn) ([]account, error) {
221202
expected := uint64(numAccounts) * uint64(initialBal)
222203
var accounts []account
223204

224205
var total uint64
225206
for i := 0; i < numAccounts; i++ {
226-
item, err := get(txn, key(i))
207+
item, err := txn.Get(key(i))
227208
if err != nil {
228209
log.Printf("Error for account: %d. err=%v. key=%q\n", i, err, key(i))
229210
return accounts, err
@@ -362,11 +343,7 @@ func runTest(cmd *cobra.Command, args []string) error {
362343
WithNumMemtables(2).
363344
// Do not GC any versions, because we need them for the disect..
364345
WithNumVersionsToKeep(int(math.MaxInt32)).
365-
WithValueThreshold(1). // Make all values go to value log
366-
WithCompression(options.ZSTD).
367-
WithKeepL0InMemory(false).
368-
WithMaxCacheSize(10 << 20)
369-
346+
WithValueThreshold(1) // Make all values go to value log
370347
if mmap {
371348
opts = opts.WithTableLoadingMode(options.MemoryMap)
372349
}

table/iterator.go

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ func (itr *blockIterator) setBlock(b *block) {
4444
// Decrement the ref for the old block. If the old block was compressed, we
4545
// might be able to reuse it.
4646
itr.block.decrRef()
47+
// Increment the ref for the new block.
48+
b.incrRef()
4749

4850
itr.block = b
4951
itr.err = nil

table/table.go

+8-44
Original file line numberDiff line numberDiff line change
@@ -202,46 +202,25 @@ type block struct {
202202
ref int32
203203
}
204204

205-
// incrRef increments the ref of a block and return a bool indicating if the
206-
// increment was successful. A true value indicates that the block can be used.
207-
func (b *block) incrRef() bool {
208-
for {
209-
// We can't blindly add 1 to ref. We need to check whether it has
210-
// reached zero first, because if it did, then we should absolutely not
211-
// use this block.
212-
ref := atomic.LoadInt32(&b.ref)
213-
// The ref would not be equal to 0 unless the existing
214-
// block get evicted before this line. If the ref is zero, it means that
215-
// the block is already added the the blockPool and cannot be used
216-
// anymore. The ref of a new block is 1 so the following condition will
217-
// be true only if the block got reused before we could increment its
218-
// ref.
219-
if ref == 0 {
220-
return false
221-
}
222-
// Increment the ref only if it is not zero and has not changed between
223-
// the time we read it and we're updating it.
224-
//
225-
if atomic.CompareAndSwapInt32(&b.ref, ref, ref+1) {
226-
return true
227-
}
228-
}
205+
func (b *block) incrRef() {
206+
atomic.AddInt32(&b.ref, 1)
229207
}
230208
func (b *block) decrRef() {
231209
if b == nil {
232210
return
233211
}
234212

213+
p := atomic.AddInt32(&b.ref, -1)
235214
// Insert the []byte into pool only if the block is resuable. When a block
236215
// is reusable a new []byte is used for decompression and this []byte can
237216
// be reused.
238217
// In case of an uncompressed block, the []byte is a reference to the
239218
// table.mmap []byte slice. Any attempt to write data to the mmap []byte
240219
// will lead to SEGFAULT.
241-
if atomic.AddInt32(&b.ref, -1) == 0 && b.isReusable {
220+
if p == 0 && b.isReusable {
242221
blockPool.Put(&b.data)
243222
}
244-
y.AssertTrue(atomic.LoadInt32(&b.ref) >= 0)
223+
y.AssertTrue(p >= 0)
245224
}
246225
func (b *block) size() int64 {
247226
return int64(3*intSize /* Size of the offset, entriesIndexStart and chkLen */ +
@@ -499,9 +478,6 @@ func calculateOffsetsSize(offsets []*pb.BlockOffset) int64 {
499478
return totalSize + 3*8
500479
}
501480

502-
// block function return a new block. Each block holds a ref and the byte
503-
// slice stored in the block will be reused when the ref becomes zero. The
504-
// caller should release the block by calling block.decrRef() on it.
505481
func (t *Table) block(idx int) (*block, error) {
506482
y.AssertTruef(idx >= 0, "idx=%d", idx)
507483
if idx >= t.noOfBlocks {
@@ -511,20 +487,14 @@ func (t *Table) block(idx int) (*block, error) {
511487
key := t.blockCacheKey(idx)
512488
blk, ok := t.opt.Cache.Get(key)
513489
if ok && blk != nil {
514-
// Use the block only if the increment was successful. The block
515-
// could get evicted from the cache between the Get() call and the
516-
// incrRef() call.
517-
if b := blk.(*block); b.incrRef() {
518-
return b, nil
519-
}
490+
return blk.(*block), nil
520491
}
521492
}
522493

523494
// Read the block index if it's nil
524495
ko := t.blockOffsets()[idx]
525496
blk := &block{
526497
offset: int(ko.Offset),
527-
ref: 1,
528498
}
529499
var err error
530500
if blk.data, err = t.read(blk.offset, int(ko.Len)); err != nil {
@@ -581,14 +551,8 @@ func (t *Table) block(idx int) (*block, error) {
581551
}
582552
if t.opt.Cache != nil && t.opt.KeepBlocksInCache {
583553
key := t.blockCacheKey(idx)
584-
// incrRef should never return false here because we're calling it on a
585-
// new block with ref=1.
586-
y.AssertTrue(blk.incrRef())
587-
588-
// Decrement the block ref if we could not insert it in the cache.
589-
if !t.opt.Cache.Set(key, blk, blk.size()) {
590-
blk.decrRef()
591-
}
554+
blk.incrRef()
555+
t.opt.Cache.Set(key, blk, blk.size())
592556
}
593557
return blk, nil
594558
}

0 commit comments

Comments
 (0)