Skip to content

Commit 9d46366

Browse files
NamanJain8Ibrahim Jarif
authored andcommitted
Update head while replaying value log (hypermodeinc#1372) (hypermodeinc#1506)
Fixes hypermodeinc#1363 The head pointer is not updated when we perform replays. The head pointer would be updated only when the replay completes. If badger crashes between the point when replay started and replay finished, we would end up replaying all the value log files. This PR fixes this issue. (cherry picked from commit 509de73) Co-authored-by: Ibrahim Jarif <[email protected]>
1 parent 94eaa4a commit 9d46366

File tree

2 files changed

+16
-7
lines changed

2 files changed

+16
-7
lines changed

db.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ func (db *DB) replayFunction() func(Entry, valuePointer) error {
136136
nv = make([]byte, vptrSize)
137137
vp.Encode(nv)
138138
meta = meta | bitValuePointer
139+
// Update vhead. If the crash happens while replay was in progess
140+
// and the head is not updated, we will end up replaying all the
141+
// files again.
142+
db.updateHead([]valuePointer{vp})
139143
}
140144

141145
v := y.ValueStruct{
@@ -550,6 +554,8 @@ func (db *DB) get(key []byte) (y.ValueStruct, error) {
550554
return db.lc.get(key, maxVs)
551555
}
552556

557+
// updateHead should not be called without the db.Lock() since db.vhead is used
558+
// by the writer go routines and memtable flushing goroutine.
553559
func (db *DB) updateHead(ptrs []valuePointer) {
554560
var ptr valuePointer
555561
for i := len(ptrs) - 1; i >= 0; i-- {
@@ -563,8 +569,6 @@ func (db *DB) updateHead(ptrs []valuePointer) {
563569
return
564570
}
565571

566-
db.Lock()
567-
defer db.Unlock()
568572
y.AssertTrue(!ptr.Less(db.vhead))
569573
db.vhead = ptr
570574
}
@@ -662,7 +666,9 @@ func (db *DB) writeRequests(reqs []*request) error {
662666
done(err)
663667
return errors.Wrap(err, "writeRequests")
664668
}
669+
db.Lock()
665670
db.updateHead(b.Ptrs)
671+
db.Unlock()
666672
}
667673
done(nil)
668674
db.elog.Printf("%d entries written", count)

value_test.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,6 @@ func TestValueGC4(t *testing.T) {
364364

365365
kv, err := Open(opt)
366366
require.NoError(t, err)
367-
defer kv.Close()
368367

369368
sz := 128 << 10 // 5 entries per value log file.
370369
txn := kv.NewTransaction(true)
@@ -403,11 +402,9 @@ func TestValueGC4(t *testing.T) {
403402
kv.vlog.rewrite(lf0, tr)
404403
kv.vlog.rewrite(lf1, tr)
405404

406-
err = kv.vlog.Close()
407-
require.NoError(t, err)
405+
require.NoError(t, kv.Close())
408406

409-
kv.vlog.init(kv)
410-
err = kv.vlog.open(kv, valuePointer{Fid: 2}, kv.replayFunction())
407+
kv, err = Open(opt)
411408
require.NoError(t, err)
412409

413410
for i := 0; i < 8; i++ {
@@ -429,6 +426,7 @@ func TestValueGC4(t *testing.T) {
429426
return nil
430427
}))
431428
}
429+
require.NoError(t, kv.Close())
432430
}
433431

434432
func TestPersistLFDiscardStats(t *testing.T) {
@@ -638,6 +636,11 @@ func TestPartialAppendToValueLog(t *testing.T) {
638636
// Replay value log from beginning, badger head is past k2.
639637
require.NoError(t, kv.vlog.Close())
640638

639+
// clean up the current db.vhead so that we can replay from the beginning.
640+
// If we don't clear the current vhead, badger will error out since new
641+
// head passed while opening vlog is zero in the following lines.
642+
kv.vhead = valuePointer{}
643+
641644
kv.vlog.init(kv)
642645
require.NoError(
643646
t, kv.vlog.open(kv, valuePointer{Fid: 0}, kv.replayFunction()),

0 commit comments

Comments
 (0)