Skip to content

Commit 98b8f4a

Browse files
committed
Merge pull request #4601 from nvanbenschoten/nvanbenschoten/mvccgc
storage/engine: Correctly handle inlined keys in MVCCGarbageCollect
2 parents 9037405 + 9ec3933 commit 98b8f4a

File tree

2 files changed

+54
-23
lines changed

2 files changed

+54
-23
lines changed

storage/engine/mvcc.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,23 +1632,29 @@ func MVCCGarbageCollect(engine Engine, ms *MVCCStats, keys []roachpb.GCRequest_G
16321632
return err
16331633
}
16341634
if !ok {
1635-
return util.Errorf("could not seek to key %q", gcKey.Key)
1635+
continue
16361636
}
1637+
inlinedValue := meta.IsInline()
16371638
implicitMeta := iter.Key().IsValue()
16381639
// First, check whether all values of the key are being deleted.
16391640
if !gcKey.Timestamp.Less(meta.Timestamp) {
16401641
// For version keys, don't allow GC'ing the meta key if it's
16411642
// not marked deleted. However, for inline values we allow it;
16421643
// they are internal and GCing them directly saves the extra
16431644
// deletion step.
1644-
if !meta.Deleted && !gcKey.Timestamp.Equal(roachpb.ZeroTimestamp) {
1645+
if !meta.Deleted && !inlinedValue {
16451646
return util.Errorf("request to GC non-deleted, latest value of %q", gcKey.Key)
16461647
}
16471648
if meta.Txn != nil {
16481649
return util.Errorf("request to GC intent at %q", gcKey.Key)
16491650
}
16501651
if ms != nil {
1651-
ms.Add(updateStatsOnGC(gcKey.Key, metaKeySize, metaValSize, meta, meta.Timestamp.WallTime, timestamp.WallTime))
1652+
if inlinedValue {
1653+
updateStatsForInline(ms, gcKey.Key, metaKeySize, metaValSize, 0, 0)
1654+
ms.AgeTo(timestamp.WallTime)
1655+
} else {
1656+
ms.Add(updateStatsOnGC(gcKey.Key, metaKeySize, metaValSize, meta, meta.Timestamp.WallTime, timestamp.WallTime))
1657+
}
16521658
}
16531659
if !implicitMeta {
16541660
if err := engine.Clear(iter.Key()); err != nil {

storage/engine/mvcc_test.go

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2645,6 +2645,7 @@ func TestMVCCGarbageCollect(t *testing.T) {
26452645
val1 := roachpb.MakeValueFromBytesAndTimestamp(bytes, ts1)
26462646
val2 := roachpb.MakeValueFromBytesAndTimestamp(bytes, ts2)
26472647
val3 := roachpb.MakeValueFromBytesAndTimestamp(bytes, ts3)
2648+
valInline := roachpb.MakeValueFromBytesAndTimestamp(bytes, roachpb.ZeroTimestamp)
26482649

26492650
testData := []struct {
26502651
key roachpb.Key
@@ -2655,6 +2656,7 @@ func TestMVCCGarbageCollect(t *testing.T) {
26552656
{roachpb.Key("a-del"), []roachpb.Value{val1, val2}, true},
26562657
{roachpb.Key("b"), []roachpb.Value{val1, val2, val3}, false},
26572658
{roachpb.Key("b-del"), []roachpb.Value{val1, val2, val3}, true},
2659+
{roachpb.Key("inline"), []roachpb.Value{valInline}, false},
26582660
}
26592661

26602662
for i := 0; i < 3; i++ {
@@ -2677,12 +2679,12 @@ func TestMVCCGarbageCollect(t *testing.T) {
26772679
}
26782680
}
26792681
}
2680-
kvsn, err := Scan(engine, mvccKey(keyMin), mvccKey(keyMax), 0)
2681-
if err != nil {
2682-
t.Fatal(err)
2683-
}
2684-
for i, kv := range kvsn {
2685-
if log.V(1) {
2682+
if log.V(1) {
2683+
kvsn, err := Scan(engine, mvccKey(keyMin), mvccKey(keyMax), 0)
2684+
if err != nil {
2685+
t.Fatal(err)
2686+
}
2687+
for i, kv := range kvsn {
26862688
log.Infof("%d: %s", i, kv.Key)
26872689
}
26882690
}
@@ -2692,6 +2694,10 @@ func TestMVCCGarbageCollect(t *testing.T) {
26922694
{Key: roachpb.Key("a-del"), Timestamp: ts2},
26932695
{Key: roachpb.Key("b"), Timestamp: ts1},
26942696
{Key: roachpb.Key("b-del"), Timestamp: ts2},
2697+
{Key: roachpb.Key("inline"), Timestamp: roachpb.ZeroTimestamp},
2698+
// Keys that don't exist, which should result in a no-op.
2699+
{Key: roachpb.Key("a-bad"), Timestamp: ts2},
2700+
{Key: roachpb.Key("inline-bad"), Timestamp: roachpb.ZeroTimestamp},
26952701
}
26962702
if err := MVCCGarbageCollect(engine, ms, keys, ts3); err != nil {
26972703
t.Fatal(err)
@@ -2761,21 +2767,40 @@ func TestMVCCGarbageCollectNonDeleted(t *testing.T) {
27612767
ts2 := makeTS(2E9, 0)
27622768
val1 := mkVal(s, ts1)
27632769
val2 := mkVal(s, ts2)
2764-
key := roachpb.Key("a")
2765-
vals := []roachpb.Value{val1, val2}
2766-
for _, val := range vals {
2767-
valCpy := *util.CloneProto(&val).(*roachpb.Value)
2768-
valCpy.Timestamp = roachpb.ZeroTimestamp
2769-
if err := MVCCPut(engine, nil, key, val.Timestamp, valCpy, nil); err != nil {
2770-
t.Fatal(err)
2771-
}
2772-
}
2773-
keys := []roachpb.GCRequest_GCKey{
2774-
{Key: roachpb.Key("a"), Timestamp: ts2},
2770+
valInline := mkVal(s, roachpb.ZeroTimestamp)
2771+
2772+
testData := []struct {
2773+
key roachpb.Key
2774+
vals []roachpb.Value
2775+
expError string
2776+
}{
2777+
{roachpb.Key("a"), []roachpb.Value{val1, val2}, `request to GC non-deleted, latest value ok "a"`},
2778+
{roachpb.Key("inline"), []roachpb.Value{valInline}, ""},
27752779
}
2776-
if err := MVCCGarbageCollect(engine, nil, keys, ts2); err == nil {
2777-
t.Fatal("expected error garbage collecting a non-deleted live value")
2780+
2781+
for _, test := range testData {
2782+
for _, val := range test.vals {
2783+
valCpy := *util.CloneProto(&val).(*roachpb.Value)
2784+
valCpy.Timestamp = roachpb.ZeroTimestamp
2785+
if err := MVCCPut(engine, nil, test.key, val.Timestamp, valCpy, nil); err != nil {
2786+
t.Fatal(err)
2787+
}
2788+
}
2789+
keys := []roachpb.GCRequest_GCKey{
2790+
{Key: test.key, Timestamp: ts2},
2791+
}
2792+
err := MVCCGarbageCollect(engine, nil, keys, ts2)
2793+
if test.expError == "" {
2794+
if err != nil {
2795+
t.Fatalf("expected no error garbage collecting a non-deleted inline live value, found %v", err)
2796+
}
2797+
} else {
2798+
if testutils.IsError(err, test.expError) {
2799+
t.Fatalf("expected error %q when garbage collecting a non-deleted live value, found %v", test.expError, err)
2800+
}
2801+
}
27782802
}
2803+
27792804
}
27802805

27812806
// TestMVCCGarbageCollectIntent verifies that an intent cannot be GC'd.
@@ -2800,7 +2825,7 @@ func TestMVCCGarbageCollectIntent(t *testing.T) {
28002825
t.Fatal(err)
28012826
}
28022827
keys := []roachpb.GCRequest_GCKey{
2803-
{Key: roachpb.Key("a"), Timestamp: ts2},
2828+
{Key: key, Timestamp: ts2},
28042829
}
28052830
if err := MVCCGarbageCollect(engine, nil, keys, ts2); err == nil {
28062831
t.Fatal("expected error garbage collecting an intent")

0 commit comments

Comments
 (0)