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  }