github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bithash/bithash_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 bithash
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/binary"
    20  	"errors"
    21  	"fmt"
    22  	"io/fs"
    23  	"math/rand"
    24  	"os"
    25  	"runtime"
    26  	"strconv"
    27  	"sync"
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/stretchr/testify/require"
    32  	"github.com/zuoyebang/bitalosdb/internal/base"
    33  	"github.com/zuoyebang/bitalosdb/internal/compress"
    34  	"github.com/zuoyebang/bitalosdb/internal/hash"
    35  	"github.com/zuoyebang/bitalosdb/internal/list2"
    36  	"github.com/zuoyebang/bitalosdb/internal/options"
    37  )
    38  
    39  const testdataDir = "test"
    40  
    41  type testKvItem struct {
    42  	k  []byte
    43  	v  []byte
    44  	fn FileNum
    45  }
    46  
    47  func testGetBithashOpts(sz int) *options.BithashOptions {
    48  	opts := &options.BithashOptions{
    49  		Options: &options.Options{
    50  			FS:              testFs,
    51  			Logger:          base.DefaultLogger,
    52  			Compressor:      compress.NoCompressor,
    53  			DeleteFilePacer: options.NewDefaultDeletionFileLimiter(),
    54  			BytesPerSync:    512 << 10,
    55  		},
    56  		TableMaxSize: sz,
    57  		Index:        1,
    58  	}
    59  	return opts
    60  }
    61  
    62  func testBuildKV(num int) []testKvItem {
    63  	var kvList []testKvItem
    64  	for i := 0; i < num; i++ {
    65  		kvList = append(kvList, testKvItem{
    66  			k: []byte("vip:uinfo:scancode:" + strconv.Itoa(i)),
    67  			v: testGenValue(2048)})
    68  	}
    69  
    70  	return kvList
    71  }
    72  
    73  func testGenValue(size int) []byte {
    74  	buf := make([]byte, size)
    75  	for i := 0; i < size; i++ {
    76  		rand.Intn(122 - 65)
    77  		buf[i] = byte(rand.Intn(122-65) + 65)
    78  	}
    79  	return buf
    80  }
    81  
    82  func testOpenBithash() *Bithash {
    83  	opts := testGetBithashOpts(1 << 20)
    84  	_, err := os.Stat(testdataDir)
    85  	if nil != err && !os.IsExist(err) {
    86  		err = os.MkdirAll(testdataDir, 0775)
    87  		if nil != err {
    88  			panic(err)
    89  		}
    90  	}
    91  	bithash, err := Open(testdataDir, opts)
    92  	if err != nil {
    93  		panic(err)
    94  	}
    95  
    96  	return bithash
    97  }
    98  
    99  func testOpenBithash_64MB() *Bithash {
   100  	opts := testGetBithashOpts(64 << 20)
   101  	_, err := os.Stat(testdataDir)
   102  	if nil != err && !os.IsExist(err) {
   103  		err = os.MkdirAll(testdataDir, 0775)
   104  		if nil != err {
   105  			panic(err)
   106  		}
   107  	}
   108  	bithash, err := Open(testdataDir, opts)
   109  	if err != nil {
   110  		panic(err)
   111  	}
   112  
   113  	return bithash
   114  }
   115  
   116  func getSlotIndexBuf(key []byte) []byte {
   117  	index := hash.Fnv32(key) % 1024
   118  	buf := make([]byte, 4)
   119  	binary.BigEndian.PutUint32(buf, index)
   120  	return buf
   121  }
   122  
   123  func testBithashClose(t *testing.T, b *Bithash) {
   124  	require.NoError(t, b.Close())
   125  	b.deleteFilePacer.Close()
   126  }
   127  
   128  func TestBithashOpen(t *testing.T) {
   129  	defer os.RemoveAll(testdataDir)
   130  	os.RemoveAll(testdataDir)
   131  	b := testOpenBithash()
   132  	require.Equal(t, 0, len(b.mufn.fnMap))
   133  	key := []byte("key")
   134  	ek := make([]byte, len(key)+4)
   135  	pos := copy(ek, getSlotIndexBuf(key))
   136  	copy(ek[pos:], key)
   137  	khash := hash.Crc32(ek)
   138  	_, _, err := b.Get(ek, khash, 5)
   139  	require.Equal(t, ErrBhFileNumZero, err)
   140  	testBithashClose(t, b)
   141  }
   142  
   143  func testGetGID() uint64 {
   144  	b := make([]byte, 64)
   145  	b = b[:runtime.Stack(b, false)]
   146  	b = bytes.TrimPrefix(b, []byte("goroutine "))
   147  	b = b[:bytes.IndexByte(b, ' ')]
   148  	n, _ := strconv.ParseUint(string(b), 10, 64)
   149  	return n
   150  }
   151  
   152  func testBithashWriterFlush(b *Bithash) {
   153  	kvList := testBuildKV(10000)
   154  	fmt.Println("testBithashWriterFlush", testGetGID())
   155  	bhWriter, err := b.FlushStart()
   156  	if err != nil {
   157  		panic(err)
   158  	}
   159  	for i, item := range kvList {
   160  		ik := base.MakeInternalKey(item.k, 0, InternalKeyKindSet)
   161  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   162  		if err != nil {
   163  			panic(err)
   164  		}
   165  	}
   166  	err = b.FlushFinish(bhWriter)
   167  	if err != nil {
   168  		panic(err)
   169  	}
   170  }
   171  
   172  func testBithashWriterFlushAndGet(b *Bithash) {
   173  	gid := testGetGID()
   174  	var kvList []testKvItem
   175  	for i := 0; i < 1000; i++ {
   176  		kvList = append(kvList, testKvItem{
   177  			k: []byte(fmt.Sprintf("vip:uinfo:scancode:%d:%d", gid, i)),
   178  			v: testGenValue(2048)},
   179  		)
   180  	}
   181  
   182  	bhWriter, err := b.FlushStart()
   183  	if err != nil {
   184  		panic(err)
   185  	}
   186  	fmt.Println("testBithashWriterFlush write start", gid, bhWriter.GetFileNum())
   187  	for i, item := range kvList {
   188  		ik := base.MakeInternalKey(item.k, 0, InternalKeyKindSet)
   189  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   190  		if err != nil {
   191  			panic(err)
   192  		}
   193  	}
   194  	err = b.FlushFinish(bhWriter)
   195  	if err != nil {
   196  		panic(err)
   197  	}
   198  
   199  	fmt.Println("testBithashWriterFlush write done", gid)
   200  
   201  	for _, item := range kvList {
   202  		khash := hash.Crc32(item.k)
   203  		value, putBytePool, err := b.Get(item.k, khash, item.fn)
   204  		if err != nil {
   205  			fmt.Println("get fail", gid, string(item.k), item.fn)
   206  		}
   207  		if !bytes.Equal(value, item.v) {
   208  			panic(fmt.Sprintf("check kv fail k=%s fm=%d", string(item.k), uint64(item.fn)))
   209  		}
   210  		putBytePool()
   211  	}
   212  
   213  	fmt.Println("testBithashWriterFlush finish", gid)
   214  }
   215  
   216  func TestBithashCompactAndGet(t *testing.T) {
   217  	defer os.RemoveAll(testdataDir)
   218  	os.RemoveAll(testdataDir)
   219  	seqNum := uint64(1)
   220  	b := testOpenBithash()
   221  
   222  	num := 2000
   223  	kvList := testBuildKV(num)
   224  	bhWriter, err := b.FlushStart()
   225  	require.NoError(t, err)
   226  	for i, item := range kvList {
   227  		ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   228  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   229  		if err != nil {
   230  			panic(err)
   231  		}
   232  		seqNum++
   233  		if i > 1000 {
   234  			break
   235  		}
   236  	}
   237  	require.NoError(t, b.FlushFinish(bhWriter))
   238  	bhWriter, err = b.FlushStart()
   239  	require.NoError(t, err)
   240  	for i, item := range kvList {
   241  		ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   242  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   243  		if err != nil {
   244  			panic(err)
   245  		}
   246  		seqNum++
   247  	}
   248  	require.NoError(t, b.FlushFinish(bhWriter))
   249  	testBithashClose(t, b)
   250  
   251  	b = testOpenBithash()
   252  	bw, err1 := b.NewBithashWriter(true)
   253  	require.NoError(t, err1)
   254  
   255  	newFileNum := bw.GetFileNum()
   256  	fileNums := make([]FileNum, 4)
   257  	fileNums[0] = FileNum(1)
   258  	fileNums[1] = FileNum(2)
   259  	fileNums[2] = FileNum(3)
   260  	fileNums[3] = FileNum(4)
   261  
   262  	compactFile := func(fileNum FileNum) error {
   263  		iter, err := b.NewTableIter(fileNum)
   264  		if err != nil {
   265  			return err
   266  		}
   267  		defer func() {
   268  			require.NoError(t, iter.Close())
   269  		}()
   270  		i := 0
   271  		for k, v, fn := iter.First(); iter.Valid(); k, v, fn = iter.Next() {
   272  			if err = bw.AddIkey(k, v, hash.Crc32(k.UserKey), fn); err != nil {
   273  				return err
   274  			}
   275  			i++
   276  		}
   277  		return nil
   278  	}
   279  
   280  	for _, fn := range fileNums {
   281  		err = compactFile(fn)
   282  		require.NoError(t, err)
   283  		b.SetFileNumMap(newFileNum, fn)
   284  		b.RemoveTableFiles([]FileNum{fn})
   285  	}
   286  
   287  	require.NoError(t, bw.Finish())
   288  
   289  	for _, item := range kvList {
   290  		khash := hash.Crc32(item.k)
   291  		value, putBytePool, err := b.Get(item.k, khash, item.fn)
   292  		require.NoError(t, err)
   293  		if !bytes.Equal(item.v, value) {
   294  			t.Fatalf("get fail key:%s exp:%d act:%d", string(item.k), len(item.v), len(value))
   295  		}
   296  		putBytePool()
   297  	}
   298  
   299  	testBithashClose(t, b)
   300  
   301  	b = testOpenBithash()
   302  	iter, err := b.NewTableIter(newFileNum)
   303  	if err != nil {
   304  		t.Fatal(err)
   305  	}
   306  	for k, _, fn := iter.First(); iter.Valid(); k, _, fn = iter.Next() {
   307  		khash := hash.Crc32(k.UserKey)
   308  		v, pool, err := b.Get(k.UserKey, khash, fn)
   309  		require.NoError(t, err)
   310  		require.Equal(t, 2048, len(v))
   311  		if pool != nil {
   312  			pool()
   313  		}
   314  	}
   315  	require.NoError(t, iter.Close())
   316  	testBithashClose(t, b)
   317  }
   318  
   319  func TestBithashCompactInterrupt(t *testing.T) {
   320  	defer os.RemoveAll(testdataDir)
   321  	os.RemoveAll(testdataDir)
   322  	seqNum := uint64(1)
   323  	b := testOpenBithash()
   324  
   325  	num := 1200
   326  	kvList := testBuildKV(num)
   327  	bhWriter, err := b.FlushStart()
   328  	require.NoError(t, err)
   329  	for i, item := range kvList {
   330  		ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   331  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   332  		if err != nil {
   333  			panic(err)
   334  		}
   335  		seqNum++
   336  	}
   337  	require.NoError(t, b.FlushFinish(bhWriter))
   338  	testBithashClose(t, b)
   339  
   340  	b = testOpenBithash()
   341  	bw, err := b.NewBithashWriter(true)
   342  	require.NoError(t, err)
   343  	newFileNum := bw.GetFileNum()
   344  	fmt.Println("newFileNum", newFileNum)
   345  	fileNums := make([]FileNum, 2)
   346  	fileNums[0] = FileNum(1)
   347  	fileNums[1] = FileNum(2)
   348  	compactFile := func(fileNum FileNum) error {
   349  		iter, e := b.NewTableIter(fileNum)
   350  		if e != nil {
   351  			return e
   352  		}
   353  		defer func() {
   354  			require.NoError(t, iter.Close())
   355  		}()
   356  		i := 0
   357  		for k, v, fn := iter.First(); iter.Valid(); k, v, fn = iter.Next() {
   358  			if e = bw.AddIkey(k, v, hash.Crc32(k.UserKey), fn); e != nil {
   359  				return e
   360  			}
   361  			i++
   362  			if i == 100 {
   363  				return nil
   364  			}
   365  		}
   366  		return nil
   367  	}
   368  
   369  	for _, fn := range fileNums {
   370  		err = compactFile(fn)
   371  		if err != nil {
   372  			t.Fatalf("compactFile fail fn:%d err:%s", fn, err)
   373  		}
   374  	}
   375  
   376  	b = testOpenBithash()
   377  	filename := MakeFilepath(b.fs, b.dirname, fileTypeTable, newFileNum)
   378  	_, err = b.fs.Stat(filename)
   379  	require.Equal(t, true, errors.Is(err, fs.ErrNotExist))
   380  	_, ok := b.meta.mu.filesMeta[newFileNum]
   381  	require.Equal(t, false, ok)
   382  	testBithashClose(t, b)
   383  }
   384  
   385  func TestBithashWriterFlush(t *testing.T) {
   386  	defer os.RemoveAll(testdataDir)
   387  	os.RemoveAll(testdataDir)
   388  	b := testOpenBithash()
   389  	testBithashWriterFlush(b)
   390  	testBithashClose(t, b)
   391  }
   392  
   393  func TestBithashWriterConcurrencyFlush(t *testing.T) {
   394  	defer os.RemoveAll(testdataDir)
   395  	os.RemoveAll(testdataDir)
   396  	var wg sync.WaitGroup
   397  	b := testOpenBithash()
   398  	for i := 0; i < 1; i++ {
   399  		wg.Add(1)
   400  		go func() {
   401  			defer wg.Done()
   402  			testBithashWriterFlushAndGet(b)
   403  		}()
   404  	}
   405  	wg.Wait()
   406  	testBithashClose(t, b)
   407  }
   408  
   409  func TestBithashFlushAndGet(t *testing.T) {
   410  	defer os.RemoveAll(testdataDir)
   411  	os.RemoveAll(testdataDir)
   412  	b := testOpenBithash()
   413  	kvList := testBuildKV(5000)
   414  	bhWriter, err := b.FlushStart()
   415  	if err != nil {
   416  		panic(err)
   417  	}
   418  	for i, item := range kvList {
   419  		ik := base.MakeInternalKey(item.k, 0, InternalKeyKindSet)
   420  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   421  		if err != nil {
   422  			panic(err)
   423  		}
   424  	}
   425  	err = b.FlushFinish(bhWriter)
   426  	if err != nil {
   427  		panic(err)
   428  	}
   429  
   430  	for _, item := range kvList {
   431  		khash := hash.Crc32(item.k)
   432  		value, putBytePool, err := b.Get(item.k, khash, item.fn)
   433  		if err != nil {
   434  			panic(err)
   435  		}
   436  		if !bytes.Equal(value, item.v) {
   437  			panic(fmt.Sprintf("check kv fail k=%s fm=%d", string(item.k), uint64(item.fn)))
   438  		}
   439  		putBytePool()
   440  	}
   441  
   442  	testBithashClose(t, b)
   443  }
   444  
   445  func TestBithashFlushCloseAndGet(t *testing.T) {
   446  	defer os.RemoveAll(testdataDir)
   447  	os.RemoveAll(testdataDir)
   448  	kvList := testBuildKV(10000)
   449  	b := testOpenBithash()
   450  	bhWriter, err := b.FlushStart()
   451  	if err != nil {
   452  		panic(err)
   453  	}
   454  	for i, item := range kvList {
   455  		ik := base.MakeInternalKey(item.k, 0, InternalKeyKindSet)
   456  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   457  		if err != nil {
   458  			panic(err)
   459  		}
   460  	}
   461  	if err = b.FlushFinish(bhWriter); err != nil {
   462  		panic(err)
   463  	}
   464  	testBithashClose(t, b)
   465  
   466  	b1 := testOpenBithash()
   467  	for _, item := range kvList {
   468  		khash := hash.Crc32(item.k)
   469  		value, putBytePool, err := b1.Get(item.k, khash, item.fn)
   470  		if err != nil {
   471  			panic(err)
   472  		}
   473  		if !bytes.Equal(value, item.v) {
   474  			fmt.Println("check kv fail", string(item.k), item.fn)
   475  		}
   476  		putBytePool()
   477  	}
   478  
   479  	testBithashClose(t, b1)
   480  }
   481  
   482  func TestBithashWriteAndGet(t *testing.T) {
   483  	defer os.RemoveAll(testdataDir)
   484  	os.RemoveAll(testdataDir)
   485  	seqNum := uint64(1)
   486  	b := testOpenBithash()
   487  	num := 2000
   488  
   489  	fmt.Println("open1 b.mufn.fnMap", len(b.mufn.fnMap))
   490  	for k, v := range b.mufn.fnMap {
   491  		fmt.Println("open1", k, v)
   492  	}
   493  
   494  	kvList := testBuildKV(num)
   495  	bhWriter, err := b.FlushStart()
   496  	require.NoError(t, err)
   497  	for i, item := range kvList {
   498  		ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   499  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   500  		if err != nil {
   501  			panic(err)
   502  		}
   503  		seqNum++
   504  	}
   505  	require.NoError(t, b.FlushFinish(bhWriter))
   506  
   507  	fmt.Println("write1 kv finish")
   508  
   509  	for _, item := range kvList {
   510  		khash := hash.Crc32(item.k)
   511  		value, putBytePool, err := b.Get(item.k, khash, item.fn)
   512  		require.NoError(t, err)
   513  		if !bytes.Equal(item.v, value) {
   514  			t.Fatalf("key:%s\nexp:%s\nact:%s", string(item.k), string(item.v), string(value))
   515  		}
   516  		putBytePool()
   517  	}
   518  
   519  	testBithashClose(t, b)
   520  
   521  	b = testOpenBithash()
   522  	fmt.Println("open2 b.mufn.fnMap", len(b.mufn.fnMap))
   523  	for k, v := range b.mufn.fnMap {
   524  		fmt.Println("open2", k, v)
   525  	}
   526  
   527  	kvList = testBuildKV(num)
   528  	bhWriter, err = b.FlushStart()
   529  	require.NoError(t, err)
   530  	for i, item := range kvList {
   531  		ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   532  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   533  		if err != nil {
   534  			panic(err)
   535  		}
   536  		seqNum++
   537  	}
   538  	err = b.FlushFinish(bhWriter)
   539  	require.NoError(t, err)
   540  
   541  	fmt.Println("write2 kv finish")
   542  
   543  	fmt.Println("start get")
   544  	for _, item := range kvList {
   545  		khash := hash.Crc32(item.k)
   546  		value, putBytePool, err := b.Get(item.k, khash, item.fn)
   547  		require.NoError(t, err)
   548  		if !bytes.Equal(item.v, value) {
   549  			t.Fatalf("key:%s exp:%s act:%s", string(item.k), string(item.v), string(value))
   550  		}
   551  		putBytePool()
   552  	}
   553  
   554  	testBithashClose(t, b)
   555  
   556  	b = testOpenBithash()
   557  	fmt.Println("open3 b.mufn.fnMap", len(b.mufn.fnMap))
   558  	for k, v := range b.mufn.fnMap {
   559  		fmt.Println("open3", k, v)
   560  	}
   561  
   562  	testBithashClose(t, b)
   563  }
   564  
   565  func TestBithashWriteAndClose(t *testing.T) {
   566  	defer os.RemoveAll(testdataDir)
   567  	os.RemoveAll(testdataDir)
   568  	seqNum := uint64(1)
   569  
   570  	writeFunc := func() {
   571  		b := testOpenBithash()
   572  		num := 1900
   573  		kvList := testBuildKV(num)
   574  		bhWriter, err := b.FlushStart()
   575  		require.NoError(t, err)
   576  		for i, item := range kvList {
   577  			ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   578  			kvList[i].fn, err = bhWriter.Add(ik, item.v)
   579  			if err != nil {
   580  				panic(err)
   581  			}
   582  			seqNum++
   583  		}
   584  		require.NoError(t, b.FlushFinish(bhWriter))
   585  		testBithashClose(t, b)
   586  		b = testOpenBithash()
   587  		for _, item := range kvList {
   588  			khash := hash.Crc32(item.k)
   589  			value, putBytePool, e := b.Get(item.k, khash, item.fn)
   590  			if e != nil {
   591  				t.Fatalf("get fail key:%s err:%s", string(item.k), err)
   592  			}
   593  			if !bytes.Equal(item.v, value) {
   594  				t.Fatalf("get fail key:%s exp:%d act:%d", string(item.k), len(item.v), len(value))
   595  			}
   596  			putBytePool()
   597  		}
   598  		testBithashClose(t, b)
   599  	}
   600  
   601  	for i := 0; i < 10; i++ {
   602  		fmt.Println("openclose", i)
   603  		writeFunc()
   604  	}
   605  }
   606  
   607  func TestBithashKeyRepeat(t *testing.T) {
   608  	defer os.RemoveAll(testdataDir)
   609  	os.RemoveAll(testdataDir)
   610  
   611  	seqNum := uint64(1)
   612  	b := testOpenBithash()
   613  	num := 500
   614  
   615  	fmt.Println("start write 1")
   616  
   617  	kvList := testBuildKV(num)
   618  	bhWriter, err := b.FlushStart()
   619  	require.NoError(t, err)
   620  	for i, item := range kvList {
   621  		ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   622  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   623  		if err != nil {
   624  			panic(err)
   625  		}
   626  		seqNum++
   627  	}
   628  	err = b.FlushFinish(bhWriter)
   629  	require.NoError(t, err)
   630  
   631  	fmt.Println("start write 2")
   632  
   633  	kvList = testBuildKV(num)
   634  	bhWriter, err = b.FlushStart()
   635  	require.NoError(t, err)
   636  	for i, item := range kvList {
   637  		ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   638  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   639  		if err != nil {
   640  			panic(err)
   641  		}
   642  		seqNum++
   643  	}
   644  	err = b.FlushFinish(bhWriter)
   645  	require.NoError(t, err)
   646  
   647  	fmt.Println("start get")
   648  
   649  	for _, item := range kvList {
   650  		khash := hash.Crc32(item.k)
   651  		value, putBytePool, err := b.Get(item.k, khash, item.fn)
   652  		require.NoError(t, err)
   653  		require.Equal(t, item.v, value)
   654  		putBytePool()
   655  	}
   656  
   657  	testBithashClose(t, b)
   658  }
   659  
   660  func TestBithashKeyHashConflict(t *testing.T) {
   661  	defer os.RemoveAll(testdataDir)
   662  	os.RemoveAll(testdataDir)
   663  
   664  	seqNum := uint64(1)
   665  	b := testOpenBithash_64MB()
   666  
   667  	conflictKeys := []string{
   668  		"m_T`UpDSxCr`ySymsoev",
   669  		"yjdJKx\\xjRgcMn\\OHr`_",
   670  		"tNurPFGNoJ_UROdugxXM",
   671  		"`pheCoLCfcAr_qCdaIhE",
   672  		"NvxogGOdNnpRAnRAVaW]",
   673  		"qAGjXZSJkJpFbojaeFFu",
   674  		"t_paOJENejFVUfP]npTQ",
   675  		"WwfjcpTd\\tRZ\\WgYVUZK",
   676  		"wQtERVmd^xpSk_]n[_\\k",
   677  		"Wd\\[BIVamMWtMyPEybOa",
   678  		"\\sJNnWFpmpjEumBPT]ol",
   679  		"yfNJhKZyKikCokteoMag",
   680  	}
   681  
   682  	var conflictKvList []testKvItem
   683  	for _, k := range conflictKeys {
   684  		conflictKvList = append(conflictKvList, testKvItem{
   685  			k: []byte(k),
   686  			v: testGenValue(2048),
   687  		})
   688  	}
   689  
   690  	fmt.Println("start write 1")
   691  
   692  	kvList := testBuildKV(100)
   693  	bhWriter, err := b.FlushStart()
   694  	require.NoError(t, err)
   695  	for i, item := range kvList {
   696  		ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   697  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   698  		if err != nil {
   699  			panic(err)
   700  		}
   701  		seqNum++
   702  		if i == 50 {
   703  			for i, item := range conflictKvList {
   704  				ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   705  				conflictKvList[i].fn, err = bhWriter.Add(ik, item.v)
   706  				if err != nil {
   707  					panic(err)
   708  				}
   709  				seqNum++
   710  			}
   711  		}
   712  	}
   713  
   714  	err = b.FlushFinish(bhWriter)
   715  	require.NoError(t, err)
   716  
   717  	readKv := func() {
   718  		for _, item := range kvList {
   719  			value, putBytePool, err := b.Get(item.k, hash.Crc32(item.k), item.fn)
   720  			require.NoError(t, err)
   721  			require.Equal(t, item.v, value)
   722  			putBytePool()
   723  		}
   724  		for _, item := range conflictKvList {
   725  			value, putBytePool, err := b.Get(item.k, hash.Crc32(item.k), item.fn)
   726  			require.NoError(t, err)
   727  			require.Equal(t, item.v, value)
   728  			putBytePool()
   729  		}
   730  	}
   731  
   732  	fmt.Println("start get1")
   733  	readKv()
   734  
   735  	bhWriter, err = b.FlushStart()
   736  	require.NoError(t, err)
   737  	bhWriter.compact = true
   738  	err = b.FlushFinish(bhWriter)
   739  	require.NoError(t, err)
   740  
   741  	fmt.Println("start get2")
   742  	readKv()
   743  
   744  	fm := b.meta.mu.filesMeta[FileNum(1)]
   745  	fmt.Println("debuginfo", b.DebugInfo("test"))
   746  	fmt.Println("fm", fm)
   747  	require.Equal(t, uint32(112), fm.keyNum)
   748  	require.Equal(t, uint32(12), fm.conflictKeyNum)
   749  	testBithashClose(t, b)
   750  }
   751  
   752  func TestBithashOpenTableErrRebuild(t *testing.T) {
   753  	defer os.RemoveAll(testdataDir)
   754  	os.RemoveAll(testdataDir)
   755  
   756  	b := testOpenBithash()
   757  	seqNum := uint64(1)
   758  	num := 1200
   759  	kvList := testBuildKV(num)
   760  	bhWriter, err := b.FlushStart()
   761  	require.NoError(t, err)
   762  	for i, item := range kvList {
   763  		ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   764  		kvList[i].fn, err = bhWriter.Add(ik, item.v)
   765  		require.NoError(t, err)
   766  		seqNum++
   767  	}
   768  	require.NoError(t, b.FlushFinish(bhWriter))
   769  	n, err1 := bhWriter.wr.writer.Write([]byte("panic"))
   770  	require.NoError(t, err1)
   771  	require.Equal(t, 5, n)
   772  	require.NoError(t, bhWriter.wr.Flush())
   773  	//if bhWriter.wr.currentOffset != uint32(409836) {
   774  	//	t.Fatalf("check currentOffset exp:409836 act:%d", bhWriter.wr.currentOffset)
   775  	//}
   776  	require.Equal(t, uint32(409836), bhWriter.wr.currentOffset)
   777  	require.Equal(t, int64(409841), bhWriter.wr.fileStatSize())
   778  	time.Sleep(2 * time.Second)
   779  	testBithashClose(t, b)
   780  
   781  	b = testOpenBithash()
   782  	bhWriter, err = b.FlushStart()
   783  	require.NoError(t, err)
   784  	require.Equal(t, uint32(409836), bhWriter.wr.currentOffset)
   785  	require.Equal(t, int64(409841), bhWriter.wr.fileStatSize())
   786  	require.NoError(t, b.FlushFinish(bhWriter))
   787  	time.Sleep(2 * time.Second)
   788  	for _, item := range kvList {
   789  		khash := hash.Crc32(item.k)
   790  		value, putBytePool, err2 := b.Get(item.k, khash, item.fn)
   791  		require.NoError(t, err2)
   792  		require.Equal(t, item.v, value)
   793  		putBytePool()
   794  	}
   795  	testBithashClose(t, b)
   796  }
   797  
   798  func TestBithashMemSize(t *testing.T) {
   799  	defer os.RemoveAll(testdataDir)
   800  	os.RemoveAll(testdataDir)
   801  	b := testOpenBithash_64MB()
   802  
   803  	value := []byte("v")
   804  
   805  	bhWriter, err := b.FlushStart()
   806  	require.NoError(t, err)
   807  
   808  	lastFn := FileNum(0)
   809  	fileNum := make([]int, 200)
   810  	totalNum := 20 << 20
   811  
   812  	bt := time.Now()
   813  	for i := 0; i < totalNum; i++ {
   814  		key := []byte(fmt.Sprintf("bit_%d+hash_test%d+%d", i, i+512, i+1024))
   815  		ik := base.MakeInternalKey(key, uint64(i), InternalKeyKindSet)
   816  		fn, err := bhWriter.Add(ik, value)
   817  		if err != nil {
   818  			panic(err)
   819  		}
   820  
   821  		if fn != lastFn {
   822  			fileNum[int(fn)] = i
   823  			lastFn = fn
   824  		}
   825  	}
   826  	require.NoError(t, b.FlushFinish(bhWriter))
   827  	et := time.Since(bt)
   828  	fmt.Printf("build index time cost = %v\n", et)
   829  
   830  	bt = time.Now()
   831  	for i := 0; i < totalNum; i++ {
   832  		key := []byte(fmt.Sprintf("bit_%d+hash_test%d+%d", i, i+512, i+1024))
   833  		for j := 1; j < len(fileNum); j++ {
   834  			if i >= fileNum[j] && i < fileNum[j+1] || i >= fileNum[j] && fileNum[j+1] == 0 {
   835  				khash := hash.Crc32(key)
   836  				v, putBytePool, err := b.Get(key, khash, FileNum(j))
   837  				if err != nil {
   838  					fmt.Printf("check kv fail k=%s fn=%d\n", key, j)
   839  					break
   840  				}
   841  				if !bytes.Equal(value, v) {
   842  					panic(fmt.Sprintf("check kv fail k=%s fn=%d\n", key, j))
   843  				}
   844  				putBytePool()
   845  				break
   846  			}
   847  		}
   848  	}
   849  	et = time.Since(bt)
   850  	fmt.Printf("scan index time cost = %v\n", et)
   851  
   852  	printMemStats()
   853  }
   854  
   855  const MB = 1024 * 1024
   856  
   857  func printMemStats() {
   858  	var m runtime.MemStats
   859  	runtime.ReadMemStats(&m)
   860  	fmt.Printf("Map MEM: Alloc=%vMB; TotalAlloc=%vMB; SYS=%vMB; Mallocs=%v; Frees=%v; HeapAlloc=%vMB; HeapSys=%vMB; HeapIdle=%vMB; HeapReleased=%vMB; GCSys=%vMB; NextGC=%vMB; NumGC=%v; NumForcedGC=%v\n",
   861  		m.Alloc/MB, m.TotalAlloc/MB, m.Sys/MB, m.Mallocs, m.Frees, m.HeapAlloc/MB, m.HeapSys/MB, m.HeapIdle/MB, m.HeapReleased/MB,
   862  		m.GCSys/MB, m.NextGC/MB, m.NumGC, m.NumForcedGC)
   863  }
   864  
   865  func TestInitManifest(t *testing.T) {
   866  	defer os.RemoveAll(testdataDir)
   867  	os.RemoveAll(testdataDir)
   868  	bithash := testOpenBithash()
   869  	defer func() {
   870  		require.NoError(t, bithash.Close())
   871  	}()
   872  
   873  	require.Equal(t, versionV1, bithash.meta.version)
   874  
   875  	for fileNum, pos := range bithash.meta.mu.filesPos {
   876  		fmt.Println("fileMeta scan: ", fileNum, pos)
   877  		fileMeta := bithash.meta.getFileMetadata(fileNum)
   878  		fmt.Println("fileMeta value: ", fileMeta)
   879  	}
   880  }
   881  
   882  func TestBithashStats(t *testing.T) {
   883  	defer os.RemoveAll(testdataDir)
   884  	os.RemoveAll(testdataDir)
   885  	seqNum := uint64(1)
   886  	b := testOpenBithash()
   887  	defer testBithashClose(t, b)
   888  
   889  	num := 2000
   890  	kvList := testBuildKV(num)
   891  
   892  	writeFunc := func() {
   893  		bhWriter, err := b.FlushStart()
   894  		require.NoError(t, err)
   895  		for i, item := range kvList {
   896  			ik := base.MakeInternalKey(item.k, seqNum, InternalKeyKindSet)
   897  			kvList[i].fn, err = bhWriter.Add(ik, item.v)
   898  			if err != nil {
   899  				panic(err)
   900  			}
   901  			seqNum++
   902  		}
   903  		err = b.FlushFinish(bhWriter)
   904  		require.NoError(t, err)
   905  	}
   906  
   907  	deleteFunc := func() {
   908  		for i, item := range kvList {
   909  			if i%2 == 0 {
   910  				b.Delete(item.fn)
   911  			}
   912  		}
   913  	}
   914  
   915  	writeFunc()
   916  	deleteFunc()
   917  
   918  	require.Equal(t, uint64(2000), b.stats.KeyTotal.Load())
   919  	require.Equal(t, uint64(1000), b.stats.DelKeyTotal.Load())
   920  }
   921  
   922  func TestBithashReadFile(t *testing.T) {
   923  	fn := FileNum(1)
   924  	dir := ""
   925  	if dir == "" {
   926  		return
   927  	}
   928  
   929  	opts := &options.BithashOptions{
   930  		Options: &options.Options{
   931  			FS:         testFs,
   932  			Logger:     base.DefaultLogger,
   933  			Compressor: compress.SnappyCompressor,
   934  		},
   935  		TableMaxSize: 512 << 20,
   936  		Index:        1,
   937  	}
   938  
   939  	b := &Bithash{
   940  		dirname:      dir,
   941  		fs:           opts.FS,
   942  		tableMaxSize: opts.TableMaxSize,
   943  		logger:       opts.Logger,
   944  		compressor:   opts.Compressor,
   945  		index:        opts.Index,
   946  		bhtReaders:   sync.Map{},
   947  		rwwWriters:   sync.Map{},
   948  		stats:        &Stats{},
   949  	}
   950  	b.mufn.fnMap = make(map[FileNum]FileNum, 1<<10)
   951  	b.mutw.mutableWriters = list2.NewStack()
   952  
   953  	defer func() {
   954  		if err := b.Close(); err != nil {
   955  			t.Fatal(err)
   956  		}
   957  	}()
   958  
   959  	filename := MakeFilepath(b.fs, b.dirname, fileTypeTable, fn)
   960  	fmt.Println("filename", filename)
   961  
   962  	f, err := b.fs.Open(filename)
   963  	if err != nil {
   964  		t.Fatal(err)
   965  	}
   966  
   967  	r, err := NewReader(b, f, FileReopenOpt{fs: b.fs, filename: filename, fileNum: fn, readOnly: true})
   968  	if err != nil {
   969  		t.Fatal(err)
   970  	}
   971  
   972  	b.addReaders(r)
   973  	b.mufn.fnMap[fn] = fn
   974  
   975  	fmt.Println("dataBH", r.dataBH)
   976  	fmt.Println("indexHashBH", r.indexHashBH)
   977  	fmt.Println("conflictBH", r.conflictBH)
   978  	fmt.Println("conflictBuf len", len(r.conflictBuf))
   979  	fmt.Println("indexHash", r.indexHash.Size(), r.indexHash.Length())
   980  }