github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bdb_test.go (about)

     1  package bitree
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/require"
     9  	"github.com/zuoyebang/bitalosdb/bitpage"
    10  	"github.com/zuoyebang/bitalosdb/bitree/bdb"
    11  	"github.com/zuoyebang/bitalosdb/internal/consts"
    12  	"github.com/zuoyebang/bitalosdb/internal/sortedkv"
    13  	"github.com/zuoyebang/bitalosdb/internal/utils"
    14  )
    15  
    16  func TestBitree_Bdb_Seek(t *testing.T) {
    17  	defer os.RemoveAll(testDir)
    18  	os.RemoveAll(testDir)
    19  
    20  	seekFunc := func(index int) {
    21  		btree, _ := testOpenBitree()
    22  
    23  		pn, sentinel, closer := btree.FindKeyPageNum(consts.BdbMaxKey)
    24  		require.Equal(t, bitpage.PageNum(1), pn)
    25  		require.Equal(t, consts.BdbMaxKey, sentinel)
    26  		closer()
    27  
    28  		if index == 0 {
    29  			for i := 0; i < 10; i++ {
    30  				key := makeTestKey(i)
    31  				pn, sentinel, closer = btree.FindKeyPageNum(key)
    32  				require.Equal(t, bitpage.PageNum(1), pn)
    33  				require.Equal(t, consts.BdbMaxKey, sentinel)
    34  				closer()
    35  			}
    36  			err := btree.bdb.Update(func(tx *bdb.Tx) error {
    37  				bkt := tx.Bucket(consts.BdbBucketName)
    38  				if bkt == nil {
    39  					return bdb.ErrBucketNotFound
    40  				}
    41  				for i := 2; i < 10; i++ {
    42  					if i%3 != 0 {
    43  						continue
    44  					}
    45  
    46  					key := makeTestKey(i)
    47  					require.NoError(t, bkt.Put(key, bitpage.PageNum(i).ToByte()))
    48  				}
    49  				return nil
    50  			})
    51  			btree.txPool.Update()
    52  			require.NoError(t, err)
    53  		}
    54  
    55  		checkValue := func(i, exp int) {
    56  			key := makeTestKey(i)
    57  			pn, sentinel, closer = btree.FindKeyPageNum(key)
    58  			require.Equal(t, bitpage.PageNum(exp), pn)
    59  			closer()
    60  			if exp == 1 {
    61  				require.Equal(t, consts.BdbMaxKey, sentinel)
    62  			} else {
    63  				require.Equal(t, makeTestKey(exp), sentinel)
    64  			}
    65  		}
    66  
    67  		checkValue(0, 3)
    68  		checkValue(3, 3)
    69  		checkValue(12, 3)
    70  		checkValue(4, 6)
    71  		checkValue(5, 6)
    72  		checkValue(51, 6)
    73  		checkValue(6, 6)
    74  		checkValue(60, 9)
    75  		checkValue(899, 9)
    76  		checkValue(9, 9)
    77  		checkValue(90, 1)
    78  		checkValue(91, 1)
    79  
    80  		require.NoError(t, testBitreeClose(btree))
    81  	}
    82  
    83  	for i := 0; i < 5; i++ {
    84  		seekFunc(i)
    85  	}
    86  }
    87  
    88  func TestBitree_Bdb_Seek_LargeKey(t *testing.T) {
    89  	defer os.RemoveAll(testDir)
    90  	os.RemoveAll(testDir)
    91  
    92  	btree, _ := testOpenBitree()
    93  	keyPrefix := utils.FuncRandBytes(1100)
    94  	makeLargeKey := func(i int) []byte {
    95  		return []byte(fmt.Sprintf("bdb_%s_%d", keyPrefix, i))
    96  	}
    97  	err := btree.bdb.Update(func(tx *bdb.Tx) error {
    98  		bkt := tx.Bucket(consts.BdbBucketName)
    99  		if bkt == nil {
   100  			return bdb.ErrBucketNotFound
   101  		}
   102  		for i := 2; i < 200; i++ {
   103  			if i%3 != 0 {
   104  				continue
   105  			}
   106  			key := makeLargeKey(i)
   107  			require.NoError(t, bkt.Put(key, bitpage.PageNum(i).ToByte()))
   108  		}
   109  		return nil
   110  	})
   111  	btree.txPool.Update()
   112  	require.NoError(t, err)
   113  
   114  	expPns := []int{102, 102, 21, 3, 42, 51, 6, 72, 81, 9, 102, 111, 12, 132, 141, 15, 162, 171, 18, 192, 21, 21, 24, 24,
   115  		24, 27, 27, 27, 3, 3, 30, 33, 33, 33, 36, 36, 36, 39, 39, 39, 42, 42, 42, 45, 45, 45, 48, 48, 48, 51, 51, 51, 54, 54, 54,
   116  		57, 57, 57, 6, 6, 60, 63, 63, 63, 66, 66, 66, 69, 69, 69, 72, 72, 72, 75, 75, 75, 78, 78, 78, 81, 81, 81, 84, 84, 84, 87,
   117  		87, 87, 9, 9, 90, 93, 93, 93, 96, 96, 96, 99, 99, 99, 102, 102, 102, 105, 105, 105, 108, 108, 108, 111, 111, 111, 114,
   118  		114, 114, 117, 117, 117, 12, 12, 120, 123, 123, 123, 126, 126, 126, 129, 129, 129, 132, 132, 132, 135, 135, 135,
   119  		138, 138, 138, 141, 141, 141, 144, 144, 144, 147, 147, 147, 15, 15, 150, 153, 153, 153, 156, 156, 156, 159, 159,
   120  		159, 162, 162, 162, 165, 165, 165, 168, 168, 168, 171, 171, 171, 174, 174, 174, 177, 177, 177, 18, 18, 180, 183,
   121  		183, 183, 186, 186, 186, 189, 189, 189, 192, 192, 192, 195, 195, 195, 198, 198, 198, 21}
   122  
   123  	for i := 0; i < 200; i++ {
   124  		key := makeLargeKey(i)
   125  		pn, _, closer := btree.FindKeyPageNum(key)
   126  		require.Equal(t, bitpage.PageNum(expPns[i]), pn)
   127  		closer()
   128  	}
   129  
   130  	checkValue := func(i, exp int) {
   131  		key := makeLargeKey(i)
   132  		pn, sentinel, closer := btree.FindKeyPageNum(key)
   133  		require.Equal(t, bitpage.PageNum(exp), pn)
   134  		closer()
   135  		if exp == 1 {
   136  			require.Equal(t, consts.BdbMaxKey, sentinel)
   137  		} else {
   138  			require.Equal(t, makeLargeKey(exp), sentinel)
   139  		}
   140  	}
   141  
   142  	checkValue(201, 21)
   143  	checkValue(255, 27)
   144  	checkValue(402, 42)
   145  	checkValue(518, 54)
   146  	checkValue(627, 63)
   147  	checkValue(734, 75)
   148  	checkValue(846, 87)
   149  	checkValue(899, 9)
   150  	checkValue(953, 96)
   151  	checkValue(999, 1)
   152  
   153  	require.NoError(t, testBitreeClose(btree))
   154  }
   155  
   156  func TestBitree_Bdb_SeekPrefixDeleteKey(t *testing.T) {
   157  	for _, isLarge := range []bool{false, true} {
   158  		t.Run(fmt.Sprintf("isLarge=%t", isLarge), func(t *testing.T) {
   159  			defer os.RemoveAll(testDir)
   160  			os.RemoveAll(testDir)
   161  
   162  			btree, _ := testOpenBitree()
   163  			defer testBitreeClose(btree)
   164  
   165  			var keyPrefix, largePrefix []byte
   166  			slotId := uint16(1)
   167  			verNum := 5
   168  			verStart := uint64(1024)
   169  			verEnd := uint64(1030)
   170  			if isLarge {
   171  				largePrefix = utils.FuncRandBytes(1100)
   172  			} else {
   173  				largePrefix = []byte("")
   174  			}
   175  
   176  			makeKey := func(n int, v uint64) []byte {
   177  				keyPrefix = []byte(fmt.Sprintf("bdb_%s_%d", largePrefix, n))
   178  				return sortedkv.MakeKey2(keyPrefix, slotId, v)
   179  			}
   180  
   181  			err := btree.bdb.Update(func(tx *bdb.Tx) error {
   182  				bkt := tx.Bucket(consts.BdbBucketName)
   183  				if bkt == nil {
   184  					return bdb.ErrBucketNotFound
   185  				}
   186  
   187  				for ver := verStart; ver <= verEnd; ver++ {
   188  					for i := 1; i <= verNum; i++ {
   189  						key := makeKey(i, ver)
   190  						require.NoError(t, bkt.Put(key, bitpage.PageNum(i).ToByte()))
   191  					}
   192  				}
   193  				return nil
   194  			})
   195  			btree.txPool.Update()
   196  			require.NoError(t, err)
   197  
   198  			checkSeek := func(n int, version uint64) {
   199  				rtx := btree.txPool.Load()
   200  				defer rtx.Unref(true)
   201  
   202  				bkt := rtx.Bucket()
   203  				if bkt == nil {
   204  					t.Fatal("bkt is nil")
   205  				}
   206  
   207  				seek := makeKey(n, version)
   208  				pns, sentinels := btree.findPrefixDeleteKeyPageNums(seek, bkt.Cursor())
   209  
   210  				if version > verEnd {
   211  					require.Equal(t, 1, len(pns))
   212  					require.Equal(t, 1, len(sentinels))
   213  					require.Equal(t, consts.BdbMaxKey, sentinels[0])
   214  					return
   215  				}
   216  
   217  				expNum := verNum - n + 2
   218  				sentinelsNum := len(sentinels)
   219  				require.Equal(t, expNum, len(pns))
   220  				require.Equal(t, expNum, sentinelsNum)
   221  
   222  				seekPrefixDelete := btree.opts.KeyPrefixDeleteFunc(seek)
   223  				for i := range sentinels {
   224  					s := btree.opts.KeyPrefixDeleteFunc(sentinels[i])
   225  					exp := seekPrefixDelete
   226  					if i == sentinelsNum-1 {
   227  						if version == verEnd {
   228  							require.Equal(t, consts.BdbMaxKey, sentinels[i])
   229  							break
   230  						}
   231  						exp = seekPrefixDelete + 1
   232  					}
   233  					require.Equal(t, exp, s)
   234  				}
   235  			}
   236  
   237  			for ver := verStart; ver <= verEnd+5; ver++ {
   238  				for i := 1; i <= verNum; i++ {
   239  					checkSeek(i, ver)
   240  				}
   241  			}
   242  		})
   243  	}
   244  }