github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/lsmkv/strategies_map_integration_test.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  //go:build integrationTest
    13  // +build integrationTest
    14  
    15  package lsmkv
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  	"github.com/weaviate/weaviate/entities/cyclemanager"
    25  )
    26  
    27  func TestMapCollectionStrategy(t *testing.T) {
    28  	ctx := testCtx()
    29  	tests := bucketIntegrationTests{
    30  		{
    31  			name: "mapInsertAndAppend",
    32  			f:    mapInsertAndAppend,
    33  			opts: []BucketOption{
    34  				WithStrategy(StrategyMapCollection),
    35  			},
    36  		},
    37  		{
    38  			name: "mapInsertAndDelete",
    39  			f:    mapInsertAndDelete,
    40  			opts: []BucketOption{
    41  				WithStrategy(StrategyMapCollection),
    42  			},
    43  		},
    44  		{
    45  			name: "mapCursors",
    46  			f:    mapCursors,
    47  			opts: []BucketOption{
    48  				WithStrategy(StrategyMapCollection),
    49  			},
    50  		},
    51  	}
    52  	tests.run(ctx, t)
    53  }
    54  
    55  func mapInsertAndAppend(ctx context.Context, t *testing.T, opts []BucketOption) {
    56  	dirName := t.TempDir()
    57  
    58  	t.Run("memtable-only", func(t *testing.T) {
    59  		b, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
    60  			cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
    61  		require.Nil(t, err)
    62  
    63  		// so big it effectively never triggers as part of this test
    64  		b.SetMemtableThreshold(1e9)
    65  
    66  		rowKey1 := []byte("test1-key-1")
    67  		rowKey2 := []byte("test1-key-2")
    68  
    69  		t.Run("set original values and verify", func(t *testing.T) {
    70  			row1Map := []MapPair{
    71  				{
    72  					Key:   []byte("row1-key1"),
    73  					Value: []byte("row1-key1-value1"),
    74  				}, {
    75  					Key:   []byte("row1-key2"),
    76  					Value: []byte("row1-key2-value1"),
    77  				},
    78  			}
    79  
    80  			row2Map := []MapPair{
    81  				{
    82  					Key:   []byte("row2-key1"),
    83  					Value: []byte("row2-key1-value1"),
    84  				}, {
    85  					Key:   []byte("row2-key2"),
    86  					Value: []byte("row2-key2-value1"),
    87  				},
    88  			}
    89  
    90  			for _, pair := range row1Map {
    91  				err = b.MapSet(rowKey1, pair)
    92  				require.Nil(t, err)
    93  			}
    94  
    95  			for _, pair := range row2Map {
    96  				err = b.MapSet(rowKey2, pair)
    97  				require.Nil(t, err)
    98  			}
    99  
   100  			res, err := b.MapList(rowKey1)
   101  			require.Nil(t, err)
   102  			assert.Equal(t, row1Map, res)
   103  			res, err = b.MapList(rowKey2)
   104  			require.Nil(t, err)
   105  			assert.Equal(t, res, row2Map)
   106  		})
   107  
   108  		t.Run("replace an existing map key", func(t *testing.T) {
   109  			err = b.MapSet(rowKey1, MapPair{
   110  				Key:   []byte("row1-key1"),        // existing key
   111  				Value: []byte("row1-key1-value2"), // updated value
   112  			})
   113  			require.Nil(t, err)
   114  
   115  			row1Updated := []MapPair{
   116  				{
   117  					Key:   []byte("row1-key1"),
   118  					Value: []byte("row1-key1-value2"), // <--- updated, rest unchanged
   119  				}, {
   120  					Key:   []byte("row1-key2"),
   121  					Value: []byte("row1-key2-value1"),
   122  				},
   123  			}
   124  
   125  			row2Unchanged := []MapPair{
   126  				{
   127  					Key:   []byte("row2-key1"),
   128  					Value: []byte("row2-key1-value1"),
   129  				}, {
   130  					Key:   []byte("row2-key2"),
   131  					Value: []byte("row2-key2-value1"),
   132  				},
   133  			}
   134  
   135  			res, err := b.MapList(rowKey1)
   136  			require.Nil(t, err)
   137  			// NOTE: We are accepting that the order is changed here. Given the name
   138  			// "MapCollection" there should be no expectations regarding the order,
   139  			// but we have yet to validate if this fits with all of the intended use
   140  			// cases.
   141  			assert.ElementsMatch(t, row1Updated, res)
   142  			res, err = b.MapList(rowKey2)
   143  			require.Nil(t, err)
   144  			assert.Equal(t, res, row2Unchanged)
   145  		})
   146  	})
   147  
   148  	t.Run("with a single flush between updates", func(t *testing.T) {
   149  		b, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
   150  			cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
   151  		require.Nil(t, err)
   152  
   153  		// so big it effectively never triggers as part of this test
   154  		b.SetMemtableThreshold(1e9)
   155  
   156  		rowKey1 := []byte("test2-key-1")
   157  		rowKey2 := []byte("test2-key-2")
   158  
   159  		t.Run("set original values and verify", func(t *testing.T) {
   160  			row1Map := []MapPair{
   161  				{
   162  					Key:   []byte("row1-key1"),
   163  					Value: []byte("row1-key1-value1"),
   164  				}, {
   165  					Key:   []byte("row1-key2"),
   166  					Value: []byte("row1-key2-value1"),
   167  				},
   168  			}
   169  
   170  			row2Map := []MapPair{
   171  				{
   172  					Key:   []byte("row2-key1"),
   173  					Value: []byte("row2-key1-value1"),
   174  				}, {
   175  					Key:   []byte("row2-key2"),
   176  					Value: []byte("row2-key2-value1"),
   177  				},
   178  			}
   179  
   180  			for _, pair := range row1Map {
   181  				err = b.MapSet(rowKey1, pair)
   182  				require.Nil(t, err)
   183  			}
   184  
   185  			for _, pair := range row2Map {
   186  				err = b.MapSet(rowKey2, pair)
   187  				require.Nil(t, err)
   188  			}
   189  
   190  			res, err := b.MapList(rowKey1)
   191  			require.Nil(t, err)
   192  			assert.Equal(t, row1Map, res)
   193  			res, err = b.MapList(rowKey2)
   194  			require.Nil(t, err)
   195  			assert.Equal(t, res, row2Map)
   196  		})
   197  
   198  		t.Run("flush to disk", func(t *testing.T) {
   199  			require.Nil(t, b.FlushAndSwitch())
   200  		})
   201  
   202  		t.Run("replace an existing map key", func(t *testing.T) {
   203  			err = b.MapSet(rowKey1, MapPair{
   204  				Key:   []byte("row1-key1"),        // existing key
   205  				Value: []byte("row1-key1-value2"), // updated value
   206  			})
   207  			require.Nil(t, err)
   208  
   209  			row1Updated := []MapPair{
   210  				{
   211  					Key:   []byte("row1-key1"),
   212  					Value: []byte("row1-key1-value2"), // <--- updated, rest unchanged
   213  				}, {
   214  					Key:   []byte("row1-key2"),
   215  					Value: []byte("row1-key2-value1"),
   216  				},
   217  			}
   218  
   219  			row2Unchanged := []MapPair{
   220  				{
   221  					Key:   []byte("row2-key1"),
   222  					Value: []byte("row2-key1-value1"),
   223  				}, {
   224  					Key:   []byte("row2-key2"),
   225  					Value: []byte("row2-key2-value1"),
   226  				},
   227  			}
   228  
   229  			res, err := b.MapList(rowKey1)
   230  			require.Nil(t, err)
   231  			// NOTE: We are accepting that the order is changed here. Given the name
   232  			// "MapCollection" there should be no expectations regarding the order,
   233  			// but we have yet to validate if this fits with all of the intended use
   234  			// cases.
   235  			assert.ElementsMatch(t, row1Updated, res)
   236  			res, err = b.MapList(rowKey2)
   237  			require.Nil(t, err)
   238  			assert.Equal(t, res, row2Unchanged)
   239  		})
   240  	})
   241  
   242  	t.Run("with flushes after initial and update", func(t *testing.T) {
   243  		b, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
   244  			cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
   245  		require.Nil(t, err)
   246  
   247  		// so big it effectively never triggers as part of this test
   248  		b.SetMemtableThreshold(1e9)
   249  
   250  		rowKey1 := []byte("test3-key-1")
   251  		rowKey2 := []byte("test3-key-2")
   252  
   253  		t.Run("set original values and verify", func(t *testing.T) {
   254  			row1Map := []MapPair{
   255  				{
   256  					Key:   []byte("row1-key1"),
   257  					Value: []byte("row1-key1-value1"),
   258  				}, {
   259  					Key:   []byte("row1-key2"),
   260  					Value: []byte("row1-key2-value1"),
   261  				},
   262  			}
   263  
   264  			row2Map := []MapPair{
   265  				{
   266  					Key:   []byte("row2-key1"),
   267  					Value: []byte("row2-key1-value1"),
   268  				}, {
   269  					Key:   []byte("row2-key2"),
   270  					Value: []byte("row2-key2-value1"),
   271  				},
   272  			}
   273  
   274  			for _, pair := range row1Map {
   275  				err = b.MapSet(rowKey1, pair)
   276  				require.Nil(t, err)
   277  			}
   278  
   279  			for _, pair := range row2Map {
   280  				err = b.MapSet(rowKey2, pair)
   281  				require.Nil(t, err)
   282  			}
   283  
   284  			res, err := b.MapList(rowKey1)
   285  			require.Nil(t, err)
   286  			assert.Equal(t, row1Map, res)
   287  			res, err = b.MapList(rowKey2)
   288  			require.Nil(t, err)
   289  			assert.Equal(t, res, row2Map)
   290  		})
   291  
   292  		t.Run("flush to disk", func(t *testing.T) {
   293  			require.Nil(t, b.FlushAndSwitch())
   294  		})
   295  
   296  		t.Run("replace an existing map key", func(t *testing.T) {
   297  			err = b.MapSet(rowKey1, MapPair{
   298  				Key:   []byte("row1-key1"),        // existing key
   299  				Value: []byte("row1-key1-value2"), // updated value
   300  			})
   301  			require.Nil(t, err)
   302  
   303  			// Flush again!
   304  			require.Nil(t, b.FlushAndSwitch())
   305  
   306  			row1Updated := []MapPair{
   307  				{
   308  					Key:   []byte("row1-key1"),
   309  					Value: []byte("row1-key1-value2"), // <--- updated, rest unchanged
   310  				}, {
   311  					Key:   []byte("row1-key2"),
   312  					Value: []byte("row1-key2-value1"),
   313  				},
   314  			}
   315  
   316  			row2Unchanged := []MapPair{
   317  				{
   318  					Key:   []byte("row2-key1"),
   319  					Value: []byte("row2-key1-value1"),
   320  				}, {
   321  					Key:   []byte("row2-key2"),
   322  					Value: []byte("row2-key2-value1"),
   323  				},
   324  			}
   325  
   326  			res, err := b.MapList(rowKey1)
   327  			require.Nil(t, err)
   328  			// NOTE: We are accepting that the order is changed here. Given the name
   329  			// "MapCollection" there should be no expectations regarding the order,
   330  			// but we have yet to validate if this fits with all of the intended use
   331  			// cases.
   332  			assert.ElementsMatch(t, row1Updated, res)
   333  			res, err = b.MapList(rowKey2)
   334  			require.Nil(t, err)
   335  			assert.Equal(t, res, row2Unchanged)
   336  		})
   337  	})
   338  
   339  	t.Run("update in memtable, then do an orderly shutdown, and re-init", func(t *testing.T) {
   340  		b, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
   341  			cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
   342  		require.Nil(t, err)
   343  
   344  		// so big it effectively never triggers as part of this test
   345  		b.SetMemtableThreshold(1e9)
   346  
   347  		rowKey1 := []byte("test4-key-1")
   348  		rowKey2 := []byte("test4-key-2")
   349  
   350  		t.Run("set original values and verify", func(t *testing.T) {
   351  			row1Map := []MapPair{
   352  				{
   353  					Key:   []byte("row1-key1"),
   354  					Value: []byte("row1-key1-value1"),
   355  				}, {
   356  					Key:   []byte("row1-key2"),
   357  					Value: []byte("row1-key2-value1"),
   358  				},
   359  			}
   360  
   361  			row2Map := []MapPair{
   362  				{
   363  					Key:   []byte("row2-key1"),
   364  					Value: []byte("row2-key1-value1"),
   365  				}, {
   366  					Key:   []byte("row2-key2"),
   367  					Value: []byte("row2-key2-value1"),
   368  				},
   369  			}
   370  
   371  			for _, pair := range row1Map {
   372  				err = b.MapSet(rowKey1, pair)
   373  				require.Nil(t, err)
   374  			}
   375  
   376  			for _, pair := range row2Map {
   377  				err = b.MapSet(rowKey2, pair)
   378  				require.Nil(t, err)
   379  			}
   380  
   381  			res, err := b.MapList(rowKey1)
   382  			require.Nil(t, err)
   383  			assert.Equal(t, row1Map, res)
   384  			res, err = b.MapList(rowKey2)
   385  			require.Nil(t, err)
   386  			assert.Equal(t, res, row2Map)
   387  		})
   388  
   389  		t.Run("replace an existing map key", func(t *testing.T) {
   390  			err = b.MapSet(rowKey1, MapPair{
   391  				Key:   []byte("row1-key1"),        // existing key
   392  				Value: []byte("row1-key1-value2"), // updated value
   393  			})
   394  			require.Nil(t, err)
   395  		})
   396  
   397  		t.Run("orderly shutdown", func(t *testing.T) {
   398  			b.Shutdown(context.Background())
   399  		})
   400  
   401  		t.Run("init another bucket on the same files", func(t *testing.T) {
   402  			b2, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
   403  				cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
   404  			require.Nil(t, err)
   405  
   406  			row1Updated := []MapPair{
   407  				{
   408  					Key:   []byte("row1-key1"),
   409  					Value: []byte("row1-key1-value2"), // <--- updated, rest unchanged
   410  				}, {
   411  					Key:   []byte("row1-key2"),
   412  					Value: []byte("row1-key2-value1"),
   413  				},
   414  			}
   415  
   416  			row2Unchanged := []MapPair{
   417  				{
   418  					Key:   []byte("row2-key1"),
   419  					Value: []byte("row2-key1-value1"),
   420  				}, {
   421  					Key:   []byte("row2-key2"),
   422  					Value: []byte("row2-key2-value1"),
   423  				},
   424  			}
   425  
   426  			res, err := b2.MapList(rowKey1)
   427  			require.Nil(t, err)
   428  			// NOTE: We are accepting that the order is changed here. Given the name
   429  			// "MapCollection" there should be no expectations regarding the order,
   430  			// but we have yet to validate if this fits with all of the intended use
   431  			// cases.
   432  			assert.ElementsMatch(t, row1Updated, res)
   433  			res, err = b2.MapList(rowKey2)
   434  			require.Nil(t, err)
   435  			assert.Equal(t, res, row2Unchanged)
   436  		})
   437  	})
   438  }
   439  
   440  func mapInsertAndDelete(ctx context.Context, t *testing.T, opts []BucketOption) {
   441  	dirName := t.TempDir()
   442  
   443  	t.Run("memtable-only", func(t *testing.T) {
   444  		b, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
   445  			cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
   446  		require.Nil(t, err)
   447  
   448  		// so big it effectively never triggers as part of this test
   449  		b.SetMemtableThreshold(1e9)
   450  
   451  		rowKey1 := []byte("test1-key-1")
   452  		rowKey2 := []byte("test1-key-2")
   453  
   454  		t.Run("set original values and verify", func(t *testing.T) {
   455  			row1Map := []MapPair{
   456  				{
   457  					Key:   []byte("row1-key1"),
   458  					Value: []byte("row1-key1-value1"),
   459  				}, {
   460  					Key:   []byte("row1-key2"),
   461  					Value: []byte("row1-key2-value1"),
   462  				},
   463  			}
   464  
   465  			row2Map := []MapPair{
   466  				{
   467  					Key:   []byte("row2-key1"),
   468  					Value: []byte("row2-key1-value1"),
   469  				}, {
   470  					Key:   []byte("row2-key2"),
   471  					Value: []byte("row2-key2-value1"),
   472  				},
   473  			}
   474  
   475  			for _, pair := range row1Map {
   476  				err = b.MapSet(rowKey1, pair)
   477  				require.Nil(t, err)
   478  			}
   479  
   480  			for _, pair := range row2Map {
   481  				err = b.MapSet(rowKey2, pair)
   482  				require.Nil(t, err)
   483  			}
   484  
   485  			res, err := b.MapList(rowKey1)
   486  			require.Nil(t, err)
   487  			assert.Equal(t, row1Map, res)
   488  			res, err = b.MapList(rowKey2)
   489  			require.Nil(t, err)
   490  			assert.Equal(t, res, row2Map)
   491  		})
   492  
   493  		t.Run("delete some keys, re-add one of them", func(t *testing.T) {
   494  			err := b.MapDeleteKey(rowKey1, []byte("row1-key1"))
   495  			require.Nil(t, err)
   496  			err = b.MapDeleteKey(rowKey2, []byte("row2-key2"))
   497  			require.Nil(t, err)
   498  			err = b.MapSet(rowKey2, MapPair{
   499  				Key:   []byte("row2-key2"),
   500  				Value: []byte("row2-key2-reinserted"),
   501  			})
   502  			require.Nil(t, err)
   503  		})
   504  
   505  		t.Run("validate the results", func(t *testing.T) {
   506  			row1Updated := []MapPair{
   507  				// key 1 was deleted
   508  				{
   509  					Key:   []byte("row1-key2"),
   510  					Value: []byte("row1-key2-value1"),
   511  				},
   512  			}
   513  
   514  			row2Updated := []MapPair{
   515  				{
   516  					Key:   []byte("row2-key1"),
   517  					Value: []byte("row2-key1-value1"),
   518  				}, {
   519  					Key:   []byte("row2-key2"),
   520  					Value: []byte("row2-key2-reinserted"),
   521  				},
   522  			}
   523  
   524  			// NOTE: We are accepting that the order is changed here. Given the name
   525  			// "MapCollection" there should be no expectations regarding the order,
   526  			// but we have yet to validate if this fits with all of the intended use
   527  			// cases.
   528  			res, err := b.MapList(rowKey1)
   529  			require.Nil(t, err)
   530  			assert.ElementsMatch(t, row1Updated, res)
   531  			res, err = b.MapList(rowKey2)
   532  			require.Nil(t, err)
   533  			assert.ElementsMatch(t, row2Updated, res)
   534  		})
   535  	})
   536  
   537  	t.Run("with flushes between updates", func(t *testing.T) {
   538  		b, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
   539  			cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
   540  		require.Nil(t, err)
   541  
   542  		// so big it effectively never triggers as part of this test
   543  		b.SetMemtableThreshold(1e9)
   544  
   545  		rowKey1 := []byte("test1-key-1")
   546  		rowKey2 := []byte("test1-key-2")
   547  
   548  		t.Run("set original values and verify", func(t *testing.T) {
   549  			row1Map := []MapPair{
   550  				{
   551  					Key:   []byte("row1-key1"),
   552  					Value: []byte("row1-key1-value1"),
   553  				}, {
   554  					Key:   []byte("row1-key2"),
   555  					Value: []byte("row1-key2-value1"),
   556  				},
   557  			}
   558  
   559  			row2Map := []MapPair{
   560  				{
   561  					Key:   []byte("row2-key1"),
   562  					Value: []byte("row2-key1-value1"),
   563  				}, {
   564  					Key:   []byte("row2-key2"),
   565  					Value: []byte("row2-key2-value1"),
   566  				},
   567  			}
   568  
   569  			for _, pair := range row1Map {
   570  				err = b.MapSet(rowKey1, pair)
   571  				require.Nil(t, err)
   572  			}
   573  
   574  			for _, pair := range row2Map {
   575  				err = b.MapSet(rowKey2, pair)
   576  				require.Nil(t, err)
   577  			}
   578  
   579  			res, err := b.MapList(rowKey1)
   580  			require.Nil(t, err)
   581  			assert.Equal(t, row1Map, res)
   582  			res, err = b.MapList(rowKey2)
   583  			require.Nil(t, err)
   584  			assert.Equal(t, res, row2Map)
   585  		})
   586  
   587  		t.Run("flush to disk", func(t *testing.T) {
   588  			require.Nil(t, b.FlushAndSwitch())
   589  		})
   590  
   591  		t.Run("delete some keys, re-add one of them", func(t *testing.T) {
   592  			err := b.MapDeleteKey(rowKey1, []byte("row1-key1"))
   593  			require.Nil(t, err)
   594  			err = b.MapDeleteKey(rowKey2, []byte("row2-key2"))
   595  			require.Nil(t, err)
   596  			err = b.MapSet(rowKey2, MapPair{
   597  				Key:   []byte("row2-key2"),
   598  				Value: []byte("row2-key2-reinserted"),
   599  			})
   600  			require.Nil(t, err)
   601  		})
   602  
   603  		t.Run("flush to disk", func(t *testing.T) {
   604  			require.Nil(t, b.FlushAndSwitch())
   605  		})
   606  
   607  		t.Run("validate the results", func(t *testing.T) {
   608  			row1Updated := []MapPair{
   609  				// key 1 was deleted
   610  				{
   611  					Key:   []byte("row1-key2"),
   612  					Value: []byte("row1-key2-value1"),
   613  				},
   614  			}
   615  
   616  			row2Updated := []MapPair{
   617  				{
   618  					Key:   []byte("row2-key1"),
   619  					Value: []byte("row2-key1-value1"),
   620  				}, {
   621  					Key:   []byte("row2-key2"),
   622  					Value: []byte("row2-key2-reinserted"),
   623  				},
   624  			}
   625  
   626  			// NOTE: We are accepting that the order is changed here. Given the name
   627  			// "MapCollection" there should be no expectations regarding the order,
   628  			// but we have yet to validate if this fits with all of the intended use
   629  			// cases.
   630  			res, err := b.MapList(rowKey1)
   631  			require.Nil(t, err)
   632  			assert.ElementsMatch(t, row1Updated, res)
   633  			res, err = b.MapList(rowKey2)
   634  			require.Nil(t, err)
   635  			assert.ElementsMatch(t, row2Updated, res)
   636  		})
   637  	})
   638  
   639  	t.Run("with memtable only, then an orderly shutdown and restart", func(t *testing.T) {
   640  		b, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
   641  			cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
   642  		require.Nil(t, err)
   643  
   644  		// so big it effectively never triggers as part of this test
   645  		b.SetMemtableThreshold(1e9)
   646  
   647  		rowKey1 := []byte("test1-key-1")
   648  		rowKey2 := []byte("test1-key-2")
   649  
   650  		t.Run("set original values and verify", func(t *testing.T) {
   651  			row1Map := []MapPair{
   652  				{
   653  					Key:   []byte("row1-key1"),
   654  					Value: []byte("row1-key1-value1"),
   655  				}, {
   656  					Key:   []byte("row1-key2"),
   657  					Value: []byte("row1-key2-value1"),
   658  				},
   659  			}
   660  
   661  			row2Map := []MapPair{
   662  				{
   663  					Key:   []byte("row2-key1"),
   664  					Value: []byte("row2-key1-value1"),
   665  				}, {
   666  					Key:   []byte("row2-key2"),
   667  					Value: []byte("row2-key2-value1"),
   668  				},
   669  			}
   670  
   671  			for _, pair := range row1Map {
   672  				err = b.MapSet(rowKey1, pair)
   673  				require.Nil(t, err)
   674  			}
   675  
   676  			for _, pair := range row2Map {
   677  				err = b.MapSet(rowKey2, pair)
   678  				require.Nil(t, err)
   679  			}
   680  
   681  			res, err := b.MapList(rowKey1)
   682  			require.Nil(t, err)
   683  			assert.Equal(t, row1Map, res)
   684  			res, err = b.MapList(rowKey2)
   685  			require.Nil(t, err)
   686  			assert.Equal(t, res, row2Map)
   687  		})
   688  
   689  		t.Run("delete some keys, re-add one of them", func(t *testing.T) {
   690  			err := b.MapDeleteKey(rowKey1, []byte("row1-key1"))
   691  			require.Nil(t, err)
   692  			err = b.MapDeleteKey(rowKey2, []byte("row2-key2"))
   693  			require.Nil(t, err)
   694  			err = b.MapSet(rowKey2, MapPair{
   695  				Key:   []byte("row2-key2"),
   696  				Value: []byte("row2-key2-reinserted"),
   697  			})
   698  			require.Nil(t, err)
   699  		})
   700  
   701  		t.Run("orderly shutdown", func(t *testing.T) {
   702  			b.Shutdown(context.Background())
   703  		})
   704  
   705  		t.Run("init another bucket on the same files", func(t *testing.T) {
   706  			b2, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
   707  				cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
   708  			require.Nil(t, err)
   709  
   710  			row1Updated := []MapPair{
   711  				// key 1 was deleted
   712  				{
   713  					Key:   []byte("row1-key2"),
   714  					Value: []byte("row1-key2-value1"),
   715  				},
   716  			}
   717  
   718  			row2Updated := []MapPair{
   719  				{
   720  					Key:   []byte("row2-key1"),
   721  					Value: []byte("row2-key1-value1"),
   722  				}, {
   723  					Key:   []byte("row2-key2"),
   724  					Value: []byte("row2-key2-reinserted"),
   725  				},
   726  			}
   727  
   728  			// NOTE: We are accepting that the order is changed here. Given the name
   729  			// "MapCollection" there should be no expectations regarding the order,
   730  			// but we have yet to validate if this fits with all of the intended use
   731  			// cases.
   732  			res, err := b2.MapList(rowKey1)
   733  			require.Nil(t, err)
   734  			assert.ElementsMatch(t, row1Updated, res)
   735  			res, err = b2.MapList(rowKey2)
   736  			require.Nil(t, err)
   737  			assert.ElementsMatch(t, row2Updated, res)
   738  		})
   739  	})
   740  }
   741  
   742  func mapCursors(ctx context.Context, t *testing.T, opts []BucketOption) {
   743  	t.Run("memtable-only", func(t *testing.T) {
   744  		r := getRandomSeed()
   745  		dirName := t.TempDir()
   746  
   747  		b, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
   748  			cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
   749  		require.Nil(t, err)
   750  
   751  		// so big it effectively never triggers as part of this test
   752  		b.SetMemtableThreshold(1e9)
   753  
   754  		t.Run("set original values", func(t *testing.T) {
   755  			pairs := 20
   756  			valuesPerPair := 3
   757  			keys := make([][]byte, pairs)
   758  			values := make([][]MapPair, pairs)
   759  
   760  			for i := range keys {
   761  				keys[i] = []byte(fmt.Sprintf("row-%03d", i))
   762  				values[i] = make([]MapPair, valuesPerPair)
   763  				for j := range values[i] {
   764  					values[i][j] = MapPair{
   765  						Key:   []byte(fmt.Sprintf("row-%03d-key-%d", i, j)),
   766  						Value: []byte(fmt.Sprintf("row-%03d-value-%d", i, j)),
   767  					}
   768  				}
   769  			}
   770  
   771  			// shuffle to make sure the BST isn't accidentally in order
   772  			r.Shuffle(len(keys), func(i, j int) {
   773  				keys[i], keys[j] = keys[j], keys[i]
   774  				values[i], values[j] = values[j], values[i]
   775  			})
   776  
   777  			for i := range keys {
   778  				mapPairs := values[i]
   779  				for j := range mapPairs {
   780  					err = b.MapSet(keys[i], mapPairs[j])
   781  					require.Nil(t, err)
   782  				}
   783  			}
   784  		})
   785  
   786  		t.Run("seek from somewhere in the middle", func(t *testing.T) {
   787  			expectedKeys := [][]byte{
   788  				[]byte("row-016"),
   789  				[]byte("row-017"),
   790  				[]byte("row-018"),
   791  				[]byte("row-019"),
   792  			}
   793  			expectedValues := [][]MapPair{
   794  				{
   795  					{Key: []byte("row-016-key-0"), Value: []byte("row-016-value-0")},
   796  					{Key: []byte("row-016-key-1"), Value: []byte("row-016-value-1")},
   797  					{Key: []byte("row-016-key-2"), Value: []byte("row-016-value-2")},
   798  				},
   799  				{
   800  					{Key: []byte("row-017-key-0"), Value: []byte("row-017-value-0")},
   801  					{Key: []byte("row-017-key-1"), Value: []byte("row-017-value-1")},
   802  					{Key: []byte("row-017-key-2"), Value: []byte("row-017-value-2")},
   803  				},
   804  				{
   805  					{Key: []byte("row-018-key-0"), Value: []byte("row-018-value-0")},
   806  					{Key: []byte("row-018-key-1"), Value: []byte("row-018-value-1")},
   807  					{Key: []byte("row-018-key-2"), Value: []byte("row-018-value-2")},
   808  				},
   809  				{
   810  					{Key: []byte("row-019-key-0"), Value: []byte("row-019-value-0")},
   811  					{Key: []byte("row-019-key-1"), Value: []byte("row-019-value-1")},
   812  					{Key: []byte("row-019-key-2"), Value: []byte("row-019-value-2")},
   813  				},
   814  			}
   815  
   816  			var retrievedKeys [][]byte
   817  			var retrievedValues [][]MapPair
   818  			c := b.MapCursor()
   819  			defer c.Close()
   820  			for k, v := c.Seek([]byte("row-016")); k != nil; k, v = c.Next() {
   821  				retrievedKeys = append(retrievedKeys, k)
   822  				retrievedValues = append(retrievedValues, v)
   823  			}
   824  
   825  			assert.Equal(t, expectedKeys, retrievedKeys)
   826  
   827  			require.Equal(t, len(expectedValues), len(retrievedValues))
   828  			for i := range expectedValues {
   829  				assert.ElementsMatch(t, expectedValues[i], retrievedValues[i])
   830  			}
   831  		})
   832  
   833  		t.Run("start from beginning", func(t *testing.T) {
   834  			expectedKeys := [][]byte{
   835  				[]byte("row-000"),
   836  				[]byte("row-001"),
   837  				[]byte("row-002"),
   838  			}
   839  			expectedValues := [][]MapPair{
   840  				{
   841  					{Key: []byte("row-000-key-0"), Value: []byte("row-000-value-0")},
   842  					{Key: []byte("row-000-key-1"), Value: []byte("row-000-value-1")},
   843  					{Key: []byte("row-000-key-2"), Value: []byte("row-000-value-2")},
   844  				},
   845  				{
   846  					{Key: []byte("row-001-key-0"), Value: []byte("row-001-value-0")},
   847  					{Key: []byte("row-001-key-1"), Value: []byte("row-001-value-1")},
   848  					{Key: []byte("row-001-key-2"), Value: []byte("row-001-value-2")},
   849  				},
   850  				{
   851  					{Key: []byte("row-002-key-0"), Value: []byte("row-002-value-0")},
   852  					{Key: []byte("row-002-key-1"), Value: []byte("row-002-value-1")},
   853  					{Key: []byte("row-002-key-2"), Value: []byte("row-002-value-2")},
   854  				},
   855  			}
   856  
   857  			var retrievedKeys [][]byte
   858  			var retrievedValues [][]MapPair
   859  			c := b.MapCursor()
   860  			defer c.Close()
   861  			retrieved := 0
   862  			for k, v := c.First(); k != nil && retrieved < 3; k, v = c.Next() {
   863  				retrieved++
   864  				retrievedKeys = append(retrievedKeys, k)
   865  				retrievedValues = append(retrievedValues, v)
   866  			}
   867  
   868  			assert.Equal(t, expectedKeys, retrievedKeys)
   869  
   870  			require.Equal(t, len(expectedValues), len(retrievedValues))
   871  			for i := range expectedValues {
   872  				assert.ElementsMatch(t, expectedValues[i], retrievedValues[i])
   873  			}
   874  		})
   875  
   876  		t.Run("delete/replace an existing map key/value pair", func(t *testing.T) {
   877  			row := []byte("row-002")
   878  			pair := MapPair{
   879  				Key:   []byte("row-002-key-1"),           // existing key
   880  				Value: []byte("row-002-value-1-updated"), // updated value
   881  			}
   882  
   883  			require.Nil(t, b.MapSet(row, pair))
   884  
   885  			row = []byte("row-001")
   886  			key := []byte("row-001-key-1")
   887  
   888  			require.Nil(t, b.MapDeleteKey(row, key))
   889  		})
   890  
   891  		t.Run("verify update is contained", func(t *testing.T) {
   892  			expectedKeys := [][]byte{
   893  				[]byte("row-001"),
   894  				[]byte("row-002"),
   895  			}
   896  			expectedValues := [][]MapPair{
   897  				{
   898  					{Key: []byte("row-001-key-0"), Value: []byte("row-001-value-0")},
   899  					// key-1 was deleted
   900  					{Key: []byte("row-001-key-2"), Value: []byte("row-001-value-2")},
   901  				},
   902  				{
   903  					{Key: []byte("row-002-key-0"), Value: []byte("row-002-value-0")},
   904  					{Key: []byte("row-002-key-1"), Value: []byte("row-002-value-1-updated")},
   905  					{Key: []byte("row-002-key-2"), Value: []byte("row-002-value-2")},
   906  				},
   907  			}
   908  
   909  			var retrievedKeys [][]byte
   910  			var retrievedValues [][]MapPair
   911  			c := b.MapCursor()
   912  			defer c.Close()
   913  			retrieved := 0
   914  			for k, v := c.Seek([]byte("row-001")); k != nil && retrieved < 2; k, v = c.Next() {
   915  				retrieved++
   916  				retrievedKeys = append(retrievedKeys, k)
   917  				retrievedValues = append(retrievedValues, v)
   918  			}
   919  
   920  			assert.Equal(t, expectedKeys, retrievedKeys)
   921  
   922  			require.Equal(t, len(expectedValues), len(retrievedValues))
   923  			for i := range expectedValues {
   924  				assert.ElementsMatch(t, expectedValues[i], retrievedValues[i])
   925  			}
   926  		})
   927  	})
   928  
   929  	t.Run("with flushes", func(t *testing.T) {
   930  		r := getRandomSeed()
   931  		dirName := t.TempDir()
   932  
   933  		b, err := NewBucket(ctx, dirName, "", nullLogger(), nil,
   934  			cyclemanager.NewCallbackGroupNoop(), cyclemanager.NewCallbackGroupNoop(), opts...)
   935  		require.Nil(t, err)
   936  
   937  		// so big it effectively never triggers as part of this test
   938  		b.SetMemtableThreshold(1e9)
   939  
   940  		t.Run("first third (%3==0)", func(t *testing.T) {
   941  			pairs := 20
   942  			valuesPerPair := 3
   943  			var keys [][]byte
   944  			var values [][]MapPair
   945  
   946  			for i := 0; i < pairs; i++ {
   947  				if i%3 != 0 {
   948  					continue
   949  				}
   950  
   951  				keys = append(keys, []byte(fmt.Sprintf("row-%03d", i)))
   952  				curValues := make([]MapPair, valuesPerPair)
   953  				for j := range curValues {
   954  					curValues[j] = MapPair{
   955  						Key:   []byte(fmt.Sprintf("row-%03d-key-%d", i, j)),
   956  						Value: []byte(fmt.Sprintf("row-%03d-value-%d", i, j)),
   957  					}
   958  				}
   959  
   960  				values = append(values, curValues)
   961  			}
   962  
   963  			// shuffle to make sure the BST isn't accidentally in order
   964  			r.Shuffle(len(keys), func(i, j int) {
   965  				keys[i], keys[j] = keys[j], keys[i]
   966  				values[i], values[j] = values[j], values[i]
   967  			})
   968  
   969  			for i := range keys {
   970  				mapPairs := values[i]
   971  				for j := range mapPairs {
   972  					err = b.MapSet(keys[i], mapPairs[j])
   973  					require.Nil(t, err)
   974  				}
   975  			}
   976  		})
   977  
   978  		t.Run("flush to disk", func(t *testing.T) {
   979  			require.Nil(t, b.FlushAndSwitch())
   980  		})
   981  
   982  		t.Run("second third (%3==1)", func(t *testing.T) {
   983  			pairs := 20
   984  			valuesPerPair := 3
   985  			var keys [][]byte
   986  			var values [][]MapPair
   987  
   988  			for i := 0; i < pairs; i++ {
   989  				if i%3 != 1 {
   990  					continue
   991  				}
   992  
   993  				keys = append(keys, []byte(fmt.Sprintf("row-%03d", i)))
   994  				curValues := make([]MapPair, valuesPerPair)
   995  				for j := range curValues {
   996  					curValues[j] = MapPair{
   997  						Key:   []byte(fmt.Sprintf("row-%03d-key-%d", i, j)),
   998  						Value: []byte(fmt.Sprintf("row-%03d-value-%d", i, j)),
   999  					}
  1000  				}
  1001  
  1002  				values = append(values, curValues)
  1003  			}
  1004  
  1005  			// shuffle to make sure the BST isn't accidentally in order
  1006  			r.Shuffle(len(keys), func(i, j int) {
  1007  				keys[i], keys[j] = keys[j], keys[i]
  1008  				values[i], values[j] = values[j], values[i]
  1009  			})
  1010  
  1011  			for i := range keys {
  1012  				mapPairs := values[i]
  1013  				for j := range mapPairs {
  1014  					err = b.MapSet(keys[i], mapPairs[j])
  1015  					require.Nil(t, err)
  1016  				}
  1017  			}
  1018  		})
  1019  
  1020  		t.Run("flush to disk", func(t *testing.T) {
  1021  			require.Nil(t, b.FlushAndSwitch())
  1022  		})
  1023  
  1024  		t.Run("third third (%3==2) memtable only", func(t *testing.T) {
  1025  			pairs := 20
  1026  			valuesPerPair := 3
  1027  			var keys [][]byte
  1028  			var values [][]MapPair
  1029  
  1030  			for i := 0; i < pairs; i++ {
  1031  				if i%3 != 2 {
  1032  					continue
  1033  				}
  1034  
  1035  				keys = append(keys, []byte(fmt.Sprintf("row-%03d", i)))
  1036  				curValues := make([]MapPair, valuesPerPair)
  1037  				for j := range curValues {
  1038  					curValues[j] = MapPair{
  1039  						Key:   []byte(fmt.Sprintf("row-%03d-key-%d", i, j)),
  1040  						Value: []byte(fmt.Sprintf("row-%03d-value-%d", i, j)),
  1041  					}
  1042  				}
  1043  
  1044  				values = append(values, curValues)
  1045  			}
  1046  
  1047  			// shuffle to make sure the BST isn't accidentally in order
  1048  			r.Shuffle(len(keys), func(i, j int) {
  1049  				keys[i], keys[j] = keys[j], keys[i]
  1050  				values[i], values[j] = values[j], values[i]
  1051  			})
  1052  
  1053  			for i := range keys {
  1054  				mapPairs := values[i]
  1055  				for j := range mapPairs {
  1056  					err = b.MapSet(keys[i], mapPairs[j])
  1057  					require.Nil(t, err)
  1058  				}
  1059  			}
  1060  
  1061  			// no flush for this one, so this segment stays in the memtable
  1062  		})
  1063  
  1064  		t.Run("seek from somewhere in the middle", func(t *testing.T) {
  1065  			expectedKeys := [][]byte{
  1066  				[]byte("row-016"),
  1067  				[]byte("row-017"),
  1068  				[]byte("row-018"),
  1069  				[]byte("row-019"),
  1070  			}
  1071  			expectedValues := [][]MapPair{
  1072  				{
  1073  					{Key: []byte("row-016-key-0"), Value: []byte("row-016-value-0")},
  1074  					{Key: []byte("row-016-key-1"), Value: []byte("row-016-value-1")},
  1075  					{Key: []byte("row-016-key-2"), Value: []byte("row-016-value-2")},
  1076  				},
  1077  				{
  1078  					{Key: []byte("row-017-key-0"), Value: []byte("row-017-value-0")},
  1079  					{Key: []byte("row-017-key-1"), Value: []byte("row-017-value-1")},
  1080  					{Key: []byte("row-017-key-2"), Value: []byte("row-017-value-2")},
  1081  				},
  1082  				{
  1083  					{Key: []byte("row-018-key-0"), Value: []byte("row-018-value-0")},
  1084  					{Key: []byte("row-018-key-1"), Value: []byte("row-018-value-1")},
  1085  					{Key: []byte("row-018-key-2"), Value: []byte("row-018-value-2")},
  1086  				},
  1087  				{
  1088  					{Key: []byte("row-019-key-0"), Value: []byte("row-019-value-0")},
  1089  					{Key: []byte("row-019-key-1"), Value: []byte("row-019-value-1")},
  1090  					{Key: []byte("row-019-key-2"), Value: []byte("row-019-value-2")},
  1091  				},
  1092  			}
  1093  
  1094  			var retrievedKeys [][]byte
  1095  			var retrievedValues [][]MapPair
  1096  			c := b.MapCursor()
  1097  			defer c.Close()
  1098  			for k, v := c.Seek([]byte("row-016")); k != nil; k, v = c.Next() {
  1099  				retrievedKeys = append(retrievedKeys, k)
  1100  				retrievedValues = append(retrievedValues, v)
  1101  			}
  1102  
  1103  			assert.Equal(t, expectedKeys, retrievedKeys)
  1104  
  1105  			require.Equal(t, len(expectedValues), len(retrievedValues))
  1106  			for i := range expectedValues {
  1107  				assert.ElementsMatch(t, expectedValues[i], retrievedValues[i])
  1108  			}
  1109  		})
  1110  
  1111  		t.Run("start from beginning", func(t *testing.T) {
  1112  			expectedKeys := [][]byte{
  1113  				[]byte("row-000"),
  1114  				[]byte("row-001"),
  1115  				[]byte("row-002"),
  1116  			}
  1117  			expectedValues := [][]MapPair{
  1118  				{
  1119  					{Key: []byte("row-000-key-0"), Value: []byte("row-000-value-0")},
  1120  					{Key: []byte("row-000-key-1"), Value: []byte("row-000-value-1")},
  1121  					{Key: []byte("row-000-key-2"), Value: []byte("row-000-value-2")},
  1122  				},
  1123  				{
  1124  					{Key: []byte("row-001-key-0"), Value: []byte("row-001-value-0")},
  1125  					{Key: []byte("row-001-key-1"), Value: []byte("row-001-value-1")},
  1126  					{Key: []byte("row-001-key-2"), Value: []byte("row-001-value-2")},
  1127  				},
  1128  				{
  1129  					{Key: []byte("row-002-key-0"), Value: []byte("row-002-value-0")},
  1130  					{Key: []byte("row-002-key-1"), Value: []byte("row-002-value-1")},
  1131  					{Key: []byte("row-002-key-2"), Value: []byte("row-002-value-2")},
  1132  				},
  1133  			}
  1134  
  1135  			var retrievedKeys [][]byte
  1136  			var retrievedValues [][]MapPair
  1137  			c := b.MapCursor()
  1138  			defer c.Close()
  1139  			retrieved := 0
  1140  			for k, v := c.First(); k != nil && retrieved < 3; k, v = c.Next() {
  1141  				retrieved++
  1142  				retrievedKeys = append(retrievedKeys, k)
  1143  				retrievedValues = append(retrievedValues, v)
  1144  			}
  1145  
  1146  			assert.Equal(t, expectedKeys, retrievedKeys)
  1147  
  1148  			require.Equal(t, len(expectedValues), len(retrievedValues))
  1149  			for i := range expectedValues {
  1150  				assert.ElementsMatch(t, expectedValues[i], retrievedValues[i])
  1151  			}
  1152  		})
  1153  
  1154  		t.Run("delete/replace an existing map key/value pair", func(t *testing.T) {
  1155  			row := []byte("row-002")
  1156  			pair := MapPair{
  1157  				Key:   []byte("row-002-key-1"),           // existing key
  1158  				Value: []byte("row-002-value-1-updated"), // updated value
  1159  			}
  1160  
  1161  			require.Nil(t, b.MapSet(row, pair))
  1162  
  1163  			row = []byte("row-001")
  1164  			key := []byte("row-001-key-1")
  1165  
  1166  			require.Nil(t, b.MapDeleteKey(row, key))
  1167  		})
  1168  
  1169  		t.Run("verify update is contained", func(t *testing.T) {
  1170  			expectedKeys := [][]byte{
  1171  				[]byte("row-001"),
  1172  				[]byte("row-002"),
  1173  			}
  1174  			expectedValues := [][]MapPair{
  1175  				{
  1176  					{Key: []byte("row-001-key-0"), Value: []byte("row-001-value-0")},
  1177  					// key-1 was deleted
  1178  					{Key: []byte("row-001-key-2"), Value: []byte("row-001-value-2")},
  1179  				},
  1180  				{
  1181  					{Key: []byte("row-002-key-0"), Value: []byte("row-002-value-0")},
  1182  					{Key: []byte("row-002-key-1"), Value: []byte("row-002-value-1-updated")},
  1183  					{Key: []byte("row-002-key-2"), Value: []byte("row-002-value-2")},
  1184  				},
  1185  			}
  1186  
  1187  			var retrievedKeys [][]byte
  1188  			var retrievedValues [][]MapPair
  1189  			c := b.MapCursor()
  1190  			defer c.Close()
  1191  			retrieved := 0
  1192  			for k, v := c.Seek([]byte("row-001")); k != nil && retrieved < 2; k, v = c.Next() {
  1193  				retrieved++
  1194  				retrievedKeys = append(retrievedKeys, k)
  1195  				retrievedValues = append(retrievedValues, v)
  1196  			}
  1197  
  1198  			assert.Equal(t, expectedKeys, retrievedKeys)
  1199  
  1200  			require.Equal(t, len(expectedValues), len(retrievedValues))
  1201  			for i := range expectedValues {
  1202  				assert.ElementsMatch(t, expectedValues[i], retrievedValues[i])
  1203  			}
  1204  		})
  1205  
  1206  		t.Run("one final flush to disk", func(t *testing.T) {
  1207  			require.Nil(t, b.FlushAndSwitch())
  1208  		})
  1209  
  1210  		t.Run("verify update is contained - after flushing the update", func(t *testing.T) {
  1211  			expectedKeys := [][]byte{
  1212  				[]byte("row-001"),
  1213  				[]byte("row-002"),
  1214  			}
  1215  			expectedValues := [][]MapPair{
  1216  				{
  1217  					{Key: []byte("row-001-key-0"), Value: []byte("row-001-value-0")},
  1218  					// key-1 was deleted
  1219  					{Key: []byte("row-001-key-2"), Value: []byte("row-001-value-2")},
  1220  				},
  1221  				{
  1222  					{Key: []byte("row-002-key-0"), Value: []byte("row-002-value-0")},
  1223  					{Key: []byte("row-002-key-1"), Value: []byte("row-002-value-1-updated")},
  1224  					{Key: []byte("row-002-key-2"), Value: []byte("row-002-value-2")},
  1225  				},
  1226  			}
  1227  
  1228  			var retrievedKeys [][]byte
  1229  			var retrievedValues [][]MapPair
  1230  			c := b.MapCursor()
  1231  			defer c.Close()
  1232  			retrieved := 0
  1233  			for k, v := c.Seek([]byte("row-001")); k != nil && retrieved < 2; k, v = c.Next() {
  1234  				retrieved++
  1235  				retrievedKeys = append(retrievedKeys, k)
  1236  				retrievedValues = append(retrievedValues, v)
  1237  			}
  1238  
  1239  			assert.Equal(t, expectedKeys, retrievedKeys)
  1240  
  1241  			require.Equal(t, len(expectedValues), len(retrievedValues))
  1242  			for i := range expectedValues {
  1243  				assert.ElementsMatch(t, expectedValues[i], retrievedValues[i])
  1244  			}
  1245  		})
  1246  	})
  1247  }