github.com/cilium/statedb@v0.3.2/part/part_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package part
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/binary"
     9  	"fmt"
    10  	"math/rand"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  const numObjectsToInsert = 1000
    19  
    20  // Tests that the right channels are closed during insertion.
    21  func Test_insertion_and_watches(t *testing.T) {
    22  	assertOpen := func(t testing.TB, c <-chan struct{}) {
    23  		t.Helper()
    24  		assert.NotNil(t, c)
    25  		select {
    26  		case <-c:
    27  			t.Error("closed, but should be open")
    28  		default:
    29  		}
    30  	}
    31  
    32  	assertClosed := func(t testing.TB, c <-chan struct{}) {
    33  		t.Helper()
    34  		assert.NotNil(t, c)
    35  		select {
    36  		case <-c:
    37  		default:
    38  			t.Error("open, but should be closed")
    39  		}
    40  	}
    41  
    42  	// Replacement
    43  	{
    44  		tree := New[int]()
    45  
    46  		txn := tree.Txn()
    47  		txn.Insert([]byte("abc"), 1)
    48  		txn.Insert([]byte("ab"), 2)
    49  		txn.Insert([]byte("abd"), 3)
    50  		tree = txn.Commit()
    51  
    52  		_, w, f := tree.Get([]byte("ab"))
    53  		assert.True(t, f)
    54  		assertOpen(t, w)
    55  		_, w2 := tree.Prefix([]byte("a"))
    56  		assertOpen(t, w2)
    57  		_, w3, f2 := tree.Get([]byte("abc"))
    58  		assert.True(t, f2)
    59  		assertOpen(t, w3)
    60  		_, w4 := tree.Prefix([]byte("abc"))
    61  		assertOpen(t, w4)
    62  
    63  		_, _, tree = tree.Insert([]byte("ab"), 42)
    64  		assertClosed(t, w)
    65  		assertClosed(t, w2)
    66  
    67  		assertOpen(t, w3)
    68  
    69  		// Prefix watch is closed as it's on the "ab" node
    70  		// since that's the closest non-leaf node to "abc" leaf.
    71  		assertClosed(t, w4)
    72  	}
    73  
    74  	// Root to leaf and back.
    75  	// N4() -- Insert(a, 1) -> N4() -- Insert(b, 2) -> N4()
    76  	//                         /                      /   \
    77  	//                      L(a, 1)             L(a, 1)    L(b, 2)
    78  	// The Get(a) channel closes, but not Prefix(a) since the prefix search
    79  	// uses the root channel.
    80  	{
    81  		tree := New[int]()
    82  
    83  		_, _, tree = tree.Insert([]byte("a"), 1)
    84  
    85  		_, w, f := tree.Get([]byte("a"))
    86  		assert.True(t, f)
    87  		assertOpen(t, w)
    88  		_, w2 := tree.Prefix([]byte("a"))
    89  		assertOpen(t, w2)
    90  
    91  		_, _, tree = tree.Insert([]byte("b"), 2)
    92  		assertOpen(t, w)
    93  		assertClosed(t, w2)
    94  	}
    95  
    96  	// "Lateral movement" - L(a, 1) should become the leaf of the root N4
    97  	{
    98  		tree := New[int]()
    99  
   100  		_, _, tree = tree.Insert([]byte("a"), 1)
   101  
   102  		_, w, f := tree.Get([]byte("a"))
   103  		assert.True(t, f)
   104  		assertOpen(t, w)
   105  		_, w2 := tree.Prefix([]byte("a"))
   106  		assertOpen(t, w2)
   107  
   108  		txn := tree.Txn()
   109  		txn.Insert([]byte("aa"), 2)
   110  		txn.Insert([]byte("ab"), 3)
   111  		assertOpen(t, w) // shouldn't close until commit
   112  		assertOpen(t, w2)
   113  		tree = txn.Commit()
   114  
   115  		assertOpen(t, w)
   116  		assertClosed(t, w2)
   117  	}
   118  
   119  	// Second variant of "lateral movement" of leaf node.
   120  	//    N4(a) - L(a,1)                       N4(a) - L(a,1)
   121  	//  /      \         -- Insert(abc) -->   /     \
   122  	// L(aa,2) L(ab,3)                     L(aa,2)  N4(b) - L(ab, 3)
   123  	//                                              /
   124  	//                                             L(abc, 4)
   125  	{
   126  		tree := New[int]()
   127  
   128  		txn := tree.Txn()
   129  		txn.Insert([]byte("a"), 1)
   130  		txn.Insert([]byte("aa"), 2)
   131  		txn.Insert([]byte("ab"), 3)
   132  		tree = txn.Commit()
   133  
   134  		_, w, f := tree.Get([]byte("ab"))
   135  		assert.True(t, f)
   136  		assertOpen(t, w)
   137  
   138  		_, w2 := tree.Prefix([]byte("ab"))
   139  		assertOpen(t, w2)
   140  
   141  		// This should move the L(ab) laterally and insert a N4(ab) with a L(abc, 4)
   142  		// child
   143  		_, _, tree = tree.Insert([]byte("abc"), 4)
   144  		// The precise "ab" chan should be open.
   145  		assertOpen(t, w)
   146  		// The "ab" prefix chan should be closed.
   147  		assertClosed(t, w2)
   148  	}
   149  
   150  }
   151  
   152  func Test_commonPrefix(t *testing.T) {
   153  	check := func(a, b, common string) {
   154  		actual := string(commonPrefix([]byte(a), []byte(b)))
   155  		if actual != common {
   156  			t.Fatalf("expected commonPrefix(%q, %q) to equal %q, but got %q",
   157  				a, b, common, actual)
   158  		}
   159  	}
   160  
   161  	check("", "", "")
   162  	check("", "a", "")
   163  	check("a", "", "")
   164  	check("a", "a", "a")
   165  	check("a", "b", "")
   166  	check("abc", "d", "")
   167  	check("d", "abc", "")
   168  	check("ab", "abc", "ab")
   169  	check("abc", "ab", "ab")
   170  }
   171  
   172  func Test_search(t *testing.T) {
   173  	tree := New[[]byte](RootOnlyWatch)
   174  	_, _, tree = tree.Insert([]byte("a"), []byte("a"))
   175  	_, _, tree = tree.Insert([]byte("ba"), []byte("ba"))
   176  	_, _, tree = tree.Insert([]byte("bb"), []byte("bb"))
   177  	_, _, tree = tree.Insert([]byte("c"), []byte("c"))
   178  	_, _, tree = tree.Insert([]byte("ca"), []byte("ca"))
   179  
   180  	v, _, ok := tree.Get([]byte("nope"))
   181  	if ok {
   182  		t.Fatalf("found unexpected value: %v", v)
   183  	}
   184  
   185  	for _, key := range []string{"a", "ba", "bb"} {
   186  		v, _, ok = tree.Get([]byte(key))
   187  		if !ok || string(v) != key {
   188  			t.Fatalf("%q not found (%v) or mismatch %q", key, ok, v)
   189  		}
   190  	}
   191  }
   192  
   193  func uint64Key(n uint64) []byte {
   194  	return binary.BigEndian.AppendUint64(nil, n)
   195  }
   196  
   197  func hexKey(n uint64) []byte {
   198  	return []byte(fmt.Sprintf("%x", n))
   199  }
   200  
   201  func uint32Key(n uint32) []byte {
   202  	return binary.BigEndian.AppendUint32(nil, n)
   203  }
   204  
   205  func Test_simple_delete(t *testing.T) {
   206  	tree := New[uint64]()
   207  	txn := tree.Txn()
   208  
   209  	_, hadOld := txn.Insert(uint64Key(1), 1)
   210  	require.False(t, hadOld)
   211  
   212  	_, hadOld = txn.Insert(uint64Key(2), 2)
   213  	require.False(t, hadOld)
   214  
   215  	_, hadOld = txn.Delete(uint64Key(1))
   216  	require.True(t, hadOld)
   217  
   218  	_, _, ok := txn.Get(uint64Key(1))
   219  	require.False(t, ok)
   220  }
   221  
   222  func Test_delete(t *testing.T) {
   223  	tree := New[uint64]()
   224  
   225  	// Do multiple rounds with the same tree.
   226  	for round := 0; round < 100; round++ {
   227  		// Use a random amount of keys in random order to exercise different
   228  		// tree structures each time.
   229  		numKeys := 10 + rand.Intn(1000)
   230  		t.Logf("numKeys=%d", numKeys)
   231  
   232  		keys := []uint64{}
   233  		for i := uint64(1); i < uint64(numKeys); i++ {
   234  			keys = append(keys, i)
   235  		}
   236  		hadOld := false
   237  
   238  		// Insert the keys in random order.
   239  		rand.Shuffle(len(keys), func(i, j int) {
   240  			keys[i], keys[j] = keys[j], keys[i]
   241  		})
   242  
   243  		txn := tree.Txn()
   244  		for _, i := range keys {
   245  			_, hadOld = txn.Insert(uint64Key(i), i)
   246  			assert.False(t, hadOld)
   247  			v, _, ok := txn.Get(uint64Key(i))
   248  			assert.True(t, ok)
   249  			assert.EqualValues(t, v, i)
   250  		}
   251  		tree = txn.Commit()
   252  		assert.Equal(t, len(keys), tree.Len())
   253  
   254  		// Delete the keys in random order.
   255  		rand.Shuffle(len(keys), func(i, j int) {
   256  			keys[i], keys[j] = keys[j], keys[i]
   257  		})
   258  
   259  		txn = tree.Txn()
   260  		for _, i := range keys {
   261  			v, _, ok := txn.Get(uint64Key(i))
   262  			assert.True(t, ok)
   263  			assert.EqualValues(t, v, i)
   264  			v, hadOld = txn.Delete(uint64Key(i))
   265  			assert.True(t, hadOld)
   266  			assert.EqualValues(t, v, i)
   267  			_, _, ok = txn.Get(uint64Key(i))
   268  			assert.False(t, ok)
   269  		}
   270  		tree = txn.Commit()
   271  
   272  		assert.Equal(t, 0, tree.Len())
   273  		for _, i := range keys {
   274  			_, _, ok := tree.Get(uint64Key(i))
   275  			assert.False(t, ok)
   276  		}
   277  
   278  		// And finally insert the keys back one more time
   279  		// in random order.
   280  		rand.Shuffle(len(keys), func(i, j int) {
   281  			keys[i], keys[j] = keys[j], keys[i]
   282  		})
   283  
   284  		watches := map[uint64]<-chan struct{}{}
   285  
   286  		txn = tree.Txn()
   287  		for _, i := range keys {
   288  			_, hadOld = txn.Insert(uint64Key(i), i)
   289  			assert.False(t, hadOld)
   290  			v, watch, ok := txn.Get(uint64Key(i))
   291  			watches[i] = watch
   292  			assert.True(t, ok)
   293  			assert.EqualValues(t, v, i)
   294  		}
   295  		tree = txn.Commit()
   296  		assert.Equal(t, len(keys), tree.Len())
   297  
   298  		// Do few rounds of lookups and deletions.
   299  		for step := 0; step < 2; step++ {
   300  			// Lookup with a Txn
   301  			txn = tree.Txn()
   302  			for _, i := range keys {
   303  				v, _, ok := txn.Get(uint64Key(i))
   304  				assert.True(t, ok)
   305  				assert.EqualValues(t, v, i)
   306  			}
   307  			txn = nil
   308  
   309  			// Test that full iteration is ordered
   310  			iter := tree.Iterator()
   311  			prev := uint64(0)
   312  			num := 0
   313  			for {
   314  				_, v, ok := iter.Next()
   315  				if !ok {
   316  					break
   317  				}
   318  				num++
   319  				require.Greater(t, v, prev)
   320  				prev = v
   321  			}
   322  			assert.Equal(t, num, len(keys))
   323  
   324  			// Test that lowerbound iteration is ordered and correct
   325  			idx := len(keys) / 2
   326  			prev = keys[idx]
   327  			num = 0
   328  			start := prev + 1
   329  			iter = tree.LowerBound(uint64Key(start))
   330  			obs := []uint64{}
   331  			for {
   332  				_, v, ok := iter.Next()
   333  				if !ok {
   334  					break
   335  				}
   336  				num++
   337  				obs = append(obs, v)
   338  				require.Greater(t, v, prev)
   339  				prev = v
   340  			}
   341  			exp := 0
   342  			for _, k := range keys {
   343  				if k >= start {
   344  					exp++
   345  				}
   346  			}
   347  			if !assert.Equal(t, exp, num) {
   348  				t.Logf("LowerBound from %d failed", start)
   349  				t.Logf("observed: %v", obs)
   350  				tree.PrintTree()
   351  				t.Fatal()
   352  			}
   353  
   354  			// Test that prefix iteration is ordered and correct
   355  			prev = 0
   356  			iter, _ = tree.Prefix([]byte{})
   357  			for {
   358  				_, v, ok := iter.Next()
   359  				if !ok {
   360  					break
   361  				}
   362  				require.Greater(t, v, prev)
   363  				prev = v
   364  			}
   365  
   366  			// Remove half the keys
   367  			for _, k := range keys[:len(keys)/2] {
   368  				_, _, tree = tree.Delete(uint64Key(k))
   369  			}
   370  			keys = keys[len(keys)/2:]
   371  		}
   372  
   373  		// Remove everything remaining with iteration
   374  		txn = tree.Txn()
   375  		iter := txn.Iterator()
   376  		for k, _, ok := iter.Next(); ok; k, _, ok = iter.Next() {
   377  			_, hadOld = txn.Delete(k)
   378  			assert.True(t, hadOld)
   379  
   380  			_, _, ok := txn.Get(k)
   381  			assert.False(t, ok)
   382  		}
   383  
   384  		// Check that we can iterate with the transaction and
   385  		// everything is gone.
   386  		iter = txn.Iterator()
   387  		_, _, ok := iter.Next()
   388  		assert.False(t, ok)
   389  
   390  		tree = txn.Commit()
   391  
   392  		// Check that all the watch channels closed
   393  		for _, watch := range watches {
   394  			<-watch
   395  		}
   396  
   397  		// Check that everything is gone after commit.
   398  		for _, i := range keys {
   399  			_, _, ok := tree.Get(uint64Key(i))
   400  			assert.False(t, ok)
   401  		}
   402  
   403  		assert.Equal(t, 0, tree.Len())
   404  	}
   405  }
   406  
   407  func Test_watch(t *testing.T) {
   408  	tree := New[[]byte]()
   409  
   410  	// Insert 'a', get it and check watch channel is not closed.
   411  	_, _, tree = tree.Insert([]byte("a"), []byte("a"))
   412  
   413  	_, watchA, ok := tree.Get([]byte("a"))
   414  	if !ok {
   415  		t.Fatal("expected to find 'a'")
   416  	}
   417  	select {
   418  	case <-watchA:
   419  		t.Fatal("did not expect watch to be closed")
   420  	default:
   421  	}
   422  
   423  	// Get 'b' that should not exist and the watch channel should
   424  	// not be closed.
   425  	_, watchB, ok := tree.Get([]byte("b"))
   426  	assert.False(t, ok, "Get(b)")
   427  
   428  	select {
   429  	case <-watchB:
   430  		t.Fatal("did not expect watch to be closed")
   431  	default:
   432  	}
   433  
   434  	// Modify 'a'. Now the watch channel should close.
   435  	_, _, tree = tree.Insert([]byte("a"), []byte("aa"))
   436  
   437  	select {
   438  	case <-watchA:
   439  	case <-time.After(10 * time.Second):
   440  		t.Fatal("expected watch channel to close")
   441  	}
   442  
   443  	v, _, ok := tree.Get([]byte("a"))
   444  	if !ok {
   445  		t.Fatal("expected to find 'a'")
   446  	}
   447  	if string(v) != "aa" {
   448  		t.Fatalf("expected value 'aa', got '%s'", v)
   449  	}
   450  
   451  	// Insert 'b'. Now the watch channel should close.
   452  	_, _, tree = tree.Insert([]byte("b"), []byte("b"))
   453  	select {
   454  	case <-watchB:
   455  	case <-time.After(10 * time.Second):
   456  		t.Fatal("expected watch channel to close")
   457  	}
   458  }
   459  
   460  func Test_insert(t *testing.T) {
   461  	tree := New[int]()
   462  	for i := 0; i < 10000; i++ {
   463  		key := binary.NativeEndian.AppendUint32(nil, uint32(i))
   464  		_, _, tree = tree.Insert(key, i)
   465  	}
   466  	for i := 0; i < 10000; i++ {
   467  		key := binary.NativeEndian.AppendUint32(nil, uint32(i))
   468  		_, _, ok := tree.Get(key)
   469  		if !ok {
   470  			t.Fatalf("%d not found", i)
   471  		}
   472  	}
   473  }
   474  
   475  func Test_modify(t *testing.T) {
   476  	tree := New[int]()
   477  	key := []byte{1}
   478  
   479  	// Modify without the value existing inserts it.
   480  	_, _, tree = tree.Modify(key, func(x int) int { return 1 })
   481  
   482  	v, _, ok := tree.Get(key)
   483  	require.True(t, ok)
   484  	require.Equal(t, 1, v)
   485  
   486  	txn := tree.Txn()
   487  	for i := range 10000 {
   488  		old, hadOld := txn.Modify(key, func(x int) int { return x + 1 })
   489  		require.True(t, hadOld)
   490  		require.Equal(t, i+1, old)
   491  	}
   492  	tree = txn.Commit()
   493  
   494  	v, _, ok = tree.Get(key)
   495  	require.True(t, ok)
   496  	require.Equal(t, 10001, v)
   497  }
   498  
   499  func Test_replaceRoot(t *testing.T) {
   500  	tree := New[int]()
   501  	keyA := []byte{'a'}
   502  	keyB := []byte{'a', 'b'}
   503  	_, _, tree = tree.Insert(keyA, 1)
   504  	_, _, tree = tree.Insert(keyB, 3)
   505  	_, _, tree = tree.Delete(keyA)
   506  	_, _, tree = tree.Insert(keyA, 2)
   507  	val, _, ok := tree.Get(keyA)
   508  	if !ok || val != 2 {
   509  		t.Fatalf("%v not found", keyA)
   510  	}
   511  	val, _, ok = tree.Get(keyB)
   512  	if !ok || val != 3 {
   513  		t.Fatalf("%v not found", keyB)
   514  	}
   515  }
   516  
   517  func Test_deleteRoot(t *testing.T) {
   518  	tree := New[int]()
   519  	keyA := []byte{'a'}
   520  	_, _, tree = tree.Insert(keyA, 1)
   521  	_, _, tree = tree.Delete(keyA)
   522  	_, _, ok := tree.Get(keyA)
   523  	if ok {
   524  		t.Fatal("Root exists")
   525  	}
   526  }
   527  
   528  func Test_deleteIntermediate(t *testing.T) {
   529  	tree := New[int]()
   530  	keyA := []byte{'a'}
   531  	keyAB := []byte{'a', 'b'}
   532  	keyABC := []byte{'a', 'b', 'c'}
   533  	_, _, tree = tree.Insert(keyA, 1)
   534  	_, _, tree = tree.Insert(keyAB, 2)
   535  	_, _, tree = tree.Insert(keyABC, 3)
   536  	_, _, tree = tree.Delete(keyAB)
   537  	_, _, ok := tree.Get(keyA)
   538  	if !ok {
   539  		t.Fatal("A doesn't exist")
   540  	}
   541  	_, _, ok = tree.Get(keyAB)
   542  	if ok {
   543  		t.Fatal("AB exists")
   544  	}
   545  	_, _, ok = tree.Get(keyABC)
   546  	if !ok {
   547  		t.Fatal("ABC doesn't exist")
   548  	}
   549  }
   550  
   551  func Test_deleteNonExistantIntermediate(t *testing.T) {
   552  	tree := New[int]()
   553  	keyAB := []byte{'a', 'b'}
   554  	keyAC := []byte{'a', 'c'}
   555  	_, _, tree = tree.Insert(keyAB, 1)
   556  	_, _, tree = tree.Insert(keyAC, 2)
   557  	_, _, tree = tree.Delete([]byte{'a'})
   558  	_, _, ok := tree.Get(keyAB)
   559  	if !ok {
   560  		t.Fatal("AB doesn't exist")
   561  	}
   562  	_, _, ok = tree.Get(keyAC)
   563  	if !ok {
   564  		t.Fatal("AC doesn't exist")
   565  	}
   566  }
   567  
   568  func Test_deleteNonExistantCommonPrefix(t *testing.T) {
   569  	tree := New[int]()
   570  	keyAB := []byte{'a', 'b', 'c'}
   571  	_, _, tree = tree.Insert(keyAB, 1)
   572  	_, _, tree = tree.Delete([]byte{'a', 'b', 'e'})
   573  	_, _, ok := tree.Get(keyAB)
   574  	if !ok {
   575  		t.Fatal("AB doesn't exist")
   576  	}
   577  }
   578  
   579  func Test_replace(t *testing.T) {
   580  	tree := New[int]()
   581  	key := binary.BigEndian.AppendUint32(nil, uint32(0))
   582  
   583  	var v int
   584  	var hadOld bool
   585  	_, hadOld, tree = tree.Insert(key, 1)
   586  	require.False(t, hadOld)
   587  
   588  	v, hadOld, tree = tree.Insert(key, 2)
   589  	require.True(t, hadOld)
   590  	require.EqualValues(t, 1, v)
   591  }
   592  
   593  func Test_prefix(t *testing.T) {
   594  	tree := New[[]byte]()
   595  	ins := func(s string) { _, _, tree = tree.Insert([]byte(s), []byte(s)) }
   596  	ins("a")
   597  	ins("ab")
   598  	ins("abc")
   599  	ins("abcd")
   600  	ins("bc")
   601  
   602  	iter, _ := tree.Prefix([]byte("ab"))
   603  	k, v, ok := iter.Next()
   604  	assert.True(t, ok)
   605  	assert.Equal(t, []byte("ab"), k)
   606  	assert.Equal(t, []byte("ab"), v)
   607  
   608  	k, v, ok = iter.Next()
   609  	assert.True(t, ok)
   610  	assert.Equal(t, []byte("abc"), k)
   611  	assert.Equal(t, []byte("abc"), v)
   612  
   613  	k, v, ok = iter.Next()
   614  	assert.True(t, ok)
   615  	assert.Equal(t, []byte("abcd"), k)
   616  	assert.Equal(t, []byte("abcd"), v)
   617  
   618  	_, _, ok = iter.Next()
   619  	assert.False(t, ok)
   620  }
   621  
   622  func Test_deleteEmptyKey(t *testing.T) {
   623  	tree := New[string]()
   624  
   625  	_, _, tree = tree.Insert([]byte{}, "x")
   626  
   627  	v, watch, ok := tree.Get([]byte{})
   628  	assert.True(t, ok)
   629  	assert.Equal(t, "x", v)
   630  	select {
   631  	case <-watch:
   632  		t.Fatalf("channel closed")
   633  	default:
   634  	}
   635  
   636  	_, _, tree = tree.Delete([]byte{})
   637  
   638  	_, _, ok = tree.Get([]byte{})
   639  	assert.False(t, ok)
   640  
   641  	select {
   642  	case <-watch:
   643  	default:
   644  		t.Fatalf("channel not closed")
   645  	}
   646  }
   647  
   648  func Test_txn(t *testing.T) {
   649  	tree := New[uint64]()
   650  	ins := func(n uint64) { _, _, tree = tree.Insert(uint64Key(n), n) }
   651  
   652  	var iter *Iterator[uint64]
   653  	next := func(exOK bool, exVal int) {
   654  		t.Helper()
   655  		_, v, ok := iter.Next()
   656  		if assert.Equal(t, exOK, ok) {
   657  			assert.EqualValues(t, exVal, v)
   658  		}
   659  	}
   660  
   661  	for i := 1; i <= 3; i++ {
   662  		ins(1)
   663  		ins(2)
   664  		ins(3)
   665  	}
   666  
   667  	txn := tree.Txn()
   668  	txn.Delete(uint64Key(2))
   669  	txn.Delete(uint64Key(3))
   670  	txn.Insert(uint64Key(4), 4)
   671  
   672  	iter = txn.Iterator()
   673  	next(true, 1)
   674  	next(true, 4)
   675  	next(false, 0)
   676  
   677  	_ = txn.Commit() // Ignore the new tree
   678  
   679  	// Original tree should be untouched.
   680  	for i := 1; i <= 3; i++ {
   681  		_, _, ok := tree.Get(uint64Key(uint64(i)))
   682  		assert.True(t, ok, "Get(%d)", i)
   683  	}
   684  
   685  	iter = tree.Iterator()
   686  	next(true, 1)
   687  	next(true, 2)
   688  	next(true, 3)
   689  	next(false, 0)
   690  }
   691  
   692  func Test_lowerbound(t *testing.T) {
   693  	tree := New[uint64]()
   694  	ins := func(n int) { _, _, tree = tree.Insert(uint64Key(uint64(n)), uint64(n)) }
   695  
   696  	// Insert 1..3
   697  	for i := 1; i <= 3; i++ {
   698  		ins(i)
   699  	}
   700  
   701  	var iter *Iterator[uint64]
   702  	next := func(exOK bool, exVal int) {
   703  		t.Helper()
   704  		_, v, ok := iter.Next()
   705  		require.Equal(t, exOK, ok)
   706  		require.EqualValues(t, exVal, v)
   707  	}
   708  
   709  	iter = tree.LowerBound([]byte{})
   710  	next(true, 1)
   711  	next(true, 2)
   712  	next(true, 3)
   713  	next(false, 0)
   714  
   715  	iter = tree.LowerBound(uint64Key(0))
   716  	next(true, 1)
   717  	next(true, 2)
   718  	next(true, 3)
   719  	next(false, 0)
   720  
   721  	iter = tree.LowerBound(uint64Key(3))
   722  	next(true, 3)
   723  	next(false, 0)
   724  
   725  	iter = tree.LowerBound(uint64Key(4))
   726  	next(false, 0)
   727  }
   728  
   729  func Test_lowerbound_edge_cases(t *testing.T) {
   730  	tree := New[uint32]()
   731  	keys := []uint32{}
   732  	ins := func(n uint32) {
   733  		_, _, tree = tree.Insert(uint32Key(n), n)
   734  		keys = append(keys, n)
   735  	}
   736  
   737  	var iter *Iterator[uint32]
   738  	next := func(exOK bool, exVal uint32) {
   739  		t.Helper()
   740  		_, v, ok := iter.Next()
   741  		assert.Equal(t, exOK, ok)
   742  		require.Equal(t, exVal, v)
   743  	}
   744  
   745  	// Empty tree
   746  	iter = tree.LowerBound([]byte{})
   747  	next(false, 0)
   748  	iter = tree.LowerBound(uint32Key(0x1))
   749  	next(false, 0)
   750  
   751  	// case 0: Leaf at the root
   752  	ins(0x1)
   753  	iter = tree.LowerBound([]byte{})
   754  	next(true, 0x1)
   755  	next(false, 0)
   756  	iter = tree.LowerBound(uint32Key(0x1))
   757  	next(true, 0x1)
   758  	next(false, 0)
   759  	iter = tree.LowerBound(uint32Key(0x2))
   760  	next(false, 0)
   761  
   762  	// Two leafs, node4 root
   763  	ins(0x2)
   764  	iter = tree.LowerBound([]byte{})
   765  	next(true, 0x1)
   766  	next(true, 0x2)
   767  	next(false, 0)
   768  	iter = tree.LowerBound(uint32Key(0x2))
   769  	next(true, 0x2)
   770  	next(false, 0)
   771  	iter = tree.LowerBound(uint32Key(0x3))
   772  	next(false, 0)
   773  
   774  	// Different prefix
   775  	ins(0x0101)
   776  	iter = tree.LowerBound(uint32Key(0x100))
   777  	next(true, 0x101)
   778  	next(false, 0)
   779  
   780  	// case -1: Matching prefix (0x1??) but only smaller nodes behind it
   781  	ins(0x1100)
   782  	iter = tree.LowerBound(uint32Key(0x102))
   783  	next(true, 0x1100)
   784  	next(false, 0)
   785  
   786  	// Short search keys
   787  	ins(0x010000)
   788  
   789  	iter = tree.LowerBound([]byte{1})
   790  	next(false, 0)
   791  
   792  	iter = tree.LowerBound([]byte{0, 0})
   793  	next(true, 0x1)
   794  	next(true, 0x2)
   795  	next(true, 0x0101)
   796  	next(true, 0x1100)
   797  	next(true, 0x010000)
   798  	next(false, 0)
   799  
   800  	iter = tree.LowerBound([]byte{0, 1, 0})
   801  	next(true, 0x010000)
   802  	next(false, 0)
   803  
   804  	// Node256
   805  	for i := 1; i < 50; i += 2 { // add less than 256 for some holes in node256.children
   806  		n := uint32(0x20000 + i)
   807  		_, _, tree = tree.Insert(uint32Key(n), n)
   808  		keys = append(keys, n)
   809  	}
   810  
   811  	iter = tree.LowerBound(uint32Key(0x20000))
   812  	for i := 1; i < 50; i += 2 {
   813  		n := uint32(0x20000 + i)
   814  		next(true, n)
   815  	}
   816  	next(false, 0)
   817  
   818  	iter = tree.LowerBound([]byte{})
   819  	for i := range keys {
   820  		next(true, keys[i])
   821  	}
   822  	next(false, 0)
   823  
   824  }
   825  
   826  func Test_lowerbound_regression(t *testing.T) {
   827  	// Regression test for bug in lowerbound() where the lowerbound search ended up
   828  	// in a smaller node and thought there were no larger nodes in the tree to iterate
   829  	// over.
   830  
   831  	tree := New[uint64]()
   832  	ins := func(n uint64) { _, _, tree = tree.Insert(uint64Key(uint64(n)), uint64(n)) }
   833  
   834  	values := []uint64{
   835  		70370, // ... 1 18 226
   836  		70411, // ... 1 19 11
   837  		70412,
   838  	}
   839  
   840  	for _, v := range values {
   841  		ins(v)
   842  	}
   843  
   844  	iter := tree.LowerBound(uint64Key(70399))
   845  	i := 1
   846  	for _, obj, ok := iter.Next(); ok; _, obj, ok = iter.Next() {
   847  		require.Equal(t, values[i], obj)
   848  		i++
   849  	}
   850  	require.Equal(t, len(values), i)
   851  }
   852  
   853  func Test_prefix_regression(t *testing.T) {
   854  	// Regression test for bug where a long key and a short key was inserted and where
   855  	// the keys shared a prefix.
   856  
   857  	tree := New[string]()
   858  	_, _, tree = tree.Insert([]byte("foobar"), "foobar")
   859  	_, _, tree = tree.Insert([]byte("foo"), "foo")
   860  
   861  	s, _, found := tree.Get([]byte("foobar"))
   862  	require.True(t, found)
   863  	require.Equal(t, s, "foobar")
   864  
   865  	s, _, found = tree.Get([]byte("foo"))
   866  	require.True(t, found)
   867  	require.Equal(t, s, "foo")
   868  }
   869  
   870  func Test_iterate(t *testing.T) {
   871  	sizes := []int{1, 10, 100, 1000}
   872  	for _, size := range sizes {
   873  		t.Logf("size=%d", size)
   874  		tree := New[uint64]()
   875  		keys := []uint64{}
   876  		for i := 0; i < size; i++ {
   877  			keys = append(keys, uint64(i))
   878  		}
   879  
   880  		rand.Shuffle(len(keys), func(i, j int) {
   881  			keys[i], keys[j] = keys[j], keys[i]
   882  		})
   883  
   884  		watches := []<-chan struct{}{}
   885  		for _, i := range keys {
   886  			_, _, tree = tree.Insert(hexKey(uint64(i)), uint64(i))
   887  			v, watch, ok := tree.Get(hexKey(uint64(i)))
   888  			require.True(t, ok, "Get %x", hexKey(uint64(i)))
   889  			require.Equal(t, v, uint64(i), "values equal")
   890  			require.NotNil(t, watch, "watch not nil")
   891  			watches = append(watches, watch)
   892  		}
   893  
   894  		// Check that watches are not closed.
   895  		for _, w := range watches {
   896  			select {
   897  			case <-w:
   898  				tree.PrintTree()
   899  				t.Fatalf("watch channel %p closed unexpectedly", w)
   900  			default:
   901  			}
   902  		}
   903  
   904  		// Insert again and validate that the old value is returned and
   905  		// all watch channels are closed.
   906  		for _, i := range keys {
   907  			var old uint64
   908  			var hadOld bool
   909  			old, hadOld, tree = tree.Insert(hexKey(uint64(i)), uint64(i))
   910  			assert.True(t, hadOld, "hadOld")
   911  			assert.Equal(t, old, uint64(i))
   912  		}
   913  		t.Logf("waiting for watches to close")
   914  		for _, w := range watches {
   915  			<-w
   916  		}
   917  
   918  		// The order for the variable length keys is based on prefix,
   919  		// so we would get 0x0105 before 0x02, since it has "smaller"
   920  		// prefix. Hence we just check we see all values.
   921  		iter := tree.Iterator()
   922  		i := int(0)
   923  		for key, obj, ok := iter.Next(); ok; key, obj, ok = iter.Next() {
   924  			if !bytes.Equal(hexKey(obj), key) {
   925  				t.Fatalf("expected %x, got %x", key, hexKey(obj))
   926  			}
   927  			i++
   928  		}
   929  		if !assert.Equal(t, size, i) {
   930  			tree.PrintTree()
   931  			t.FailNow()
   932  		}
   933  
   934  		_, _, ok := iter.Next()
   935  		require.False(t, ok, "expected exhausted iterator to keep returning false")
   936  
   937  		// Delete keys one at a time, in random order.
   938  		rand.Shuffle(len(keys), func(i, j int) {
   939  			keys[i], keys[j] = keys[j], keys[i]
   940  		})
   941  		txn := tree.Txn()
   942  		n := rand.Intn(20)
   943  		for i, k := range keys {
   944  			txn.Delete(hexKey(uint64(k)))
   945  
   946  			n--
   947  			if n <= 0 {
   948  				tree = txn.Commit()
   949  				txn = tree.Txn()
   950  				n = rand.Intn(20)
   951  			}
   952  
   953  			// All the rest of the keys can still be found
   954  			for _, j := range keys[i+1:] {
   955  				n, _, found := txn.Get(hexKey(j))
   956  				if !assert.True(t, found) || !assert.Equal(t, n, j) {
   957  					fmt.Println("--- new tree")
   958  					txn.PrintTree()
   959  					t.FailNow()
   960  				}
   961  			}
   962  		}
   963  
   964  	}
   965  }
   966  
   967  func Test_closed_chan_regression(t *testing.T) {
   968  	tree := New[uint64]()
   969  	_, _, tree = tree.Insert(hexKey(uint64(0)), uint64(0))
   970  	_, _, tree = tree.Insert(hexKey(uint64(1)), uint64(1))
   971  	_, _, tree = tree.Insert(hexKey(uint64(2)), uint64(2))
   972  	_, _, tree = tree.Insert(hexKey(uint64(3)), uint64(3))
   973  
   974  	txn := tree.Txn()
   975  	txn.Delete(hexKey(uint64(3)))
   976  	txn.Delete(hexKey(uint64(1)))
   977  	tree = txn.Commit()
   978  
   979  	// No reachable channel should be closed
   980  	for _, c := range tree.root.children() {
   981  		select {
   982  		case <-c.watch:
   983  			t.Logf("%x %p closed already", c.prefix, &c.watch)
   984  			t.FailNow()
   985  		default:
   986  		}
   987  	}
   988  }
   989  
   990  func Test_lowerbound_bigger(t *testing.T) {
   991  	tree := New[uint64]()
   992  	ins := func(n int) { _, _, tree = tree.Insert(uint64Key(uint64(n)), uint64(n)) }
   993  
   994  	// Insert 5..10
   995  	for i := 5; i <= 10; i++ {
   996  		ins(i)
   997  	}
   998  
   999  	iter := tree.LowerBound([]byte{4})
  1000  	_, _, ok := iter.Next()
  1001  	require.False(t, ok)
  1002  }
  1003  
  1004  func Benchmark_Insert_RootOnlyWatch(b *testing.B) {
  1005  	benchmark_Insert(b, RootOnlyWatch)
  1006  }
  1007  
  1008  func Benchmark_Insert(b *testing.B) {
  1009  	benchmark_Insert(b)
  1010  }
  1011  
  1012  func benchmark_Insert(b *testing.B, opts ...Option) {
  1013  	for n := 0; n < b.N; n++ {
  1014  		tree := New[int](opts...)
  1015  		txn := tree.Txn()
  1016  		for i := 0; i < numObjectsToInsert; i++ {
  1017  			key := binary.BigEndian.AppendUint32(nil, uint32(numObjectsToInsert+i))
  1018  			txn.Insert(key, numObjectsToInsert+i)
  1019  		}
  1020  		txn.Commit()
  1021  	}
  1022  	b.StopTimer()
  1023  	b.ReportMetric(float64(b.N*numObjectsToInsert)/b.Elapsed().Seconds(), "objects/sec")
  1024  }
  1025  
  1026  func benchmark_Modify_vs_GetInsert(b *testing.B, doGetInsert bool) {
  1027  	tree := New[int](RootOnlyWatch)
  1028  	keys := [][]byte{}
  1029  	for i := 0; i < numObjectsToInsert; i++ {
  1030  		key := binary.BigEndian.AppendUint32(nil, uint32(numObjectsToInsert+i))
  1031  		_, _, tree = tree.Insert(key, numObjectsToInsert+i)
  1032  		keys = append(keys, key)
  1033  	}
  1034  	b.ResetTimer()
  1035  	for n := 0; n < b.N; n++ {
  1036  		txn := tree.Txn()
  1037  		for _, key := range keys {
  1038  			if doGetInsert {
  1039  				v, _, _ := txn.Get(key)
  1040  				txn.Insert(key, v)
  1041  			} else {
  1042  				txn.Modify(key, func(x int) int { return x })
  1043  			}
  1044  		}
  1045  		tree = txn.Commit()
  1046  	}
  1047  	b.ReportMetric(float64(b.N*numObjectsToInsert)/b.Elapsed().Seconds(), "objects/sec")
  1048  }
  1049  
  1050  func Benchmark_Modify(b *testing.B) {
  1051  	benchmark_Modify_vs_GetInsert(b, false)
  1052  }
  1053  
  1054  func Benchmark_GetInsert(b *testing.B) {
  1055  	benchmark_Modify_vs_GetInsert(b, true)
  1056  }
  1057  
  1058  func Benchmark_Replace(b *testing.B) {
  1059  	benchmark_Replace(b, true)
  1060  }
  1061  
  1062  func Benchmark_Replace_RootOnlyWatch(b *testing.B) {
  1063  	benchmark_Replace(b, false)
  1064  }
  1065  
  1066  func benchmark_Replace(b *testing.B, watching bool) {
  1067  	tree := New[int](RootOnlyWatch)
  1068  	txn := tree.Txn()
  1069  	for i := 0; i < numObjectsToInsert; i++ {
  1070  		key := binary.BigEndian.AppendUint32(nil, uint32(numObjectsToInsert+i))
  1071  		txn.Insert(key, numObjectsToInsert+i)
  1072  	}
  1073  
  1074  	b.ResetTimer()
  1075  	key := binary.BigEndian.AppendUint32(nil, uint32(0))
  1076  	for n := 0; n < b.N; n++ {
  1077  		txn.Insert(key, 0)
  1078  	}
  1079  	b.StopTimer()
  1080  	b.ReportMetric(float64(b.N)/b.Elapsed().Seconds(), "objects/sec")
  1081  }
  1082  
  1083  func Benchmark_txn_1(b *testing.B) {
  1084  	benchmark_txn_batch(b, 1)
  1085  }
  1086  
  1087  func Benchmark_txn_10(b *testing.B) {
  1088  	benchmark_txn_batch(b, 10)
  1089  }
  1090  
  1091  func Benchmark_txn_100(b *testing.B) {
  1092  	benchmark_txn_batch(b, 100)
  1093  }
  1094  
  1095  func Benchmark_txn_1000(b *testing.B) {
  1096  	benchmark_txn_batch(b, 1000)
  1097  }
  1098  
  1099  func benchmark_txn_batch(b *testing.B, batchSize int) {
  1100  	tree := New[int](RootOnlyWatch)
  1101  	n := b.N
  1102  	for n > 0 {
  1103  		txn := tree.Txn()
  1104  		for j := 0; j < batchSize; j++ {
  1105  			txn.Insert(uint64Key(uint64(j)), j)
  1106  		}
  1107  		tree = txn.Commit()
  1108  		n -= batchSize
  1109  	}
  1110  	txn := tree.Txn()
  1111  	for j := 0; j < n; j++ {
  1112  		txn.Insert(uint64Key(uint64(j)), j)
  1113  	}
  1114  	txn.Commit()
  1115  	b.ReportMetric(float64(b.N)/b.Elapsed().Seconds(), "objects/sec")
  1116  }
  1117  
  1118  func Benchmark_txn_delete_1(b *testing.B) {
  1119  	benchmark_txn_delete_batch(b, 1)
  1120  }
  1121  
  1122  func Benchmark_txn_delete_10(b *testing.B) {
  1123  	benchmark_txn_delete_batch(b, 10)
  1124  }
  1125  
  1126  func Benchmark_txn_delete_100(b *testing.B) {
  1127  	benchmark_txn_delete_batch(b, 100)
  1128  }
  1129  
  1130  func Benchmark_txn_delete_1000(b *testing.B) {
  1131  	benchmark_txn_delete_batch(b, 1000)
  1132  }
  1133  
  1134  func benchmark_txn_delete_batch(b *testing.B, batchSize int) {
  1135  	tree := New[int](RootOnlyWatch)
  1136  	for j := 0; j < batchSize; j++ {
  1137  		_, _, tree = tree.Insert(uint64Key(uint64(j)), j)
  1138  	}
  1139  	b.ResetTimer()
  1140  
  1141  	n := b.N
  1142  	for n > 0 {
  1143  		txn := tree.Txn()
  1144  		for j := 0; j < batchSize; j++ {
  1145  			txn.Delete(uint64Key(uint64(j)))
  1146  		}
  1147  		n -= batchSize
  1148  	}
  1149  	txn := tree.Txn()
  1150  	for j := 0; j < n; j++ {
  1151  		txn.Delete(uint64Key(uint64(j)))
  1152  	}
  1153  	b.ReportMetric(float64(b.N)/b.Elapsed().Seconds(), "objects/sec")
  1154  }
  1155  
  1156  func Benchmark_Get(b *testing.B) {
  1157  	tree := New[uint64](RootOnlyWatch)
  1158  	for j := uint64(0); j < numObjectsToInsert; j++ {
  1159  		_, _, tree = tree.Insert(uint64Key(j), j)
  1160  	}
  1161  	b.ResetTimer()
  1162  	var key [8]byte // to avoid the allocation
  1163  	for i := 0; i < b.N; i++ {
  1164  		for j := uint64(0); j < numObjectsToInsert; j++ {
  1165  			binary.BigEndian.PutUint64(key[:], j)
  1166  			v, _, ok := tree.Get(key[:])
  1167  			if v != j {
  1168  				b.Fatalf("impossible: %d != %d || %v", v, j, ok)
  1169  			}
  1170  		}
  1171  
  1172  	}
  1173  	b.ReportMetric(float64(numObjectsToInsert*b.N)/b.Elapsed().Seconds(), "objects/sec")
  1174  }
  1175  
  1176  func Benchmark_Iterate(b *testing.B) {
  1177  	tree := New[uint64](RootOnlyWatch)
  1178  	for j := uint64(1); j <= numObjectsToInsert; j++ {
  1179  		_, _, tree = tree.Insert(uint64Key(j), j)
  1180  	}
  1181  	b.ResetTimer()
  1182  	for i := 0; i < b.N; i++ {
  1183  		iter := tree.Iterator()
  1184  		for _, j, ok := iter.Next(); ok; _, j, ok = iter.Next() {
  1185  			if j < 1 || j > numObjectsToInsert+1 {
  1186  				b.Fatalf("impossible value: %d", j)
  1187  			}
  1188  		}
  1189  	}
  1190  	b.ReportMetric(float64(numObjectsToInsert*b.N)/b.Elapsed().Seconds(), "objects/sec")
  1191  }
  1192  
  1193  func Benchmark_Hashmap_Insert(b *testing.B) {
  1194  	for i := 0; i < b.N; i++ {
  1195  		m := map[uint64]uint64{}
  1196  		for j := uint64(0); j < numObjectsToInsert; j++ {
  1197  			m[j] = j
  1198  		}
  1199  		if len(m) != numObjectsToInsert {
  1200  			b.Fatalf("%d != %d", len(m), numObjectsToInsert)
  1201  		}
  1202  	}
  1203  	b.ReportMetric(float64(numObjectsToInsert*b.N)/b.Elapsed().Seconds(), "objects/sec")
  1204  }
  1205  
  1206  func Benchmark_Hashmap_Get_Uint64(b *testing.B) {
  1207  	m := map[uint64]uint64{}
  1208  	for j := uint64(0); j < numObjectsToInsert; j++ {
  1209  		m[j] = j
  1210  	}
  1211  	b.ResetTimer()
  1212  	for i := 0; i < b.N; i++ {
  1213  		for j := uint64(0); j < numObjectsToInsert; j++ {
  1214  			if m[j] != j {
  1215  				b.Fatalf("impossible: %d != %d", m[j], j)
  1216  			}
  1217  		}
  1218  	}
  1219  	b.ReportMetric(float64(numObjectsToInsert*b.N)/b.Elapsed().Seconds(), "objects/sec")
  1220  }
  1221  
  1222  func Benchmark_Hashmap_Get_Bytes(b *testing.B) {
  1223  	var k [8]byte
  1224  	m := map[[8]byte]uint64{}
  1225  	for j := uint64(0); j < numObjectsToInsert; j++ {
  1226  		binary.BigEndian.PutUint64(k[:], j)
  1227  		m[k] = j
  1228  	}
  1229  	b.ResetTimer()
  1230  	for i := 0; i < b.N; i++ {
  1231  		for j := uint64(0); j < numObjectsToInsert; j++ {
  1232  			binary.BigEndian.PutUint64(k[:], j)
  1233  			if m[k] != j {
  1234  				b.Fatalf("impossible: %d != %d", m[k], j)
  1235  			}
  1236  		}
  1237  	}
  1238  	b.ReportMetric(float64(numObjectsToInsert*b.N)/b.Elapsed().Seconds(), "objects/sec")
  1239  }