github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/internal/keyspan/level_iter_test.go (about)

     1  // Copyright 2022 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 keyspan
     6  
     7  import (
     8  	"fmt"
     9  	"log"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/require"
    14  	"github.com/zuoyebang/bitalostable/internal/base"
    15  	"github.com/zuoyebang/bitalostable/internal/datadriven"
    16  	"github.com/zuoyebang/bitalostable/internal/manifest"
    17  )
    18  
    19  func TestLevelIterEquivalence(t *testing.T) {
    20  	type level [][]Span
    21  	testCases := []struct {
    22  		name   string
    23  		levels []level
    24  	}{
    25  		{
    26  			"single level, no gaps, no overlaps",
    27  			[]level{
    28  				{
    29  					{
    30  						Span{
    31  							Start: []byte("a"),
    32  							End:   []byte("b"),
    33  							Keys: []Key{{
    34  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
    35  								Suffix:  nil,
    36  								Value:   []byte("foo"),
    37  							}},
    38  						},
    39  						Span{
    40  							Start: []byte("b"),
    41  							End:   []byte("c"),
    42  							Keys: []Key{{
    43  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
    44  								Suffix:  nil,
    45  								Value:   []byte("foo"),
    46  							}},
    47  						},
    48  						Span{
    49  							Start: []byte("c"),
    50  							End:   []byte("d"),
    51  							Keys: []Key{{
    52  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
    53  								Suffix:  nil,
    54  								Value:   []byte("foo"),
    55  							}},
    56  						},
    57  					},
    58  					{
    59  						Span{
    60  							Start: []byte("d"),
    61  							End:   []byte("e"),
    62  							Keys: []Key{{
    63  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
    64  								Suffix:  nil,
    65  								Value:   []byte("foo"),
    66  							}},
    67  						},
    68  						Span{
    69  							Start: []byte("e"),
    70  							End:   []byte("f"),
    71  							Keys: []Key{{
    72  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
    73  								Suffix:  nil,
    74  								Value:   []byte("foo"),
    75  							}},
    76  						},
    77  						Span{
    78  							Start: []byte("f"),
    79  							End:   []byte("g"),
    80  							Keys: []Key{{
    81  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
    82  								Suffix:  nil,
    83  								Value:   []byte("foo"),
    84  							}},
    85  						},
    86  					},
    87  				},
    88  			},
    89  		},
    90  		{
    91  			"single level, overlapping fragments",
    92  			[]level{
    93  				{
    94  					{
    95  						Span{
    96  							Start: []byte("a"),
    97  							End:   []byte("b"),
    98  							Keys: []Key{
    99  								{
   100  									Trailer: base.MakeTrailer(4, base.InternalKeyKindRangeKeySet),
   101  									Suffix:  nil,
   102  									Value:   []byte("bar"),
   103  								},
   104  								{
   105  									Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   106  									Suffix:  nil,
   107  									Value:   []byte("foo"),
   108  								},
   109  							},
   110  						},
   111  						Span{
   112  							Start: []byte("b"),
   113  							End:   []byte("c"),
   114  							Keys: []Key{
   115  								{
   116  									Trailer: base.MakeTrailer(4, base.InternalKeyKindRangeKeySet),
   117  									Suffix:  nil,
   118  									Value:   []byte("bar"),
   119  								},
   120  								{
   121  									Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   122  									Suffix:  nil,
   123  									Value:   []byte("foo"),
   124  								},
   125  							},
   126  						},
   127  						Span{
   128  							Start: []byte("c"),
   129  							End:   []byte("d"),
   130  							Keys: []Key{{
   131  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   132  								Suffix:  nil,
   133  								Value:   []byte("foo"),
   134  							}},
   135  						},
   136  					},
   137  					{
   138  						Span{
   139  							Start: []byte("d"),
   140  							End:   []byte("e"),
   141  							Keys: []Key{{
   142  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   143  								Suffix:  nil,
   144  								Value:   []byte("foo"),
   145  							}},
   146  						},
   147  						Span{
   148  							Start: []byte("e"),
   149  							End:   []byte("f"),
   150  							Keys: []Key{{
   151  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   152  								Suffix:  nil,
   153  								Value:   []byte("foo"),
   154  							}},
   155  						},
   156  						Span{
   157  							Start: []byte("f"),
   158  							End:   []byte("g"),
   159  							Keys: []Key{{
   160  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   161  								Suffix:  nil,
   162  								Value:   []byte("foo"),
   163  							}},
   164  						},
   165  					},
   166  				},
   167  			},
   168  		},
   169  		{
   170  			"single level, gaps between files and range keys",
   171  			[]level{
   172  				{
   173  					{
   174  						Span{
   175  							Start: []byte("a"),
   176  							End:   []byte("b"),
   177  							Keys: []Key{{
   178  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   179  								Suffix:  nil,
   180  								Value:   []byte("foo"),
   181  							}},
   182  						},
   183  						Span{
   184  							Start: []byte("c"),
   185  							End:   []byte("d"),
   186  							Keys: []Key{{
   187  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   188  								Suffix:  nil,
   189  								Value:   []byte("foo"),
   190  							}},
   191  						},
   192  						Span{
   193  							Start: []byte("e"),
   194  							End:   []byte("f"),
   195  							Keys: []Key{{
   196  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   197  								Suffix:  nil,
   198  								Value:   []byte("foo"),
   199  							}},
   200  						},
   201  					},
   202  					{
   203  						Span{
   204  							Start: []byte("g"),
   205  							End:   []byte("h"),
   206  							Keys: []Key{{
   207  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   208  								Suffix:  nil,
   209  								Value:   []byte("foo"),
   210  							}},
   211  						},
   212  						Span{
   213  							Start: []byte("i"),
   214  							End:   []byte("j"),
   215  							Keys: []Key{{
   216  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   217  								Suffix:  nil,
   218  								Value:   []byte("foo"),
   219  							}},
   220  						},
   221  						Span{
   222  							Start: []byte("k"),
   223  							End:   []byte("l"),
   224  							Keys: []Key{{
   225  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   226  								Suffix:  nil,
   227  								Value:   []byte("foo"),
   228  							}},
   229  						},
   230  					},
   231  				},
   232  			},
   233  		},
   234  		{
   235  			"two levels, one with overlapping unset",
   236  			[]level{
   237  				{
   238  					{
   239  						Span{
   240  							Start: []byte("a"),
   241  							End:   []byte("h"),
   242  							Keys: []Key{{
   243  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet),
   244  								Suffix:  nil,
   245  								Value:   []byte("foo"),
   246  							}},
   247  						},
   248  					},
   249  					{
   250  						Span{
   251  							Start: []byte("l"),
   252  							End:   []byte("u"),
   253  							Keys: []Key{{
   254  								Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeyUnset),
   255  								Suffix:  nil,
   256  								Value:   nil,
   257  							}},
   258  						},
   259  					},
   260  				},
   261  				{
   262  					{
   263  						Span{
   264  							Start: []byte("e"),
   265  							End:   []byte("r"),
   266  							Keys: []Key{{
   267  								Trailer: base.MakeTrailer(1, base.InternalKeyKindRangeKeySet),
   268  								Suffix:  nil,
   269  								Value:   []byte("foo"),
   270  							}},
   271  						},
   272  					},
   273  				},
   274  			},
   275  		},
   276  	}
   277  
   278  	for _, tc := range testCases {
   279  		var fileIters []FragmentIterator
   280  		var levelIters []FragmentIterator
   281  		var iter1, iter2 MergingIter
   282  		for j, level := range tc.levels {
   283  			j := j // Copy for use in closures down below.
   284  			var levelIter LevelIter
   285  			var metas []*manifest.FileMetadata
   286  			for k, file := range level {
   287  				fileIters = append(fileIters, NewIter(base.DefaultComparer.Compare, file))
   288  				meta := &manifest.FileMetadata{
   289  					FileNum:          base.FileNum(k + 1),
   290  					Size:             1024,
   291  					SmallestSeqNum:   2,
   292  					LargestSeqNum:    2,
   293  					SmallestRangeKey: base.MakeInternalKey(file[0].Start, file[0].SmallestKey().SeqNum(), file[0].SmallestKey().Kind()),
   294  					LargestRangeKey:  base.MakeExclusiveSentinelKey(file[len(file)-1].LargestKey().Kind(), file[len(file)-1].End),
   295  					HasPointKeys:     false,
   296  					HasRangeKeys:     true,
   297  				}
   298  				meta.ExtendRangeKeyBounds(base.DefaultComparer.Compare, meta.SmallestRangeKey, meta.LargestRangeKey)
   299  				metas = append(metas, meta)
   300  			}
   301  
   302  			tableNewIters := func(file *manifest.FileMetadata, iterOptions *SpanIterOptions) (FragmentIterator, error) {
   303  				return NewIter(base.DefaultComparer.Compare, tc.levels[j][file.FileNum-1]), nil
   304  			}
   305  			// Add all the fileMetadatas to L6.
   306  			b := &manifest.BulkVersionEdit{}
   307  			b.Added[6] = metas
   308  			v, _, err := b.Apply(nil, base.DefaultComparer.Compare, base.DefaultFormatter, 0, 0)
   309  			require.NoError(t, err)
   310  			levelIter.Init(SpanIterOptions{}, base.DefaultComparer.Compare, tableNewIters, v.Levels[6].Iter(), 0, nil, manifest.KeyTypeRange)
   311  			levelIters = append(levelIters, &levelIter)
   312  		}
   313  
   314  		iter1.Init(base.DefaultComparer.Compare, visibleTransform(base.InternalKeySeqNumMax), fileIters...)
   315  		iter2.Init(base.DefaultComparer.Compare, visibleTransform(base.InternalKeySeqNumMax), levelIters...)
   316  		// Check iter1 and iter2 for equivalence.
   317  
   318  		require.Equal(t, iter1.First(), iter2.First(), "failed on test case %q", tc.name)
   319  		valid := true
   320  		for valid {
   321  			f1 := iter1.Next()
   322  			var f2 *Span
   323  			for {
   324  				f2 = iter2.Next()
   325  				// The level iter could produce empty spans that straddle between
   326  				// files. Ignore those.
   327  				if f2 == nil || !f2.Empty() {
   328  					break
   329  				}
   330  			}
   331  
   332  			require.Equal(t, f1, f2, "failed on test case %q", tc.name)
   333  			valid = f1 != nil && f2 != nil
   334  		}
   335  	}
   336  }
   337  
   338  type testLogger struct {
   339  	t *testing.T
   340  }
   341  
   342  // Infof implements the Logger.Infof interface.
   343  func (t *testLogger) Infof(format string, args ...interface{}) {
   344  	_ = log.Output(2, fmt.Sprintf(format, args...))
   345  }
   346  
   347  // Fatalf implements the Logger.Fatalf interface.
   348  func (t *testLogger) Fatalf(format string, args ...interface{}) {
   349  	_ = log.Output(2, fmt.Sprintf(format, args...))
   350  	t.t.Fail()
   351  }
   352  
   353  func TestLevelIter(t *testing.T) {
   354  	var level [][]Span
   355  	var rangedels [][]Span
   356  	var metas []*manifest.FileMetadata
   357  	var iter FragmentIterator
   358  	var extraInfo func() string
   359  
   360  	datadriven.RunTest(t, "testdata/level_iter", func(d *datadriven.TestData) string {
   361  		switch d.Cmd {
   362  		case "define":
   363  			level = level[:0]
   364  			metas = metas[:0]
   365  			rangedels = rangedels[:0]
   366  			if iter != nil {
   367  				iter.Close()
   368  				iter = nil
   369  			}
   370  			var pointKeys []base.InternalKey
   371  			var currentRangeDels []Span
   372  			var currentFile []Span
   373  			for _, key := range strings.Split(d.Input, "\n") {
   374  				if strings.HasPrefix(key, "file") {
   375  					// Skip the very first file creation.
   376  					if len(level) != 0 || len(currentFile) != 0 {
   377  						meta := &manifest.FileMetadata{
   378  							FileNum: base.FileNum(len(level) + 1),
   379  						}
   380  						if len(currentFile) > 0 {
   381  							smallest := base.MakeInternalKey(currentFile[0].Start, currentFile[0].SmallestKey().SeqNum(), currentFile[0].SmallestKey().Kind())
   382  							largest := base.MakeExclusiveSentinelKey(currentFile[len(currentFile)-1].LargestKey().Kind(), currentFile[len(currentFile)-1].End)
   383  							meta.ExtendRangeKeyBounds(base.DefaultComparer.Compare, smallest, largest)
   384  						}
   385  						if len(pointKeys) != 0 {
   386  							meta.ExtendPointKeyBounds(base.DefaultComparer.Compare, pointKeys[0], pointKeys[len(pointKeys)-1])
   387  						}
   388  						level = append(level, currentFile)
   389  						metas = append(metas, meta)
   390  						rangedels = append(rangedels, currentRangeDels)
   391  						currentRangeDels = nil
   392  						currentFile = nil
   393  						pointKeys = nil
   394  					}
   395  					continue
   396  				}
   397  				key = strings.TrimSpace(key)
   398  				if strings.HasPrefix(key, "point:") {
   399  					key = strings.TrimPrefix(key, "point:")
   400  					j := strings.Index(key, ":")
   401  					ikey := base.ParseInternalKey(key[:j])
   402  					pointKeys = append(pointKeys, ikey)
   403  					if ikey.Kind() == base.InternalKeyKindRangeDelete {
   404  						currentRangeDels = append(currentRangeDels, Span{
   405  							Start: ikey.UserKey, End: []byte(key[j+1:]), Keys: []Key{{Trailer: ikey.Trailer}}})
   406  					}
   407  					continue
   408  				}
   409  				span := ParseSpan(key)
   410  				currentFile = append(currentFile, span)
   411  			}
   412  			meta := &manifest.FileMetadata{
   413  				FileNum: base.FileNum(len(level) + 1),
   414  			}
   415  			level = append(level, currentFile)
   416  			rangedels = append(rangedels, currentRangeDels)
   417  			if len(currentFile) > 0 {
   418  				smallest := base.MakeInternalKey(currentFile[0].Start, currentFile[0].SmallestKey().SeqNum(), currentFile[0].SmallestKey().Kind())
   419  				largest := base.MakeExclusiveSentinelKey(currentFile[len(currentFile)-1].LargestKey().Kind(), currentFile[len(currentFile)-1].End)
   420  				meta.ExtendRangeKeyBounds(base.DefaultComparer.Compare, smallest, largest)
   421  			}
   422  			if len(pointKeys) != 0 {
   423  				meta.ExtendPointKeyBounds(base.DefaultComparer.Compare, pointKeys[0], pointKeys[len(pointKeys)-1])
   424  			}
   425  			metas = append(metas, meta)
   426  			return ""
   427  		case "num-files":
   428  			return fmt.Sprintf("%d", len(level))
   429  		case "close-iter":
   430  			_ = iter.Close()
   431  			iter = nil
   432  			return "ok"
   433  		case "iter":
   434  			keyType := manifest.KeyTypeRange
   435  			for _, arg := range d.CmdArgs {
   436  				if strings.Contains(arg.Key, "rangedel") {
   437  					keyType = manifest.KeyTypePoint
   438  				}
   439  			}
   440  			if iter == nil {
   441  				var lastFileNum base.FileNum
   442  				tableNewIters := func(file *manifest.FileMetadata, iterOptions *SpanIterOptions) (FragmentIterator, error) {
   443  					keyType := keyType
   444  					spans := level[file.FileNum-1]
   445  					if keyType == manifest.KeyTypePoint {
   446  						spans = rangedels[file.FileNum-1]
   447  					}
   448  					lastFileNum = file.FileNum
   449  					return NewIter(base.DefaultComparer.Compare, spans), nil
   450  				}
   451  				b := &manifest.BulkVersionEdit{}
   452  				b.Added[6] = metas
   453  				v, _, err := b.Apply(nil, base.DefaultComparer.Compare, base.DefaultFormatter, 0, 0)
   454  				require.NoError(t, err)
   455  				iter = newLevelIter(SpanIterOptions{}, base.DefaultComparer.Compare, tableNewIters, v.Levels[6].Iter(), 6, &testLogger{t}, keyType)
   456  				extraInfo = func() string {
   457  					return fmt.Sprintf("file = %s.sst", lastFileNum)
   458  				}
   459  			}
   460  
   461  			return runFragmentIteratorCmd(iter, d.Input, extraInfo)
   462  
   463  		default:
   464  			return fmt.Sprintf("unknown command: %s", d.Cmd)
   465  		}
   466  	})
   467  
   468  	if iter != nil {
   469  		iter.Close()
   470  	}
   471  }