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