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

     1  // Copyright 2018 The LevelDB-Go and Pebble and Bitalostored 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 bitalostable
     6  
     7  import (
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/cockroachdb/errors"
    12  	"github.com/zuoyebang/bitalostable/internal/base"
    13  	"github.com/zuoyebang/bitalostable/internal/keyspan"
    14  	"github.com/zuoyebang/bitalostable/internal/manifest"
    15  	"github.com/zuoyebang/bitalostable/internal/testkeys"
    16  )
    17  
    18  func TestGetIter(t *testing.T) {
    19  	// testTable is a table to insert into a version.
    20  	// Each element of data is a string of the form "internalKey value".
    21  	type testTable struct {
    22  		level   int
    23  		fileNum FileNum
    24  		data    []string
    25  	}
    26  
    27  	testCases := []struct {
    28  		description string
    29  		// badOrdering is whether this test case has a table ordering violation.
    30  		badOrdering bool
    31  		// tables are the tables to populate the version with.
    32  		tables []testTable
    33  		// queries are the queries to run against the version. Each element has
    34  		// the form "internalKey wantedValue". The internalKey is passed to the
    35  		// version.get method, wantedValue may be "ErrNotFound" if the query
    36  		// should return that error.
    37  		queries []string
    38  	}{
    39  		{
    40  			description: "empty: an empty version",
    41  			queries: []string{
    42  				"abc.SEPARATOR.101 ErrNotFound",
    43  			},
    44  		},
    45  
    46  		{
    47  			description: "single-0: one level-0 table",
    48  			tables: []testTable{
    49  				{
    50  					level:   0,
    51  					fileNum: 10,
    52  					data: []string{
    53  						"the.SET.101 a",
    54  						"cat.SET.102 b",
    55  						"on_.SET.103 c",
    56  						"the.SET.104 d",
    57  						"mat.SET.105 e",
    58  						"the.DEL.106 ",
    59  						"the.MERGE.107 g",
    60  					},
    61  				},
    62  			},
    63  			queries: []string{
    64  				"aaa.SEPARATOR.105 ErrNotFound",
    65  				"cat.SEPARATOR.105 b",
    66  				"hat.SEPARATOR.105 ErrNotFound",
    67  				"mat.SEPARATOR.105 e",
    68  				"the.SEPARATOR.108 g",
    69  				"the.SEPARATOR.107 g",
    70  				"the.SEPARATOR.106 ErrNotFound",
    71  				"the.SEPARATOR.105 d",
    72  				"the.SEPARATOR.104 d",
    73  				"the.SEPARATOR.104 d",
    74  				"the.SEPARATOR.103 a",
    75  				"the.SEPARATOR.102 a",
    76  				"the.SEPARATOR.101 a",
    77  				"the.SEPARATOR.100 ErrNotFound",
    78  				"zzz.SEPARATOR.105 ErrNotFound",
    79  			},
    80  		},
    81  
    82  		{
    83  			description: "triple-0: three level-0 tables",
    84  			tables: []testTable{
    85  				{
    86  					level:   0,
    87  					fileNum: 10,
    88  					data: []string{
    89  						"the.SET.101 a",
    90  						"cat.SET.102 b",
    91  						"on_.SET.103 c",
    92  						"the.SET.104 d",
    93  						"mat.SET.105 e",
    94  						"the.DEL.106 ",
    95  						"the.SET.107 g",
    96  					},
    97  				},
    98  				{
    99  					level:   0,
   100  					fileNum: 11,
   101  					data: []string{
   102  						"awk.SET.111 w",
   103  						"cat.SET.112 x",
   104  						"man.SET.113 y",
   105  						"sed.SET.114 z",
   106  					},
   107  				},
   108  				{
   109  					level:   0,
   110  					fileNum: 12,
   111  					data: []string{
   112  						"the.DEL.121 ",
   113  						"cat.DEL.122 ",
   114  						"man.DEL.123 ",
   115  						"was.SET.124 D",
   116  						"not.SET.125 E",
   117  						"the.SET.126 F",
   118  						"man.SET.127 G",
   119  					},
   120  				},
   121  			},
   122  			queries: []string{
   123  				"aaa.SEPARATOR.105 ErrNotFound",
   124  				"awk.SEPARATOR.135 w",
   125  				"awk.SEPARATOR.125 w",
   126  				"awk.SEPARATOR.115 w",
   127  				"awk.SEPARATOR.105 ErrNotFound",
   128  				"cat.SEPARATOR.135 ErrNotFound",
   129  				"cat.SEPARATOR.125 ErrNotFound",
   130  				"cat.SEPARATOR.115 x",
   131  				"cat.SEPARATOR.105 b",
   132  				"man.SEPARATOR.135 G",
   133  				"man.SEPARATOR.125 ErrNotFound",
   134  				"man.SEPARATOR.115 y",
   135  				"man.SEPARATOR.105 ErrNotFound",
   136  				"on_.SEPARATOR.135 c",
   137  				"on_.SEPARATOR.125 c",
   138  				"on_.SEPARATOR.115 c",
   139  				"on_.SEPARATOR.105 c",
   140  				"the.SEPARATOR.135 F",
   141  				"the.SEPARATOR.127 F",
   142  				"the.SEPARATOR.126 F",
   143  				"the.SEPARATOR.125 ErrNotFound",
   144  				"the.SEPARATOR.122 ErrNotFound",
   145  				"the.SEPARATOR.121 ErrNotFound",
   146  				"the.SEPARATOR.120 g",
   147  				"the.SEPARATOR.115 g",
   148  				"the.SEPARATOR.114 g",
   149  				"the.SEPARATOR.111 g",
   150  				"the.SEPARATOR.110 g",
   151  				"the.SEPARATOR.108 g",
   152  				"the.SEPARATOR.107 g",
   153  				"the.SEPARATOR.106 ErrNotFound",
   154  				"the.SEPARATOR.105 d",
   155  				"the.SEPARATOR.104 d",
   156  				"the.SEPARATOR.104 d",
   157  				"the.SEPARATOR.103 a",
   158  				"the.SEPARATOR.102 a",
   159  				"the.SEPARATOR.101 a",
   160  				"the.SEPARATOR.100 ErrNotFound",
   161  				"zzz.SEPARATOR.105 ErrNotFound",
   162  			},
   163  		},
   164  
   165  		{
   166  			description: "quad-4: four level-4 tables",
   167  			tables: []testTable{
   168  				{
   169  					level:   4,
   170  					fileNum: 11,
   171  					data: []string{
   172  						"aardvark.SET.101 a1",
   173  						"alpaca__.SET.201 a2",
   174  						"anteater.SET.301 a3",
   175  					},
   176  				},
   177  				{
   178  					level:   4,
   179  					fileNum: 22,
   180  					data: []string{
   181  						"baboon__.SET.102 b1",
   182  						"baboon__.DEL.202 ",
   183  						"baboon__.SET.302 b3",
   184  						"bear____.SET.402 b4",
   185  						"bear____.DEL.502 ",
   186  						"buffalo_.SET.602 b6",
   187  					},
   188  				},
   189  				{
   190  					level:   4,
   191  					fileNum: 33,
   192  					data: []string{
   193  						"buffalo_.SET.103 B1",
   194  					},
   195  				},
   196  				{
   197  					level:   4,
   198  					fileNum: 44,
   199  					data: []string{
   200  						"chipmunk.SET.104 c1",
   201  						"chipmunk.SET.204 c2",
   202  					},
   203  				},
   204  			},
   205  			queries: []string{
   206  				"a_______.SEPARATOR.999 ErrNotFound",
   207  				"aardvark.SEPARATOR.999 a1",
   208  				"aardvark.SEPARATOR.102 a1",
   209  				"aardvark.SEPARATOR.101 a1",
   210  				"aardvark.SEPARATOR.100 ErrNotFound",
   211  				"alpaca__.SEPARATOR.999 a2",
   212  				"alpaca__.SEPARATOR.200 ErrNotFound",
   213  				"anteater.SEPARATOR.999 a3",
   214  				"anteater.SEPARATOR.302 a3",
   215  				"anteater.SEPARATOR.301 a3",
   216  				"anteater.SEPARATOR.300 ErrNotFound",
   217  				"anteater.SEPARATOR.000 ErrNotFound",
   218  				"b_______.SEPARATOR.999 ErrNotFound",
   219  				"baboon__.SEPARATOR.999 b3",
   220  				"baboon__.SEPARATOR.302 b3",
   221  				"baboon__.SEPARATOR.301 ErrNotFound",
   222  				"baboon__.SEPARATOR.202 ErrNotFound",
   223  				"baboon__.SEPARATOR.201 b1",
   224  				"baboon__.SEPARATOR.102 b1",
   225  				"baboon__.SEPARATOR.101 ErrNotFound",
   226  				"bear____.SEPARATOR.999 ErrNotFound",
   227  				"bear____.SEPARATOR.500 b4",
   228  				"bear____.SEPARATOR.000 ErrNotFound",
   229  				"buffalo_.SEPARATOR.999 b6",
   230  				"buffalo_.SEPARATOR.603 b6",
   231  				"buffalo_.SEPARATOR.602 b6",
   232  				"buffalo_.SEPARATOR.601 B1",
   233  				"buffalo_.SEPARATOR.104 B1",
   234  				"buffalo_.SEPARATOR.103 B1",
   235  				"buffalo_.SEPARATOR.102 ErrNotFound",
   236  				"buffalo_.SEPARATOR.000 ErrNotFound",
   237  				"c_______.SEPARATOR.999 ErrNotFound",
   238  				"chipmunk.SEPARATOR.999 c2",
   239  				"chipmunk.SEPARATOR.205 c2",
   240  				"chipmunk.SEPARATOR.204 c2",
   241  				"chipmunk.SEPARATOR.203 c1",
   242  				"chipmunk.SEPARATOR.105 c1",
   243  				"chipmunk.SEPARATOR.104 c1",
   244  				"chipmunk.SEPARATOR.103 ErrNotFound",
   245  				"chipmunk.SEPARATOR.000 ErrNotFound",
   246  				"d_______.SEPARATOR.999 ErrNotFound",
   247  			},
   248  		},
   249  
   250  		{
   251  			description: "complex: many tables at many levels",
   252  			tables: []testTable{
   253  				{
   254  					level:   0,
   255  					fileNum: 50,
   256  					data: []string{
   257  						"alfalfa__.SET.501 p1",
   258  						"asparagus.SET.502 p2",
   259  						"cabbage__.DEL.503 ",
   260  						"spinach__.MERGE.504 p3",
   261  					},
   262  				},
   263  				{
   264  					level:   0,
   265  					fileNum: 51,
   266  					data: []string{
   267  						"asparagus.SET.511 q1",
   268  						"asparagus.SET.512 q2",
   269  						"asparagus.SET.513 q3",
   270  						"beans____.SET.514 q4",
   271  						"broccoli_.SET.515 q5",
   272  						"cabbage__.SET.516 q6",
   273  						"celery___.SET.517 q7",
   274  						"spinach__.MERGE.518 q8",
   275  					},
   276  				},
   277  				{
   278  					level:   1,
   279  					fileNum: 40,
   280  					data: []string{
   281  						"alfalfa__.SET.410 r1",
   282  						"asparagus.SET.420 r2",
   283  						"arugula__.SET.430 r3",
   284  					},
   285  				},
   286  				{
   287  					level:   1,
   288  					fileNum: 41,
   289  					data: []string{
   290  						"beans____.SET.411 s1",
   291  						"beans____.SET.421 s2",
   292  						"bokchoy__.DEL.431 ",
   293  						"broccoli_.SET.441 s4",
   294  					},
   295  				},
   296  				{
   297  					level:   1,
   298  					fileNum: 42,
   299  					data: []string{
   300  						"cabbage__.SET.412 t1",
   301  						"corn_____.DEL.422 ",
   302  						"spinach__.MERGE.432 t2",
   303  					},
   304  				},
   305  				{
   306  					level:   2,
   307  					fileNum: 30,
   308  					data: []string{
   309  						"alfalfa__.SET.310 u1",
   310  						"bokchoy__.SET.320 u2",
   311  						"celery___.SET.330 u3",
   312  						"corn_____.SET.340 u4",
   313  						"spinach__.MERGE.350 u5",
   314  					},
   315  				},
   316  			},
   317  			queries: []string{
   318  				"a________.SEPARATOR.999 ErrNotFound",
   319  				"alfalfa__.SEPARATOR.520 p1",
   320  				"alfalfa__.SEPARATOR.510 p1",
   321  				"alfalfa__.SEPARATOR.500 r1",
   322  				"alfalfa__.SEPARATOR.400 u1",
   323  				"alfalfa__.SEPARATOR.300 ErrNotFound",
   324  				"asparagus.SEPARATOR.520 q3",
   325  				"asparagus.SEPARATOR.510 p2",
   326  				"asparagus.SEPARATOR.500 r2",
   327  				"asparagus.SEPARATOR.400 ErrNotFound",
   328  				"asparagus.SEPARATOR.300 ErrNotFound",
   329  				"arugula__.SEPARATOR.520 r3",
   330  				"arugula__.SEPARATOR.510 r3",
   331  				"arugula__.SEPARATOR.500 r3",
   332  				"arugula__.SEPARATOR.400 ErrNotFound",
   333  				"arugula__.SEPARATOR.300 ErrNotFound",
   334  				"beans____.SEPARATOR.520 q4",
   335  				"beans____.SEPARATOR.510 s2",
   336  				"beans____.SEPARATOR.500 s2",
   337  				"beans____.SEPARATOR.400 ErrNotFound",
   338  				"beans____.SEPARATOR.300 ErrNotFound",
   339  				"bokchoy__.SEPARATOR.520 ErrNotFound",
   340  				"bokchoy__.SEPARATOR.510 ErrNotFound",
   341  				"bokchoy__.SEPARATOR.500 ErrNotFound",
   342  				"bokchoy__.SEPARATOR.400 u2",
   343  				"bokchoy__.SEPARATOR.300 ErrNotFound",
   344  				"broccoli_.SEPARATOR.520 q5",
   345  				"broccoli_.SEPARATOR.510 s4",
   346  				"broccoli_.SEPARATOR.500 s4",
   347  				"broccoli_.SEPARATOR.400 ErrNotFound",
   348  				"broccoli_.SEPARATOR.300 ErrNotFound",
   349  				"cabbage__.SEPARATOR.520 q6",
   350  				"cabbage__.SEPARATOR.510 ErrNotFound",
   351  				"cabbage__.SEPARATOR.500 t1",
   352  				"cabbage__.SEPARATOR.400 ErrNotFound",
   353  				"cabbage__.SEPARATOR.300 ErrNotFound",
   354  				"celery___.SEPARATOR.520 q7",
   355  				"celery___.SEPARATOR.510 u3",
   356  				"celery___.SEPARATOR.500 u3",
   357  				"celery___.SEPARATOR.400 u3",
   358  				"celery___.SEPARATOR.300 ErrNotFound",
   359  				"corn_____.SEPARATOR.520 ErrNotFound",
   360  				"corn_____.SEPARATOR.510 ErrNotFound",
   361  				"corn_____.SEPARATOR.500 ErrNotFound",
   362  				"corn_____.SEPARATOR.400 u4",
   363  				"corn_____.SEPARATOR.300 ErrNotFound",
   364  				"d________.SEPARATOR.999 ErrNotFound",
   365  				"spinach__.SEPARATOR.999 u5t2p3q8",
   366  				"spinach__.SEPARATOR.518 u5t2p3q8",
   367  				"spinach__.SEPARATOR.517 u5t2p3",
   368  				"spinach__.SEPARATOR.504 u5t2p3",
   369  				"spinach__.SEPARATOR.503 u5t2",
   370  				"spinach__.SEPARATOR.432 u5t2",
   371  				"spinach__.SEPARATOR.431 u5",
   372  				"spinach__.SEPARATOR.350 u5",
   373  				"spinach__.SEPARATOR.349 ErrNotFound",
   374  			},
   375  		},
   376  
   377  		{
   378  			description: "broken invariants 0: non-increasing level 0 sequence numbers",
   379  			badOrdering: true,
   380  			tables: []testTable{
   381  				{
   382  					level:   0,
   383  					fileNum: 19,
   384  					data: []string{
   385  						"a.SET.101 a",
   386  						"b.SET.102 b",
   387  					},
   388  				},
   389  				{
   390  					level:   0,
   391  					fileNum: 20,
   392  					data: []string{
   393  						"c.SET.101 c",
   394  					},
   395  				},
   396  			},
   397  		},
   398  
   399  		{
   400  			description: "broken invariants 1: non-increasing level 0 sequence numbers",
   401  			badOrdering: true,
   402  			tables: []testTable{
   403  				{
   404  					level:   0,
   405  					fileNum: 19,
   406  					data: []string{
   407  						"a.SET.101 a",
   408  						"b.SET.102 b",
   409  					},
   410  				},
   411  				{
   412  					level:   0,
   413  					fileNum: 20,
   414  					data: []string{
   415  						"c.SET.100 c",
   416  						"d.SET.101 d",
   417  					},
   418  				},
   419  			},
   420  		},
   421  
   422  		{
   423  			description: "broken invariants 2: matching level 0 sequence numbers, considered acceptable",
   424  			badOrdering: false,
   425  			tables: []testTable{
   426  				{
   427  					level:   0,
   428  					fileNum: 19,
   429  					data: []string{
   430  						"a.SET.101 a",
   431  					},
   432  				},
   433  				{
   434  					level:   0,
   435  					fileNum: 20,
   436  					data: []string{
   437  						"a.SET.101 a",
   438  					},
   439  				},
   440  			},
   441  		},
   442  
   443  		{
   444  			description: "broken invariants 3: level non-0 overlapping internal key ranges",
   445  			badOrdering: true,
   446  			tables: []testTable{
   447  				{
   448  					level:   5,
   449  					fileNum: 11,
   450  					data: []string{
   451  						"bat.SET.101 xxx",
   452  						"dog.SET.102 xxx",
   453  					},
   454  				},
   455  				{
   456  					level:   5,
   457  					fileNum: 12,
   458  					data: []string{
   459  						"cow.SET.103 xxx",
   460  						"pig.SET.104 xxx",
   461  					},
   462  				},
   463  			},
   464  		},
   465  	}
   466  
   467  	cmp := testkeys.Comparer.Compare
   468  	equal := testkeys.Comparer.Equal
   469  	for _, tc := range testCases {
   470  		desc := tc.description[:strings.Index(tc.description, ":")]
   471  
   472  		// m is a map from file numbers to DBs.
   473  		m := map[FileNum]*memTable{}
   474  		newIter := func(
   475  			file *manifest.FileMetadata, _ *IterOptions, _ internalIterOpts,
   476  		) (internalIterator, keyspan.FragmentIterator, error) {
   477  			d, ok := m[file.FileNum]
   478  			if !ok {
   479  				return nil, nil, errors.New("no such file")
   480  			}
   481  			return d.newIter(nil), nil, nil
   482  		}
   483  
   484  		var files [numLevels][]*fileMetadata
   485  		for _, tt := range tc.tables {
   486  			d := newMemTable(memTableOptions{})
   487  			m[tt.fileNum] = d
   488  
   489  			meta := &fileMetadata{
   490  				FileNum: tt.fileNum,
   491  			}
   492  			for i, datum := range tt.data {
   493  				s := strings.Split(datum, " ")
   494  				ikey := base.ParseInternalKey(s[0])
   495  				err := d.set(ikey, []byte(s[1]))
   496  				if err != nil {
   497  					t.Fatalf("desc=%q: memtable Set: %v", desc, err)
   498  				}
   499  
   500  				meta.ExtendPointKeyBounds(cmp, ikey, ikey)
   501  				if i == 0 {
   502  					meta.SmallestSeqNum = ikey.SeqNum()
   503  					meta.LargestSeqNum = ikey.SeqNum()
   504  				} else {
   505  					if meta.SmallestSeqNum > ikey.SeqNum() {
   506  						meta.SmallestSeqNum = ikey.SeqNum()
   507  					}
   508  					if meta.LargestSeqNum < ikey.SeqNum() {
   509  						meta.LargestSeqNum = ikey.SeqNum()
   510  					}
   511  				}
   512  			}
   513  
   514  			files[tt.level] = append(files[tt.level], meta)
   515  		}
   516  		v := manifest.NewVersion(cmp, base.DefaultFormatter, 10<<20, files)
   517  		err := v.CheckOrdering(cmp, base.DefaultFormatter)
   518  		if tc.badOrdering && err == nil {
   519  			t.Errorf("desc=%q: want bad ordering, got nil error", desc)
   520  			continue
   521  		} else if !tc.badOrdering && err != nil {
   522  			t.Errorf("desc=%q: bad ordering: %v", desc, err)
   523  			continue
   524  		}
   525  
   526  		get := func(v *version, ikey InternalKey) ([]byte, error) {
   527  			var buf struct {
   528  				dbi Iterator
   529  				get getIter
   530  			}
   531  
   532  			get := &buf.get
   533  			get.cmp = cmp
   534  			get.equal = equal
   535  			get.newIters = newIter
   536  			get.key = ikey.UserKey
   537  			get.l0 = v.L0SublevelFiles
   538  			get.version = v
   539  			get.snapshot = ikey.SeqNum() + 1
   540  
   541  			i := &buf.dbi
   542  			i.comparer = *testkeys.Comparer
   543  			i.merge = DefaultMerger.Merge
   544  			i.iter = get
   545  
   546  			defer i.Close()
   547  			if !i.First() {
   548  				err := i.Error()
   549  				if err != nil {
   550  					return nil, err
   551  				}
   552  				return nil, ErrNotFound
   553  			}
   554  			return i.Value(), nil
   555  		}
   556  
   557  		for _, query := range tc.queries {
   558  			s := strings.Split(query, " ")
   559  			ikey := base.ParseInternalKey(s[0])
   560  			value, err := get(v, ikey)
   561  			got, want := "", s[1]
   562  			if err != nil {
   563  				if err != ErrNotFound {
   564  					t.Errorf("desc=%q: query=%q: %v", desc, s[0], err)
   565  					continue
   566  				}
   567  				got = "ErrNotFound"
   568  			} else {
   569  				got = string(value)
   570  			}
   571  			if got != want {
   572  				t.Errorf("desc=%q: query=%q: got %q, want %q", desc, s[0], got, want)
   573  			}
   574  		}
   575  	}
   576  }