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

     1  // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package bitpage
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"os"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/cockroachdb/errors"
    25  	"github.com/stretchr/testify/require"
    26  	"github.com/zuoyebang/bitalosdb/internal/bindex"
    27  	"github.com/zuoyebang/bitalosdb/internal/cache/lrucache"
    28  	"github.com/zuoyebang/bitalosdb/internal/consts"
    29  	"github.com/zuoyebang/bitalosdb/internal/hash"
    30  	"github.com/zuoyebang/bitalosdb/internal/options"
    31  	"github.com/zuoyebang/bitalosdb/internal/sortedkv"
    32  )
    33  
    34  func testNewBlockCache() *lrucache.LruCache {
    35  	cacheOpts := &options.CacheOptions{
    36  		Size:     consts.BitpageDefaultBlockCacheSize,
    37  		Shards:   consts.BitpageBlockCacheShards,
    38  		HashSize: consts.BitpageBlockCacheHashSize,
    39  	}
    40  	cache := lrucache.NewLrucache(cacheOpts)
    41  
    42  	return cache
    43  }
    44  
    45  func testNewArrayTable(dir string, params []bool) (*arrayTable, *atOptions) {
    46  	atCacheOpts := &atCacheOptions{
    47  		cache: testNewBlockCache(),
    48  		id:    1 << 10,
    49  	}
    50  	opts := &atOptions{
    51  		useMapIndex:       params[0],
    52  		usePrefixCompress: params[1],
    53  		useBlockCompress:  params[2],
    54  	}
    55  	at, err := newArrayTable(dir, opts, atCacheOpts)
    56  	if err != nil {
    57  		panic(err)
    58  	}
    59  	return at, opts
    60  }
    61  
    62  func testOpenArrayTable(dir string) *arrayTable {
    63  	atCacheOpts := &atCacheOptions{
    64  		cache: testNewBlockCache(),
    65  		id:    1 << 10,
    66  	}
    67  	at, err := openArrayTable(dir, atCacheOpts)
    68  	if err != nil {
    69  		panic(err)
    70  	}
    71  	return at
    72  }
    73  
    74  func TestArrayTable_Stmap(t *testing.T) {
    75  	os.Remove(testPath)
    76  	count := 100
    77  	var keys [][]byte
    78  	for i := 0; i < count; i++ {
    79  		keys = append(keys, []byte(fmt.Sprintf("test_at_key_%d", i)))
    80  	}
    81  
    82  	hindex := bindex.NewHashIndex(true)
    83  	hindex.InitWriter()
    84  	for i := range keys {
    85  		key := keys[i]
    86  		khash := hash.Crc32(key)
    87  		hindex.Add(khash, uint32(i+1))
    88  	}
    89  
    90  	tbl := testNewTable()
    91  	defer func() {
    92  		require.NoError(t, testCloseTable(tbl))
    93  	}()
    94  
    95  	fmt.Println("stmap.Size()", hindex.Size())
    96  	mapOffset, err := tbl.alloc(hindex.Size())
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  
   101  	hindex.SetWriter(tbl.data[mapOffset:])
   102  	if !hindex.Serialize() {
   103  		t.Fatal(errors.New("hash_index Serialize Fail"))
   104  	}
   105  
   106  	hindex.Finish()
   107  
   108  	for i := range keys {
   109  		key := keys[i]
   110  		khash := hash.Crc32(key)
   111  		v, ok := hindex.Get32(khash)
   112  		if ok != true || v != uint32(i+1) {
   113  			t.Fatalf("Get---key:%s, ok:%#v, expact-val:%d, real-val:%d\n", string(key), ok, uint32(i+1), v)
   114  		}
   115  	}
   116  }
   117  
   118  func TestArrayTable_WriteRead(t *testing.T) {
   119  	testcase(func(index int, params []bool) {
   120  		dir := testPath
   121  		defer os.RemoveAll(dir)
   122  		os.RemoveAll(dir)
   123  
   124  		count := 10000
   125  		kvList := testMakeSortedKV(count, uint64(1), 100)
   126  
   127  		at, atOpts := testNewArrayTable(dir, params)
   128  		atVersion := getAtVersionByOpts(atOpts)
   129  		require.Equal(t, atVersion, at.header.version)
   130  
   131  		for i := 0; i < count; i++ {
   132  			_, err := at.writeItem(kvList[i].Key.UserKey, kvList[i].Value)
   133  			require.NoError(t, err)
   134  		}
   135  		require.NoError(t, at.writeFinish())
   136  		require.Equal(t, at.tbl.fileStatSize(), int64(at.size))
   137  		fmt.Println(index, atVersion, at.size)
   138  
   139  		seekFunc := func(a *arrayTable) {
   140  			iter := a.newIter(nil)
   141  			i := 0
   142  			for key, val := iter.First(); key != nil; key, val = iter.Next() {
   143  				require.Equal(t, kvList[i].Key.UserKey, key.UserKey)
   144  				require.Equal(t, kvList[i].Value, val)
   145  				i++
   146  			}
   147  			require.NoError(t, iter.Close())
   148  			require.Equal(t, count, i)
   149  
   150  			for j := 0; j < count; j++ {
   151  				skey := kvList[j].Key.UserKey
   152  				val, exist, _, closer := a.get(skey, hash.Crc32(skey))
   153  				require.Equal(t, true, exist)
   154  				require.Equal(t, kvList[j].Value, val)
   155  				if closer != nil {
   156  					closer()
   157  				}
   158  
   159  				it1 := a.newIter(nil)
   160  				ik, v := it1.SeekGE(skey)
   161  				require.Equal(t, skey, ik.UserKey)
   162  				require.Equal(t, kvList[j].Value, v)
   163  				require.NoError(t, it1.Close())
   164  			}
   165  
   166  			for _, n := range []int{99999, 90001} {
   167  				skey := sortedkv.MakeSortedKey(n)
   168  				_, exist, _, closer := a.get(skey, hash.Crc32(skey))
   169  				require.Equal(t, false, exist)
   170  				if closer != nil {
   171  					closer()
   172  				}
   173  			}
   174  		}
   175  
   176  		seekFunc(at)
   177  		require.NoError(t, at.close())
   178  
   179  		at1 := testOpenArrayTable(dir)
   180  		require.Equal(t, atVersion, at1.header.version)
   181  		seekFunc(at1)
   182  		require.NoError(t, at1.close())
   183  	})
   184  }
   185  
   186  func TestArrayTable_IterCompact(t *testing.T) {
   187  	for _, params := range [][]bool{
   188  		{true, true, true},
   189  		{true, false, true},
   190  	} {
   191  		func(param []bool) {
   192  			dir := testPath
   193  			defer os.RemoveAll(dir)
   194  			os.RemoveAll(dir)
   195  
   196  			count := 10000
   197  			kvList := testMakeSortedKV(count, uint64(1), 10)
   198  
   199  			at, atOpts := testNewArrayTable(dir, param)
   200  			atVersion := getAtVersionByOpts(atOpts)
   201  			require.Equal(t, atVersion, at.header.version)
   202  
   203  			for i := 0; i < count; i++ {
   204  				_, err := at.writeItem(kvList[i].Key.UserKey, kvList[i].Value)
   205  				require.NoError(t, err)
   206  			}
   207  			require.NoError(t, at.writeFinish())
   208  
   209  			require.Equal(t, at.tbl.fileStatSize(), int64(at.size))
   210  			require.Equal(t, int64(0), at.blockCache.Size())
   211  
   212  			seekFunc := func(a *arrayTable, opts *iterOptions) {
   213  				iter := a.newIter(opts)
   214  				i := 0
   215  				for key, val := iter.First(); key != nil; key, val = iter.Next() {
   216  					require.Equal(t, kvList[i].Key.UserKey, key.UserKey)
   217  					require.Equal(t, kvList[i].Value, val)
   218  					i++
   219  				}
   220  				require.NoError(t, iter.Close())
   221  				require.Equal(t, count, i)
   222  
   223  				for j := 0; j < count; j++ {
   224  					skey := kvList[j].Key.UserKey
   225  					it1 := a.newIter(opts)
   226  					ik, v := it1.SeekGE(skey)
   227  					require.Equal(t, skey, ik.UserKey)
   228  					require.Equal(t, kvList[j].Value, v)
   229  					require.NoError(t, it1.Close())
   230  				}
   231  
   232  				for _, n := range []int{99999, 90001} {
   233  					skey := sortedkv.MakeSortedKey(n)
   234  					_, exist, _, closer := a.get(skey, hash.Crc32(skey))
   235  					require.Equal(t, false, exist)
   236  					require.Equal(t, true, closer == nil)
   237  				}
   238  			}
   239  
   240  			seekFunc(at, &iterCompactOpts)
   241  			require.Equal(t, int64(1), at.blockCache.Metrics().Count)
   242  			seekFunc(at, nil)
   243  			require.Equal(t, int64(250), at.blockCache.Metrics().Count)
   244  			require.NoError(t, at.close())
   245  		}(params)
   246  	}
   247  }
   248  
   249  func TestArrayTable_IterSeek(t *testing.T) {
   250  	testcase(func(index int, params []bool) {
   251  		dir := testPath
   252  		defer os.RemoveAll(dir)
   253  		os.RemoveAll(dir)
   254  
   255  		at, atOpts := testNewArrayTable(dir, params)
   256  		atVersion := getAtVersionByOpts(atOpts)
   257  		count := 120
   258  		kvList := testMakeSortedKV(count, uint64(1), 200)
   259  
   260  		for i := 0; i < 100; i++ {
   261  			_, err := at.writeItem(kvList[i].Key.UserKey, kvList[i].Value)
   262  			require.NoError(t, err)
   263  		}
   264  		require.NoError(t, at.writeFinish())
   265  
   266  		checkKV := func(i int, ik *internalKey, iv []byte) {
   267  			if i == -1 {
   268  				require.Equal(t, nilInternalKey, ik)
   269  			} else {
   270  				require.Equal(t, kvList[i].Key.UserKey, ik.UserKey)
   271  				require.Equal(t, kvList[i].Value, iv)
   272  			}
   273  		}
   274  
   275  		seekFunc := func(a *arrayTable) {
   276  			iter := a.newIter(nil)
   277  			ik, iv := iter.First()
   278  			checkKV(0, ik, iv)
   279  
   280  			ik, iv = iter.Next()
   281  			checkKV(1, ik, iv)
   282  
   283  			ik, iv = iter.Prev()
   284  			checkKV(0, ik, iv)
   285  
   286  			ik, iv = iter.Last()
   287  			checkKV(99, ik, iv)
   288  
   289  			ik, iv = iter.SeekGE(kvList[15].Key.UserKey)
   290  			checkKV(15, ik, iv)
   291  			ik, iv = iter.SeekGE(kvList[51].Key.UserKey)
   292  			checkKV(51, ik, iv)
   293  			ik, iv = iter.SeekGE(sortedkv.MakeSortedKey(-1))
   294  			checkKV(0, ik, iv)
   295  			ik, iv = iter.SeekGE(kvList[110].Key.UserKey)
   296  			checkKV(-1, ik, iv)
   297  
   298  			ik, iv = iter.SeekLT(kvList[15].Key.UserKey)
   299  			checkKV(14, ik, iv)
   300  			ik, iv = iter.SeekLT(kvList[51].Key.UserKey)
   301  			checkKV(50, ik, iv)
   302  			ik, iv = iter.Prev()
   303  			checkKV(49, ik, iv)
   304  			ik, iv = iter.SeekLT(kvList[1].Key.UserKey)
   305  			checkKV(0, ik, iv)
   306  			ik, iv = iter.SeekLT(kvList[110].Key.UserKey)
   307  			checkKV(99, ik, iv)
   308  			ik, iv = iter.SeekLT(kvList[0].Key.UserKey)
   309  			checkKV(-1, ik, iv)
   310  			ik, iv = iter.SeekLT(sortedkv.MakeSortedKey(-1))
   311  			checkKV(-1, ik, iv)
   312  
   313  			require.NoError(t, iter.Close())
   314  		}
   315  
   316  		seekFunc(at)
   317  		require.NoError(t, at.close())
   318  
   319  		at1 := testOpenArrayTable(dir)
   320  		require.Equal(t, atVersion, at1.header.version)
   321  		seekFunc(at1)
   322  		require.NoError(t, at1.close())
   323  	})
   324  }
   325  
   326  func TestArrayTable_IterRange(t *testing.T) {
   327  	testcase(func(index int, params []bool) {
   328  		dir := testPath
   329  		defer os.RemoveAll(dir)
   330  		os.RemoveAll(dir)
   331  
   332  		at, atOpts := testNewArrayTable(dir, params)
   333  		atVersion := getAtVersionByOpts(atOpts)
   334  		count := 10000
   335  		kvList := testMakeSortedKV(count+1, uint64(1), 100)
   336  
   337  		for i := 0; i < count; i++ {
   338  			_, err := at.writeItem(kvList[i].Key.UserKey, kvList[i].Value)
   339  			require.NoError(t, err)
   340  		}
   341  		require.NoError(t, at.writeFinish())
   342  
   343  		rangeIter := func(a *arrayTable) {
   344  			iter := a.newIter(nil)
   345  			i := 0
   346  			for ik, iv := iter.First(); ik != nil; ik, iv = iter.Next() {
   347  				require.Equal(t, kvList[i].Key.UserKey, ik.UserKey)
   348  				require.Equal(t, kvList[i].Value, iv)
   349  				i++
   350  			}
   351  			require.Equal(t, i, count)
   352  			require.NoError(t, iter.Close())
   353  
   354  			iter = a.newIter(nil)
   355  			for i = 0; i < count; i++ {
   356  				ik, iv := iter.SeekGE(kvList[i].Key.UserKey)
   357  				require.Equal(t, kvList[i].Key.UserKey, ik.UserKey)
   358  				require.Equal(t, kvList[i].Value, iv)
   359  			}
   360  			require.NoError(t, iter.Close())
   361  		}
   362  
   363  		rangeReverseIter := func(a *arrayTable) {
   364  			iter := a.newIter(nil)
   365  			i := count - 1
   366  			for ik, iv := iter.Last(); ik != nil; ik, iv = iter.Prev() {
   367  				require.Equal(t, kvList[i].Key.UserKey, ik.UserKey)
   368  				require.Equal(t, kvList[i].Value, iv)
   369  				i--
   370  			}
   371  			require.Equal(t, -1, i)
   372  			require.NoError(t, iter.Close())
   373  
   374  			iter = a.newIter(nil)
   375  			for i = count; i >= 0; i-- {
   376  				ik, iv := iter.SeekLT(kvList[i].Key.UserKey)
   377  				if i == 0 {
   378  					require.Equal(t, nilInternalKey, ik)
   379  					require.Equal(t, []byte(nil), iv)
   380  				} else {
   381  					require.Equal(t, kvList[i-1].Key.UserKey, ik.UserKey)
   382  					require.Equal(t, kvList[i-1].Value, iv)
   383  				}
   384  			}
   385  			require.NoError(t, iter.Close())
   386  		}
   387  
   388  		rangeIter(at)
   389  		rangeReverseIter(at)
   390  		require.NoError(t, at.close())
   391  
   392  		at1 := testOpenArrayTable(dir)
   393  		require.Equal(t, atVersion, at1.header.version)
   394  		rangeIter(at1)
   395  		rangeReverseIter(at1)
   396  		require.NoError(t, at1.close())
   397  	})
   398  }
   399  
   400  func TestArrayTable_Empty(t *testing.T) {
   401  	testcase(func(index int, params []bool) {
   402  		dir := testPath
   403  		defer os.RemoveAll(dir)
   404  		os.RemoveAll(dir)
   405  
   406  		at, _ := testNewArrayTable(dir, params)
   407  		require.Equal(t, true, at.empty())
   408  
   409  		count := 1
   410  		kvList := testMakeSortedKV(count, uint64(1), 10)
   411  		for i := 0; i < count; i++ {
   412  			_, err := at.writeItem(kvList[i].Key.UserKey, kvList[i].Value)
   413  			require.NoError(t, err)
   414  		}
   415  		require.NoError(t, at.writeFinish())
   416  		require.Equal(t, false, at.empty())
   417  		require.NoError(t, at.close())
   418  	})
   419  }
   420  
   421  func Test_SharedPage_Perf(t *testing.T) {
   422  	os.Remove(testPath)
   423  
   424  	count := 1 << 20
   425  	kvList := testMakeSortedKV(count, uint64(1), 16)
   426  
   427  	bt := time.Now()
   428  	for _, useMapIndex := range []bool{false, true} {
   429  		fmt.Printf("Test_SharedPage_Perf, useMapIndex=%#v\n", useMapIndex)
   430  		atCacheOpts := atCacheOptions{
   431  			cache: testNewBlockCache(),
   432  			id:    1 << 10,
   433  		}
   434  		opts := &atOptions{
   435  			useMapIndex:       useMapIndex,
   436  			usePrefixCompress: false,
   437  		}
   438  		at, err := newArrayTable(testPath, opts, &atCacheOpts)
   439  		require.NoError(t, err)
   440  
   441  		bt1 := time.Now()
   442  		for i := 0; i < count; i++ {
   443  			key := kvList[i].Key.UserKey
   444  			if _, err = at.writeItem(key, kvList[i].Value); err != nil {
   445  				t.Fatalf("add err key:%s err:%v", string(key), err)
   446  			}
   447  		}
   448  		require.NoError(t, at.writeFinish())
   449  		require.Equal(t, uint32(count), at.header.num)
   450  		et1 := time.Since(bt1)
   451  		fmt.Printf("Test_SharedPage_Perf writeArrayTable time cost = %v\n", et1)
   452  
   453  		fmt.Printf("useMapIndex=%#v; at.size=%dKB; at.tbl.fileStatSize=%dKB\n", useMapIndex, at.size/1024, at.tbl.fileStatSize()/1024)
   454  
   455  		seekFunc := func(a *arrayTable) {
   456  			iter := a.newIter(nil)
   457  			i := 0
   458  			for key, val := iter.First(); key != nil; key, val = iter.Next() {
   459  				expKey := kvList[i].Key.UserKey
   460  				require.Equal(t, expKey, key.UserKey)
   461  				require.Equal(t, kvList[i].Value, val)
   462  				i++
   463  			}
   464  
   465  			require.NoError(t, iter.Close())
   466  
   467  			getFunc := func(skey []byte) {
   468  				_, exist, _, closer := a.get(skey, hash.Crc32(skey))
   469  				require.Equal(t, true, exist)
   470  				if closer != nil {
   471  					closer()
   472  				}
   473  			}
   474  
   475  			seekFunc := func(skey []byte) {
   476  				it1 := a.newIter(nil)
   477  				ik, _ := it1.SeekGE(skey)
   478  				if ik == nil {
   479  					t.Fatal("SeekGE fail", string(skey))
   480  				}
   481  				require.Equal(t, skey, ik.UserKey)
   482  				require.NoError(t, it1.Close())
   483  			}
   484  
   485  			seekNotExist := func(skey []byte) {
   486  				_, exist, _, closer := a.get(skey, hash.Crc32(skey))
   487  				require.Equal(t, false, exist)
   488  				if closer != nil {
   489  					closer()
   490  				}
   491  			}
   492  
   493  			bt1_1 := time.Now()
   494  			for j := 0; j < count; j++ {
   495  				getFunc(kvList[j].Key.UserKey)
   496  			}
   497  			et1_1 := time.Since(bt1_1)
   498  			fmt.Printf("Test_SharedPage_Perf GET time cost = %v\n", et1_1)
   499  
   500  			bt1_2 := time.Now()
   501  			for j := 0; j < count; j++ {
   502  				seekFunc(kvList[j].Key.UserKey)
   503  			}
   504  			et1_2 := time.Since(bt1_2)
   505  			fmt.Printf("Test_SharedPage_Perf SeekGE time cost = %v\n", et1_2)
   506  
   507  			for _, n := range []int{count + 7, count + 71, count + 711} {
   508  				seekNotExist(sortedkv.MakeSortedKey(n))
   509  			}
   510  		}
   511  
   512  		bt2 := time.Now()
   513  		seekFunc(at)
   514  		et2 := time.Since(bt2)
   515  		fmt.Printf("Test_SharedPage_Perf seekArrayTable time cost = %v\n", et2)
   516  
   517  		require.NoError(t, at.close())
   518  
   519  		at1, err1 := openArrayTable(testPath, &atCacheOpts)
   520  		require.NoError(t, err1)
   521  
   522  		bt3 := time.Now()
   523  		seekFunc(at1)
   524  		et3 := time.Since(bt3)
   525  		fmt.Printf("Test_SharedPage_Perf reopen&seekArrayTable time cost = %v\n", et3)
   526  
   527  		require.NoError(t, at1.close())
   528  
   529  		os.Remove(testPath)
   530  	}
   531  	et := time.Since(bt)
   532  	fmt.Printf("Test_SharedPage_Perf time cost = %v\n", et)
   533  }
   534  
   535  const item_count = 1<<20 - 1
   536  
   537  func Test_PageBlock_Perf(t *testing.T) {
   538  	defer os.Remove(testPath)
   539  	os.Remove(testPath)
   540  
   541  	count := item_count
   542  	seqNum := uint64(1)
   543  	kvList := testMakeSortedKVForBitrie(count, seqNum, 10)
   544  	seqNum += uint64(count)
   545  
   546  	bt := time.Now()
   547  	for _, opts := range [][]bool{
   548  		{false, false, false},
   549  		//{false, true, false},
   550  		{true, false, false},
   551  		//{true, true, false},
   552  	} {
   553  		bt0 := time.Now()
   554  		fmt.Printf("Start Test_PageBlock_Perf, opts(usePrefixCompress, useBlockCompress)=%#v\n", opts)
   555  
   556  		atCacheOpts := &atCacheOptions{
   557  			cache: testNewBlockCache(),
   558  			id:    1 << 10,
   559  		}
   560  		option := &atOptions{
   561  			useMapIndex:       false,
   562  			usePrefixCompress: opts[0],
   563  			useBlockCompress:  opts[1],
   564  			blockSize:         32 << 10,
   565  		}
   566  		at, err := newArrayTable(testPath, option, atCacheOpts)
   567  		require.NoError(t, err)
   568  
   569  		bt1 := time.Now()
   570  		for i := 0; i < count; i++ {
   571  			_, err = at.writeItem(kvList[i].Key.UserKey, kvList[i].Value)
   572  			require.NoError(t, err)
   573  		}
   574  		require.NoError(t, at.writeFinish())
   575  		et1 := time.Since(bt1)
   576  		fmt.Printf("Test_PageBlock_Perf writeArrayTable time cost = %v; header=%v\n", et1, at.header.version)
   577  
   578  		fmt.Printf("opts(usePrefixCompress, useBlockCompress)=%#v; at.size=%dKB; tbl.size=%dKB, at.tbl.fileStatSize=%dKB; totalNum=%d\n", opts, at.size/1024, at.tbl.Size()/1024, at.tbl.fileStatSize()/1024, at.num)
   579  
   580  		seekFunc := func(a *arrayTable) {
   581  			bt10_0 := time.Now()
   582  			iter := a.newIter(nil)
   583  			i := 0
   584  			for key, val := iter.First(); key != nil; key, val = iter.Next() {
   585  				require.Equal(t, kvList[i].Key.UserKey, key.UserKey)
   586  				require.Equal(t, kvList[i].Value, val)
   587  				i++
   588  			}
   589  			require.Equal(t, count, i)
   590  			require.NoError(t, iter.Close())
   591  			et10_0 := time.Since(bt10_0)
   592  			fmt.Printf("Test_PageBlock_Perf FlushIter_Next_Ranges time cost = %v\n", et10_0)
   593  
   594  			getFunc := func(i int) {
   595  				skey := kvList[i].Key.UserKey
   596  				val, exist, _, closer := a.get(skey, hash.Crc32(skey))
   597  				require.Equal(t, true, exist)
   598  				require.Equal(t, kvList[i].Value, val)
   599  				if closer != nil {
   600  					closer()
   601  				}
   602  			}
   603  
   604  			seekFunc := func(i int) {
   605  				it1 := a.newIter(nil)
   606  				skey := kvList[i].Key.UserKey
   607  				ik, v := it1.SeekGE(skey)
   608  				require.Equal(t, skey, ik.UserKey)
   609  				require.Equal(t, kvList[i].Value, v)
   610  				require.NoError(t, it1.Close())
   611  			}
   612  
   613  			seekltFunc := func(seek, exp int) {
   614  				it1 := a.newIter(nil)
   615  				skey := kvList[i].Key.UserKey
   616  				ik, v := it1.SeekLT(skey)
   617  				if exp != -1 {
   618  					require.Equal(t, kvList[exp].Key.UserKey, ik.UserKey)
   619  					require.Equal(t, kvList[exp].Value, v)
   620  				}
   621  				require.NoError(t, it1.Close())
   622  			}
   623  
   624  			seekNotExist := func(skey []byte) {
   625  				_, exist, _, closer := a.get(skey, hash.Crc32(skey))
   626  				require.Equal(t, false, exist)
   627  				if closer != nil {
   628  					closer()
   629  				}
   630  			}
   631  
   632  			bt1_0 := time.Now()
   633  			iter = a.newIter(nil)
   634  			i = 0
   635  			for key, val := iter.First(); key != nil; key, val = iter.Next() {
   636  				require.Equal(t, kvList[i].Key.UserKey, key.UserKey)
   637  				require.Equal(t, kvList[i].Value, val)
   638  				i++
   639  			}
   640  			require.Equal(t, count, i)
   641  			require.NoError(t, iter.Close())
   642  			et1_0 := time.Since(bt1_0)
   643  			fmt.Printf("Test_PageBlock_Perf Next_Ranges time cost = %v\n", et1_0)
   644  
   645  			bt1_00 := time.Now()
   646  			iter = a.newIter(nil)
   647  			i = count - 1
   648  			for key, val := iter.Last(); key != nil; key, val = iter.Prev() {
   649  				require.Equal(t, kvList[i].Key.UserKey, key.UserKey)
   650  				require.Equal(t, kvList[i].Value, val)
   651  				i--
   652  			}
   653  			require.Equal(t, -1, i)
   654  			require.NoError(t, iter.Close())
   655  			et1_00 := time.Since(bt1_00)
   656  			fmt.Printf("Test_PageBlock_Perf Prev_Ranges time cost = %v\n", et1_00)
   657  
   658  			bt1_1 := time.Now()
   659  			for i = 0; i < count; i++ {
   660  				getFunc(i)
   661  			}
   662  			et1_1 := time.Since(bt1_1)
   663  			fmt.Printf("Test_PageBlock_Perf GET time cost = %v\n", et1_1)
   664  
   665  			bt1_2 := time.Now()
   666  			for i = 0; i < count; i++ {
   667  				if i == 0 {
   668  					seekltFunc(0, -1)
   669  				} else {
   670  					seekltFunc(i, i-1)
   671  				}
   672  			}
   673  			et1_2 := time.Since(bt1_2)
   674  			fmt.Printf("Test_PageBlock_Perf SeekLT time cost = %v\n", et1_2)
   675  
   676  			for _, j := range []int{100007 * 100, 100071 * 100, 100711 * 100} {
   677  				seekNotExist(sortedkv.MakeSortedKey(j))
   678  			}
   679  
   680  			bt1_3 := time.Now()
   681  			for i = 0; i < count; i++ {
   682  				seekFunc(i)
   683  			}
   684  			et1_3 := time.Since(bt1_3)
   685  			fmt.Printf("Test_PageBlock_Perf SeekGE time cost = %v\n", et1_3)
   686  		}
   687  
   688  		bt2 := time.Now()
   689  		seekFunc(at)
   690  		et2 := time.Since(bt2)
   691  		fmt.Printf("Test_PageBlock_Perf seekArrayTable time cost = %v\n", et2)
   692  
   693  		require.NoError(t, at.close())
   694  
   695  		et0 := time.Since(bt0)
   696  		fmt.Printf("Finish Test_PageBlock_Perf, opts(usePrefixCompress, useBlockCompress)=%#v, time cost = %v\n======================\n", opts, et0)
   697  
   698  		os.Remove(testPath)
   699  	}
   700  	et := time.Since(bt)
   701  	fmt.Printf("Test_PageBlock_Perf Total End, time cost = %v\n", et)
   702  }
   703  
   704  func Test_Bitrie_Perf(t *testing.T) {
   705  	defer os.Remove(testPath)
   706  	os.Remove(testPath)
   707  
   708  	count := item_count
   709  	seqNum := uint64(1)
   710  	kvList := testMakeSortedKVForBitrie(count, seqNum, 10)
   711  	seqNum += uint64(count)
   712  
   713  	if count <= 50 {
   714  		for i := 0; i < count; i++ {
   715  			fmt.Printf("%s\n", kvList[i].Key.UserKey)
   716  		}
   717  	}
   718  
   719  	bt := time.Now()
   720  	for _, opts := range [][]bool{
   721  		{false, false, true},
   722  	} {
   723  		bt0 := time.Now()
   724  		fmt.Printf("Start Test_Bitrie_Perf, opts(usePrefixCompress, useBlockCompress)=%#v\n", opts)
   725  
   726  		atCacheOpts := &atCacheOptions{
   727  			cache: testNewBlockCache(),
   728  			id:    1 << 10,
   729  		}
   730  		option := &atOptions{
   731  			useMapIndex:       false,
   732  			usePrefixCompress: opts[0],
   733  			useBlockCompress:  opts[1],
   734  			useBitrieCompress: opts[2],
   735  			blockSize:         32 << 10,
   736  		}
   737  		at, err := newArrayTable(testPath, option, atCacheOpts)
   738  		require.NoError(t, err)
   739  
   740  		bt1 := time.Now()
   741  		for i := 0; i < count; i++ {
   742  			_, err = at.writeItem(kvList[i].Key.UserKey, kvList[i].Value)
   743  			require.NoError(t, err)
   744  		}
   745  
   746  		require.NoError(t, at.writeFinish())
   747  		et1 := time.Since(bt1)
   748  		fmt.Printf("Test_Bitrie_Perf writeArrayTable time cost = %v; header=%v\n", et1, at.header.version)
   749  
   750  		if count <= 50 {
   751  			fmt.Printf("Test_Bitrie_Perf BitrieToString:\n%s\n", at.bitrieIndex.AnalyzeBytes())
   752  		}
   753  
   754  		fmt.Printf("opts(usePrefixCompress, useBlockCompress, useBitrieCompress)=%#v; at.size=%dKB; tbl.size=%dKB, at.tbl.fileStatSize=%dKB; totalNum=%d\n", opts, at.size/1024, at.tbl.Size()/1024, at.tbl.fileStatSize()/1024, at.num)
   755  
   756  		seekFunc := func(a *arrayTable) {
   757  			i := 0
   758  			/*bt10_0 := time.Now()
   759  			iter := a.newIter(nil)
   760  			for key, val := iter.First(); key != nil; key, val = iter.Next() {
   761  				require.Equal(t, kvList[i].Key.UserKey, key.UserKey)
   762  				require.Equal(t, kvList[i].Value, val)
   763  				i++
   764  			}
   765  			require.Equal(t, count, i)
   766  			require.NoError(t, iter.Close())
   767  			et10_0 := time.Since(bt10_0)
   768  			fmt.Printf("Test_PageBlock_Perf FlushIter_Next_Ranges time cost = %v\n", et10_0)
   769  			*/
   770  
   771  			getFunc := func(i int) {
   772  				skey := kvList[i].Key.UserKey
   773  				val, exist, _, closer := a.get(skey, 0 /*hash.Crc32(skey)*/)
   774  				require.Equal(t, true, exist)
   775  				require.Equal(t, kvList[i].Value, val)
   776  				if closer != nil {
   777  					closer()
   778  				}
   779  			}
   780  
   781  			/*seekFunc := func(i int) {
   782  				it1 := a.newIter(nil)
   783  				skey := kvList[i].Key.UserKey
   784  				ik, v := it1.SeekGE(skey)
   785  				require.Equal(t, skey, ik.UserKey)
   786  				require.Equal(t, kvList[i].Value, v)
   787  				require.NoError(t, it1.Close())
   788  			}
   789  
   790  			seekltFunc := func(seek, exp int) {
   791  				it1 := a.newIter(nil)
   792  				skey := kvList[i].Key.UserKey
   793  				ik, v := it1.SeekLT(skey)
   794  				if exp != -1 {
   795  					require.Equal(t, kvList[exp].Key.UserKey, ik.UserKey)
   796  					require.Equal(t, kvList[exp].Value, v)
   797  				}
   798  				require.NoError(t, it1.Close())
   799  			}
   800  
   801  			seekNotExist := func(skey []byte) {
   802  				_, exist, _, closer := a.get(skey, hash.Crc32(skey))
   803  				require.Equal(t, false, exist)
   804  				if closer != nil {
   805  					closer()
   806  				}
   807  			}
   808  
   809  			bt1_0 := time.Now()
   810  			iter = a.newIter(nil)
   811  			i = 0
   812  			for key, val := iter.First(); key != nil; key, val = iter.Next() {
   813  				require.Equal(t, kvList[i].Key.UserKey, key.UserKey)
   814  				require.Equal(t, kvList[i].Value, val)
   815  				i++
   816  			}
   817  			require.Equal(t, count, i)
   818  			require.NoError(t, iter.Close())
   819  			et1_0 := time.Since(bt1_0)
   820  			fmt.Printf("Test_Bitrie_Perf Next_Ranges time cost = %v\n", et1_0)
   821  
   822  			bt1_00 := time.Now()
   823  			iter = a.newIter(nil)
   824  			i = count - 1
   825  			for key, val := iter.Last(); key != nil; key, val = iter.Prev() {
   826  				require.Equal(t, kvList[i].Key.UserKey, key.UserKey)
   827  				require.Equal(t, kvList[i].Value, val)
   828  				i--
   829  			}
   830  			require.Equal(t, -1, i)
   831  			require.NoError(t, iter.Close())
   832  			et1_00 := time.Since(bt1_00)
   833  			fmt.Printf("Test_Bitrie_Perf Prev_Ranges time cost = %v\n", et1_00)
   834  			*/
   835  
   836  			bt1_1 := time.Now()
   837  			for i = 0; i < count; i++ {
   838  				getFunc(i)
   839  			}
   840  			et1_1 := time.Since(bt1_1)
   841  			fmt.Printf("Test_Bitrie_Perf GET time cost = %v\n", et1_1)
   842  
   843  			/*bt1_2 := time.Now()
   844  			for i = 0; i < count; i++ {
   845  				if i == 0 {
   846  					seekltFunc(0, -1)
   847  				} else {
   848  					seekltFunc(i, i-1)
   849  				}
   850  			}
   851  			et1_2 := time.Since(bt1_2)
   852  			fmt.Printf("Test_Bitrie_Perf SeekLT time cost = %v\n", et1_2)
   853  
   854  			for _, j := range []int{100007, 100071, 100711} {
   855  				seekNotExist(utils.MakeSortedKey(j))
   856  			}
   857  
   858  			bt1_3 := time.Now()
   859  			for i = 0; i < count; i++ {
   860  				seekFunc(i)
   861  			}
   862  			et1_3 := time.Since(bt1_3)
   863  			fmt.Printf("Test_Bitrie_Perf SeekGE time cost = %v\n", et1_3)*/
   864  		}
   865  
   866  		bt2 := time.Now()
   867  		seekFunc(at)
   868  		et2 := time.Since(bt2)
   869  		fmt.Printf("Test_Bitrie_Perf seekArrayTable time cost = %v\n", et2)
   870  
   871  		require.NoError(t, at.close())
   872  
   873  		et0 := time.Since(bt0)
   874  		fmt.Printf("Finish Test_Bitrie_Perf, opts(usePrefixCompress, useBlockCompress)=%#v, time cost = %v\n======================\n", opts, et0)
   875  
   876  		os.Remove(testPath)
   877  	}
   878  	et := time.Since(bt)
   879  	fmt.Printf("Test_Bitrie_Perf Total End, time cost = %v\n", et)
   880  }
   881  
   882  func Test_AtEqual(t *testing.T) {
   883  	key1 := []byte("asdfghjklpoiuytrewq")
   884  	key2 := []byte("asdfghjklpoiuytrewq")
   885  	sk1 := []byte("asdfghjkl")
   886  	sk2 := []byte("poiuytrewq")
   887  
   888  	totalNum := 2 << 20
   889  	startNum := 0
   890  
   891  	fmt.Println(bytes.Equal(key1, key2), atEqual(sk1, sk2, key1))
   892  
   893  	bt := time.Now()
   894  	for i := startNum; i <= totalNum; i++ {
   895  		if !bytes.Equal(key1, key2) {
   896  			fmt.Printf("bytes.Equal error")
   897  		}
   898  	}
   899  	et := time.Since(bt)
   900  	fmt.Printf("bytes.Equal time cost = %v\n", et)
   901  
   902  	bt = time.Now()
   903  	for i := startNum; i <= totalNum; i++ {
   904  		if !atEqual(sk1, sk2, key2) {
   905  			fmt.Printf("atEqual error")
   906  		}
   907  	}
   908  	et = time.Since(bt)
   909  	fmt.Printf("atEqual time cost = %v\n", et)
   910  
   911  	bt = time.Now()
   912  	for i := startNum; i <= totalNum; i++ {
   913  		tmpk := make([]byte, 0, len(key1))
   914  		tmpk = append(tmpk, sk1...)
   915  		tmpk = append(tmpk, sk2...)
   916  		if !bytes.Equal(tmpk, key2) {
   917  			fmt.Printf("atEqual error")
   918  		}
   919  	}
   920  	et = time.Since(bt)
   921  	fmt.Printf("make&bytes.Equal time cost = %v\n", et)
   922  }
   923  
   924  func Test_AtCompare(t *testing.T) {
   925  	key1 := []byte("asdfghjklpoiuytrewq")
   926  	key2 := []byte("asdfghjklpoiuytrewq")
   927  	sk1 := []byte("asdfghjkl")
   928  	sk2 := []byte("poiuytrewq")
   929  
   930  	totalNum := 1 << 20
   931  	startNum := 0
   932  
   933  	bt := time.Now()
   934  	for i := startNum; i <= totalNum; i++ {
   935  		if bytes.Compare(key1, key2) != 0 {
   936  			fmt.Printf("bytes.Compare error")
   937  		}
   938  	}
   939  	et := time.Since(bt)
   940  	fmt.Printf("bytes.Compare time cost = %v\n", et)
   941  
   942  	bt = time.Now()
   943  	for i := startNum; i <= totalNum; i++ {
   944  		if atCompare(sk1, sk2, key2) != 0 {
   945  			fmt.Printf("atCompare error")
   946  		}
   947  	}
   948  	et = time.Since(bt)
   949  	fmt.Printf("atCompare time cost = %v\n", et)
   950  
   951  	bt = time.Now()
   952  	for i := startNum; i <= totalNum; i++ {
   953  		tmpk := make([]byte, 0, len(key1))
   954  		tmpk = append(tmpk, sk1...)
   955  		tmpk = append(tmpk, sk2...)
   956  		if bytes.Compare(tmpk, key2) != 0 {
   957  			fmt.Printf("bytes.Compare error")
   958  		}
   959  	}
   960  	et = time.Since(bt)
   961  	fmt.Printf("make&bytes.Compare time cost = %v\n", et)
   962  }
   963  
   964  func Test_AtCompare_Case(t *testing.T) {
   965  	type compareCase struct {
   966  		key []byte
   967  		sk1 []byte
   968  		sk2 []byte
   969  		ret int
   970  	}
   971  
   972  	caseList := make([]compareCase, 0, 2<<4)
   973  
   974  	caseList = append(caseList, compareCase{key: []byte("asdfghjklpoiuytrewq"), sk1: []byte("asdfghjkl"), sk2: []byte("poiuytrewq"), ret: 0})
   975  	caseList = append(caseList, compareCase{key: []byte("asdfghjkl"), sk1: []byte("asdfghjkl"), sk2: []byte(""), ret: 0})
   976  	caseList = append(caseList, compareCase{key: []byte("asdfghjkl"), sk1: []byte(""), sk2: []byte("asdfghjkl"), ret: 0})
   977  	caseList = append(caseList, compareCase{key: []byte("qwer"), sk1: []byte("asdfghjklpoiuytrewq"), sk2: []byte("a"), ret: -1})
   978  	caseList = append(caseList, compareCase{key: []byte("fdafa"), sk1: []byte("qsdfghjklpoiuytrewq"), sk2: []byte("a"), ret: 1})
   979  	caseList = append(caseList, compareCase{key: []byte("qsdfghjklpoiuytrewqqqqqq"), sk1: []byte("qsdfghjklpoiuytrewq"), sk2: []byte("a"), ret: -1})
   980  	caseList = append(caseList, compareCase{key: []byte("qsdfghjklpoiuytrewqqqqqq"), sk1: []byte("qsdfghjklpoiuytrewq"), sk2: []byte("zzzz"), ret: 1})
   981  	caseList = append(caseList, compareCase{key: []byte("abcd"), sk1: []byte("a"), sk2: []byte("zzz"), ret: 1})
   982  	caseList = append(caseList, compareCase{key: []byte("abcd"), sk1: []byte("a"), sk2: []byte("azzz"), ret: -1})
   983  
   984  	for i := 0; i < len(caseList); i++ {
   985  		r := atCompare(caseList[i].sk1, caseList[i].sk2, caseList[i].key)
   986  		require.Equal(t, r, caseList[i].ret)
   987  	}
   988  }