github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/compaction_iter_test.go (about) 1 // Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package pebble 6 7 import ( 8 "bytes" 9 "fmt" 10 "sort" 11 "strconv" 12 "strings" 13 "testing" 14 15 "github.com/petermattis/pebble/internal/base" 16 "github.com/petermattis/pebble/internal/datadriven" 17 ) 18 19 func TestSnapshotIndex(t *testing.T) { 20 testCases := []struct { 21 snapshots []uint64 22 seq uint64 23 expectedIndex int 24 expectedSeqNum uint64 25 }{ 26 {[]uint64{}, 1, 0, InternalKeySeqNumMax}, 27 {[]uint64{1}, 0, 0, 1}, 28 {[]uint64{1}, 1, 1, InternalKeySeqNumMax}, 29 {[]uint64{1}, 2, 1, InternalKeySeqNumMax}, 30 {[]uint64{1, 3}, 1, 1, 3}, 31 {[]uint64{1, 3}, 2, 1, 3}, 32 {[]uint64{1, 3}, 3, 2, InternalKeySeqNumMax}, 33 {[]uint64{1, 3}, 4, 2, InternalKeySeqNumMax}, 34 {[]uint64{1, 3, 3}, 2, 1, 3}, 35 } 36 for _, c := range testCases { 37 t.Run("", func(t *testing.T) { 38 idx, seqNum := snapshotIndex(c.seq, c.snapshots) 39 if c.expectedIndex != idx { 40 t.Fatalf("expected %d, but got %d", c.expectedIndex, idx) 41 } 42 if c.expectedSeqNum != seqNum { 43 t.Fatalf("expected %d, but got %d", c.expectedSeqNum, seqNum) 44 } 45 }) 46 } 47 } 48 49 func TestCompactionIter(t *testing.T) { 50 var keys []InternalKey 51 var vals [][]byte 52 var snapshots []uint64 53 var elideTombstones bool 54 55 newIter := func() *compactionIter { 56 return newCompactionIter( 57 DefaultComparer.Compare, 58 DefaultMerger.Merge, 59 &fakeIter{keys: keys, vals: vals}, 60 snapshots, 61 false, /* allowZeroSeqNum */ 62 func([]byte) bool { 63 return elideTombstones 64 }, 65 func(_, _ []byte) bool { 66 return elideTombstones 67 }, 68 ) 69 } 70 71 datadriven.RunTest(t, "testdata/compaction_iter", func(d *datadriven.TestData) string { 72 switch d.Cmd { 73 case "define": 74 keys = keys[:0] 75 vals = vals[:0] 76 for _, key := range strings.Split(d.Input, "\n") { 77 j := strings.Index(key, ":") 78 keys = append(keys, base.ParseInternalKey(key[:j])) 79 vals = append(vals, []byte(key[j+1:])) 80 } 81 return "" 82 83 case "iter": 84 snapshots = snapshots[:0] 85 elideTombstones = false 86 for _, arg := range d.CmdArgs { 87 switch arg.Key { 88 case "snapshots": 89 for _, val := range arg.Vals { 90 seqNum, err := strconv.Atoi(val) 91 if err != nil { 92 return err.Error() 93 } 94 snapshots = append(snapshots, uint64(seqNum)) 95 } 96 case "elide-tombstones": 97 var err error 98 elideTombstones, err = strconv.ParseBool(arg.Vals[0]) 99 if err != nil { 100 return err.Error() 101 } 102 default: 103 return fmt.Sprintf("%s: unknown arg: %s", d.Cmd, arg.Key) 104 } 105 } 106 sort.Slice(snapshots, func(i, j int) bool { 107 return snapshots[i] < snapshots[j] 108 }) 109 110 iter := newIter() 111 var b bytes.Buffer 112 for _, line := range strings.Split(d.Input, "\n") { 113 parts := strings.Fields(line) 114 if len(parts) == 0 { 115 continue 116 } 117 switch parts[0] { 118 case "first": 119 iter.First() 120 case "next": 121 iter.Next() 122 case "tombstones": 123 var key []byte 124 if len(parts) == 2 { 125 key = []byte(parts[1]) 126 } 127 for _, v := range iter.Tombstones(key) { 128 fmt.Fprintf(&b, "%s-%s#%d\n", 129 v.Start.UserKey, v.End, v.Start.SeqNum()) 130 } 131 fmt.Fprintf(&b, ".\n") 132 continue 133 default: 134 return fmt.Sprintf("unknown op: %s", parts[0]) 135 } 136 if iter.Valid() { 137 fmt.Fprintf(&b, "%s:%s\n", iter.Key(), iter.Value()) 138 } else if err := iter.Error(); err != nil { 139 fmt.Fprintf(&b, "err=%v\n", err) 140 } else { 141 fmt.Fprintf(&b, ".\n") 142 } 143 } 144 return b.String() 145 146 default: 147 return fmt.Sprintf("unknown command: %s", d.Cmd) 148 } 149 }) 150 }