github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitpage/array_table.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  	"encoding/binary"
    20  	"errors"
    21  	"fmt"
    22  	"os"
    23  	"sort"
    24  
    25  	"github.com/golang/snappy"
    26  	"github.com/zuoyebang/bitalosdb/internal/base"
    27  	"github.com/zuoyebang/bitalosdb/internal/bindex"
    28  	"github.com/zuoyebang/bitalosdb/internal/bytepools"
    29  	"github.com/zuoyebang/bitalosdb/internal/cache/lrucache"
    30  	"github.com/zuoyebang/bitalosdb/internal/consts"
    31  	"github.com/zuoyebang/bitalosdb/internal/hash"
    32  )
    33  
    34  const (
    35  	atVersionDefault uint16 = iota + 1
    36  	atVersionPrefixCompress
    37  	atVersionBlockCompress
    38  	atVersionPrefixBlockCompress
    39  	atVersionBitrieCompress
    40  )
    41  
    42  const (
    43  	atHeaderSize   = 18
    44  	atHeaderOffset = tableDataOffset
    45  	atDataOffset   = atHeaderOffset + atHeaderSize
    46  
    47  	itemOffsetSize      = 4
    48  	itemHeaderLen       = 2
    49  	itemSharedMin       = 0
    50  	itemSharedMax       = 255
    51  	itemSharedRestart   = 254
    52  	itemSharedMinLength = 6
    53  )
    54  
    55  type arrayTable struct {
    56  	tbl           *table
    57  	filename      string
    58  	header        *atHeader
    59  	block         *pageBlock
    60  	blockSize     uint32
    61  	blockCache    *lrucache.LruCache
    62  	cacheID       uint64
    63  	useMapIndex   bool
    64  	itemsOffset   []uint32
    65  	intIndex      []byte
    66  	bitrieIndex   *Bitrie
    67  	mapIndex      *bindex.HashIndex
    68  	size          uint32
    69  	num           int
    70  	compressedBuf []byte
    71  	prevKey       []byte
    72  	prevValue     []byte
    73  	prevHasShared bool
    74  	sharedKey     []byte
    75  	sharedNum     int
    76  }
    77  
    78  type atHeader struct {
    79  	version        uint16
    80  	num            uint32
    81  	dataOffset     uint32
    82  	intIndexOffset uint32
    83  	mapIndexOffset uint32
    84  }
    85  
    86  type atOptions struct {
    87  	useMapIndex       bool
    88  	usePrefixCompress bool
    89  	useBlockCompress  bool
    90  	useBitrieCompress bool
    91  	blockSize         uint32
    92  }
    93  
    94  type atCacheOptions struct {
    95  	cache *lrucache.LruCache
    96  	id    uint64
    97  }
    98  
    99  func checkArrayTable(obj interface{}) {
   100  	s := obj.(*arrayTable)
   101  	if s.tbl != nil {
   102  		fmt.Fprintf(os.Stderr, "arrayTable(%s) buffer was not freed\n", s.tbl.path)
   103  		os.Exit(1)
   104  	}
   105  }
   106  
   107  func newArrayTable(path string, opts *atOptions, cacheOpts *atCacheOptions) (*arrayTable, error) {
   108  	tbl, err := openTable(path, defaultTableOptions)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	at := &arrayTable{
   114  		tbl:           tbl,
   115  		filename:      base.GetFilePathBase(path),
   116  		blockSize:     opts.blockSize,
   117  		blockCache:    cacheOpts.cache,
   118  		cacheID:       cacheOpts.id,
   119  		useMapIndex:   opts.useMapIndex,
   120  		num:           0,
   121  		prevKey:       nil,
   122  		prevValue:     nil,
   123  		prevHasShared: false,
   124  		sharedKey:     nil,
   125  		sharedNum:     0,
   126  	}
   127  
   128  	var headerOffset uint32
   129  	headerOffset, err = at.tbl.alloc(atHeaderSize)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	if headerOffset != atHeaderOffset {
   134  		return nil, errors.New("tblSize is not large enough to hold the arrayTable header")
   135  	}
   136  
   137  	at.header = &atHeader{
   138  		dataOffset: atDataOffset,
   139  		version:    getAtVersionByOpts(opts),
   140  	}
   141  
   142  	if opts.useBlockCompress || opts.useBitrieCompress {
   143  		at.useMapIndex = false
   144  	}
   145  
   146  	if opts.useBitrieCompress {
   147  		at.bitrieIndex = NewBitrie()
   148  		at.bitrieIndex.InitWriter()
   149  	} else {
   150  		at.itemsOffset = make([]uint32, 0, 1<<20)
   151  	}
   152  
   153  	if at.useMapIndex {
   154  		at.mapIndex = bindex.NewHashIndex(true)
   155  		at.mapIndex.InitWriter()
   156  	}
   157  
   158  	return at, nil
   159  }
   160  
   161  func openArrayTable(path string, cacheOpts *atCacheOptions) (*arrayTable, error) {
   162  	tbl, err := openTable(path, &tableOptions{openType: tableReadMmap})
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  
   167  	at := &arrayTable{
   168  		tbl:        tbl,
   169  		filename:   base.GetFilePathBase(path),
   170  		blockCache: cacheOpts.cache,
   171  		cacheID:    cacheOpts.id,
   172  	}
   173  
   174  	at.readHeader()
   175  	at.num = int(at.header.num)
   176  	at.size = at.tbl.Size()
   177  
   178  	if at.header.version == atVersionBitrieCompress {
   179  		at.bitrieIndex = NewBitrie()
   180  	} else if at.header.mapIndexOffset > 0 {
   181  		at.useMapIndex = true
   182  		at.mapIndex = bindex.NewHashIndex(true)
   183  	}
   184  
   185  	at.dataIntBuffer()
   186  
   187  	return at, nil
   188  }
   189  
   190  func getAtVersionByOpts(opts *atOptions) uint16 {
   191  	var version uint16
   192  	if opts.useBitrieCompress {
   193  		version = atVersionBitrieCompress
   194  	} else if opts.usePrefixCompress {
   195  		if opts.useBlockCompress {
   196  			version = atVersionPrefixBlockCompress
   197  		} else {
   198  			version = atVersionPrefixCompress
   199  		}
   200  	} else {
   201  		if opts.useBlockCompress {
   202  			version = atVersionBlockCompress
   203  		} else {
   204  			version = atVersionDefault
   205  		}
   206  	}
   207  	return version
   208  }
   209  
   210  func (a *arrayTable) writeHeader() {
   211  	buf := a.tbl.getBytes(atHeaderOffset, atHeaderSize)
   212  	binary.BigEndian.PutUint16(buf[0:2], a.header.version)
   213  	binary.BigEndian.PutUint32(buf[2:6], a.header.num)
   214  	binary.BigEndian.PutUint32(buf[6:10], a.header.dataOffset)
   215  	binary.BigEndian.PutUint32(buf[10:14], a.header.intIndexOffset)
   216  	binary.BigEndian.PutUint32(buf[14:18], a.header.mapIndexOffset)
   217  }
   218  
   219  func (a *arrayTable) readHeader() {
   220  	buf := a.tbl.getBytes(atHeaderOffset, atHeaderSize)
   221  	a.header = &atHeader{}
   222  	a.header.version = binary.BigEndian.Uint16(buf[0:2])
   223  	a.header.num = binary.BigEndian.Uint32(buf[2:6])
   224  	a.header.dataOffset = binary.BigEndian.Uint32(buf[6:10])
   225  	a.header.intIndexOffset = binary.BigEndian.Uint32(buf[10:14])
   226  	a.header.mapIndexOffset = binary.BigEndian.Uint32(buf[14:18])
   227  }
   228  
   229  func (a *arrayTable) dataIntBuffer() {
   230  	if a.header.version == atVersionBitrieCompress {
   231  		a.bitrieIndex.SetReader(a.tbl.getBytes(0, a.size), atDataOffset)
   232  	} else {
   233  		a.intIndex = a.tbl.getBytes(a.header.intIndexOffset, a.getIntIndexSize())
   234  	}
   235  
   236  	if a.useMapIndex {
   237  		a.mapIndex.SetReader(a.tbl.getBytes(a.header.mapIndexOffset, a.size-a.header.mapIndexOffset))
   238  	}
   239  }
   240  
   241  func (a *arrayTable) getVersion() uint32 {
   242  	return uint32(a.header.version)
   243  }
   244  
   245  func (a *arrayTable) getIntIndexSize() uint32 {
   246  	return uint32(a.num * itemOffsetSize)
   247  }
   248  
   249  func (a *arrayTable) writeSharedInternal(shared int) (uint32, error) {
   250  	var keySize uint32
   251  
   252  	if !a.prevHasShared {
   253  		if shared >= itemSharedMinLength {
   254  			keySize = uint32(len(a.prevKey)) + 3
   255  		} else {
   256  			keySize = uint32(len(a.prevKey)) + 1
   257  		}
   258  	} else {
   259  		keySize = uint32(len(a.prevKey[len(a.sharedKey):])) + 1
   260  	}
   261  
   262  	valueSize := uint32(len(a.prevValue))
   263  	sz := keySize + valueSize + itemHeaderLen
   264  
   265  	offset, err := a.tbl.alloc(sz)
   266  	if err != nil {
   267  		return 0, err
   268  	}
   269  
   270  	a.itemsOffset = append(a.itemsOffset, offset)
   271  	itemBuf := a.tbl.getBytes(offset, sz)
   272  	binary.BigEndian.PutUint16(itemBuf[0:itemHeaderLen], uint16(keySize))
   273  
   274  	if !a.prevHasShared {
   275  		if shared >= itemSharedMinLength {
   276  			itemBuf[itemHeaderLen] = itemSharedMin
   277  			binary.BigEndian.PutUint16(itemBuf[itemHeaderLen+1:itemHeaderLen+3], uint16(len(a.sharedKey)))
   278  			copy(itemBuf[itemHeaderLen+3:itemHeaderLen+keySize], a.prevKey)
   279  		} else {
   280  			itemBuf[itemHeaderLen] = itemSharedMax
   281  			copy(itemBuf[itemHeaderLen+1:itemHeaderLen+keySize], a.prevKey)
   282  		}
   283  	} else {
   284  		itemBuf[itemHeaderLen] = uint8(a.num - a.sharedNum)
   285  		copy(itemBuf[itemHeaderLen+1:itemHeaderLen+keySize], a.prevKey[len(a.sharedKey):])
   286  	}
   287  
   288  	copy(itemBuf[itemHeaderLen+keySize:sz], a.prevValue)
   289  
   290  	a.num++
   291  
   292  	if a.useMapIndex {
   293  		a.mapIndex.Add(hash.Crc32(a.prevKey), uint32(a.num))
   294  	}
   295  
   296  	return sz, nil
   297  }
   298  
   299  func (a *arrayTable) writeItem(key, value []byte) (uint32, error) {
   300  	switch a.header.version {
   301  	case atVersionPrefixCompress:
   302  		return a.writeItemPrefixCompress(key, value)
   303  	case atVersionBlockCompress, atVersionPrefixBlockCompress:
   304  		return a.writeItemBlockCompress(key, value)
   305  	case atVersionBitrieCompress:
   306  		return a.writeItemBitrieCompress(key, value)
   307  	}
   308  
   309  	return a.writeItemDefault(key, value)
   310  }
   311  
   312  func (a *arrayTable) writeItemDefault(key, value []byte) (uint32, error) {
   313  	keySize := uint32(len(key))
   314  	valueSize := uint32(len(value))
   315  
   316  	sz := keySize + valueSize + itemHeaderLen
   317  	offset, err := a.tbl.alloc(sz)
   318  	if err != nil {
   319  		return 0, err
   320  	}
   321  
   322  	a.itemsOffset = append(a.itemsOffset, offset)
   323  	itemBuf := a.tbl.getBytes(offset, sz)
   324  	binary.BigEndian.PutUint16(itemBuf[0:itemHeaderLen], uint16(keySize))
   325  	copy(itemBuf[itemHeaderLen:itemHeaderLen+keySize], key)
   326  	copy(itemBuf[itemHeaderLen+keySize:sz], value)
   327  
   328  	a.num++
   329  
   330  	if a.useMapIndex {
   331  		a.mapIndex.Add(hash.Crc32(key), uint32(a.num))
   332  	}
   333  
   334  	return sz, nil
   335  }
   336  
   337  func (a *arrayTable) writeItemPrefixCompress(key, value []byte) (uint32, error) {
   338  	if a.prevKey == nil && a.prevValue == nil {
   339  		a.prevKey = make([]byte, 0, 1<<7)
   340  		a.prevKey = append(a.prevKey[:0], key...)
   341  		a.prevValue = value
   342  		a.prevHasShared = false
   343  		a.sharedKey = make([]byte, 0, 1<<6)
   344  		return 0, nil
   345  	}
   346  
   347  	shared := 0
   348  	n := len(key)
   349  	if n > len(a.prevKey) {
   350  		n = len(a.prevKey)
   351  	}
   352  	asUint64 := func(b []byte, i int) uint64 {
   353  		return binary.LittleEndian.Uint64(b[i:])
   354  	}
   355  
   356  	for shared < n-7 && asUint64(key, shared) == asUint64(a.prevKey, shared) {
   357  		shared += 8
   358  	}
   359  	for shared < n && key[shared] == a.prevKey[shared] {
   360  		shared++
   361  	}
   362  
   363  	if shared > 0 {
   364  		sharedKeyLength := len(a.sharedKey)
   365  		if shared < itemSharedMinLength || shared < sharedKeyLength {
   366  			shared = 0
   367  		} else {
   368  			if !a.prevHasShared {
   369  				a.sharedKey = append(a.sharedKey[:0], key[:shared]...)
   370  				a.sharedNum = a.num
   371  			} else if shared > sharedKeyLength+4 || a.num-a.sharedNum >= itemSharedRestart {
   372  				shared = 0
   373  			} else {
   374  				shared = sharedKeyLength
   375  			}
   376  		}
   377  	}
   378  
   379  	sz, err := a.writeSharedInternal(shared)
   380  	if err != nil {
   381  		return 0, err
   382  	}
   383  
   384  	a.prevKey = append(a.prevKey[:0], key...)
   385  	a.prevValue = value
   386  	if shared >= itemSharedMinLength {
   387  		a.prevHasShared = true
   388  	} else {
   389  		a.prevHasShared = false
   390  		a.sharedKey = a.sharedKey[:0]
   391  		a.sharedNum = 0
   392  	}
   393  
   394  	return sz, err
   395  }
   396  
   397  func (a *arrayTable) writeItemBlockCompress(key, value []byte) (uint32, error) {
   398  	if a.block == nil {
   399  		a.block = newPageBlock(a.header.version, a.blockSize)
   400  	}
   401  
   402  	a.block.writeItem(key, value)
   403  
   404  	if a.block.inuseBytes() >= a.blockSize &&
   405  		a.block.itemCount() >= consts.BitpageBlockMinItemCount {
   406  		a.block.writeFinish()
   407  
   408  		blockBuf := compressEncode(a.compressedBuf, a.block.bytes())
   409  		if cap(blockBuf) > cap(a.compressedBuf) {
   410  			a.compressedBuf = blockBuf[:cap(blockBuf)]
   411  		}
   412  		bufSize := len(blockBuf)
   413  
   414  		keySize := len(key)
   415  		sz := uint32(keySize + bufSize + itemHeaderLen)
   416  		offset, err := a.tbl.alloc(sz)
   417  		if err != nil {
   418  			return 0, err
   419  		}
   420  
   421  		a.itemsOffset = append(a.itemsOffset, offset)
   422  		itemBuf := a.tbl.getBytes(offset, sz)
   423  		binary.BigEndian.PutUint16(itemBuf[0:itemHeaderLen], uint16(keySize))
   424  		copy(itemBuf[itemHeaderLen:itemHeaderLen+keySize], key)
   425  		copy(itemBuf[itemHeaderLen+keySize:sz], blockBuf)
   426  
   427  		a.block.reset(a.header.version)
   428  		a.num++
   429  
   430  		return sz, nil
   431  	}
   432  
   433  	return 0, nil
   434  }
   435  
   436  func (a *arrayTable) writeItemBitrieCompress(key, value []byte) (uint32, error) {
   437  	a.bitrieIndex.Add(key, value)
   438  
   439  	a.num++
   440  
   441  	return uint32(len(key) + len(value)), nil
   442  }
   443  
   444  func (a *arrayTable) writeFinish() error {
   445  	switch a.header.version {
   446  	case atVersionDefault, atVersionPrefixCompress:
   447  		return a.writeFinishNonBlockCompress()
   448  	case atVersionBlockCompress, atVersionPrefixBlockCompress:
   449  		return a.writeFinishBlockCompress()
   450  	case atVersionBitrieCompress:
   451  		return a.writeFinishBitrieCompress()
   452  	}
   453  
   454  	return a.writeFinishNonBlockCompress()
   455  }
   456  
   457  func (a *arrayTable) writeFinishNonBlockCompress() error {
   458  	if a.header.version == atVersionPrefixCompress && a.prevKey != nil && a.prevValue != nil {
   459  		if _, err := a.writeSharedInternal(0); err != nil {
   460  			return err
   461  		}
   462  	}
   463  
   464  	intSize := a.getIntIndexSize()
   465  	intIndexOffset, err := a.tbl.alloc(intSize)
   466  	if err != nil {
   467  		return err
   468  	}
   469  	intIndexBuf := a.tbl.getBytes(intIndexOffset, intSize)
   470  	intIndexPos := 0
   471  	for i := range a.itemsOffset {
   472  		binary.BigEndian.PutUint32(intIndexBuf[intIndexPos:intIndexPos+itemOffsetSize], a.itemsOffset[i])
   473  		intIndexPos += itemOffsetSize
   474  	}
   475  
   476  	var mapIndexOffset uint32
   477  	if a.useMapIndex {
   478  		mapSize := a.mapIndex.Size()
   479  		mapIndexOffset, err = a.tbl.alloc(mapSize)
   480  		if err != nil {
   481  			return err
   482  		}
   483  		a.mapIndex.SetWriter(a.tbl.getBytes(mapIndexOffset, mapSize))
   484  		if !a.mapIndex.Serialize() {
   485  			return errors.New("hash_index write fail")
   486  		}
   487  
   488  		a.mapIndex.Finish()
   489  	}
   490  
   491  	a.size = a.tbl.Size()
   492  	a.itemsOffset = nil
   493  	a.header.num = uint32(a.num)
   494  	a.header.intIndexOffset = intIndexOffset
   495  	a.header.mapIndexOffset = mapIndexOffset
   496  	a.writeHeader()
   497  
   498  	if err = a.tbl.mmapReadTruncate(int(a.size)); err != nil {
   499  		return err
   500  	}
   501  
   502  	a.dataIntBuffer()
   503  
   504  	a.block = nil
   505  	a.compressedBuf = nil
   506  	a.prevKey = nil
   507  	a.prevValue = nil
   508  	a.sharedKey = nil
   509  
   510  	return nil
   511  }
   512  
   513  func (a *arrayTable) writeFinishBlockCompress() error {
   514  	if !a.block.empty() {
   515  		a.block.writeFinish()
   516  
   517  		blockBuf := compressEncode(a.compressedBuf, a.block.bytes())
   518  		bufSize := len(blockBuf)
   519  
   520  		key := consts.BdbMaxKey
   521  		keySize := len(consts.BdbMaxKey)
   522  		sz := uint32(keySize + bufSize + itemHeaderLen)
   523  		offset, err := a.tbl.alloc(sz)
   524  		if err != nil {
   525  			return err
   526  		}
   527  
   528  		a.itemsOffset = append(a.itemsOffset, offset)
   529  		itemBuf := a.tbl.getBytes(offset, sz)
   530  		binary.BigEndian.PutUint16(itemBuf[0:itemHeaderLen], uint16(keySize))
   531  		copy(itemBuf[itemHeaderLen:itemHeaderLen+keySize], key)
   532  		copy(itemBuf[itemHeaderLen+keySize:sz], blockBuf)
   533  
   534  		a.block.reset(a.header.version)
   535  
   536  		a.num++
   537  	}
   538  
   539  	intSize := a.getIntIndexSize()
   540  	intIndexOffset, err := a.tbl.alloc(intSize)
   541  	if err != nil {
   542  		return err
   543  	}
   544  	intIndexBuf := a.tbl.getBytes(intIndexOffset, intSize)
   545  	intIndexPos := 0
   546  	for i := range a.itemsOffset {
   547  		binary.BigEndian.PutUint32(intIndexBuf[intIndexPos:intIndexPos+itemOffsetSize], a.itemsOffset[i])
   548  		intIndexPos += itemOffsetSize
   549  	}
   550  
   551  	a.size = a.tbl.Size()
   552  	a.itemsOffset = nil
   553  	a.header.num = uint32(a.num)
   554  	a.header.intIndexOffset = intIndexOffset
   555  	a.header.mapIndexOffset = 0
   556  	a.writeHeader()
   557  
   558  	if err = a.tbl.mmapReadTruncate(int(a.size)); err != nil {
   559  		return err
   560  	}
   561  
   562  	a.dataIntBuffer()
   563  
   564  	a.block = nil
   565  	a.compressedBuf = nil
   566  	a.prevKey = nil
   567  	a.prevValue = nil
   568  	a.sharedKey = nil
   569  
   570  	return nil
   571  }
   572  
   573  func (a *arrayTable) writeFinishBitrieCompress() error {
   574  	tblalloc := func(size uint32) uint32 {
   575  		offset, _ := a.tbl.alloc(size)
   576  		return offset
   577  	}
   578  
   579  	tblbytes := func(offset uint32, size uint32) []byte {
   580  		return a.tbl.getBytes(offset, size)
   581  	}
   582  
   583  	tblsize := func() uint32 {
   584  		return a.tbl.Size()
   585  	}
   586  
   587  	if !a.bitrieIndex.Serialize(tblalloc, tblbytes, tblsize) {
   588  		return errors.New("bitrie serialize fail")
   589  	}
   590  	a.bitrieIndex.Finish()
   591  
   592  	a.size = a.tbl.Size()
   593  	a.itemsOffset = nil
   594  	a.header.num = uint32(a.num)
   595  	a.header.intIndexOffset = 0
   596  	a.header.mapIndexOffset = 0
   597  	a.writeHeader()
   598  
   599  	if err := a.tbl.mmapReadTruncate(int(a.size)); err != nil {
   600  		return err
   601  	}
   602  
   603  	a.dataIntBuffer()
   604  
   605  	a.block = nil
   606  	a.compressedBuf = nil
   607  	a.prevKey = nil
   608  	a.prevValue = nil
   609  	a.sharedKey = nil
   610  
   611  	return nil
   612  }
   613  
   614  func (a *arrayTable) getSharedKey(i int, key []byte, sharedCache *sharedInfo) ([]byte, []byte) {
   615  	offset := key[0]
   616  	switch offset {
   617  	case itemSharedMin:
   618  		return key[3:], nil
   619  	case itemSharedMax:
   620  		return key[1:], nil
   621  	default:
   622  		idx := i - int(offset)
   623  
   624  		if sharedCache != nil && sharedCache.idx == idx && len(sharedCache.key) >= itemSharedMinLength {
   625  			return sharedCache.key, key[1:]
   626  		}
   627  
   628  		itemOffset := a.getItemOffset(idx)
   629  		if itemOffset == 0 {
   630  			return nil, nil
   631  		}
   632  
   633  		sharedKeySize := uint32(binary.BigEndian.Uint16(a.tbl.getBytes(itemOffset, itemHeaderLen)))
   634  		sharedKey := a.tbl.getBytes(itemOffset+itemHeaderLen, sharedKeySize)
   635  
   636  		sharedKeyOffset := sharedKey[0]
   637  		if sharedKeyOffset != itemSharedMin {
   638  			return nil, nil
   639  		}
   640  
   641  		sharedKeyLenght := uint32(binary.BigEndian.Uint16(sharedKey[1:]) + 3)
   642  		if sharedKeyLenght > sharedKeySize {
   643  			return nil, nil
   644  		}
   645  
   646  		if sharedCache != nil && sharedCache.idx != idx {
   647  			sharedCache.idx = idx
   648  			sharedCache.key = sharedKey[3:sharedKeyLenght]
   649  		}
   650  
   651  		return sharedKey[3:sharedKeyLenght], key[1:]
   652  	}
   653  }
   654  
   655  func (a *arrayTable) checkPositon(i int) bool {
   656  	return i >= 0 && i < a.num
   657  }
   658  
   659  func (a *arrayTable) getItemOffset(i int) uint32 {
   660  	if i < 0 || i >= a.num {
   661  		return 0
   662  	}
   663  
   664  	pos := i * itemOffsetSize
   665  	itemOffset := binary.BigEndian.Uint32(a.intIndex[pos : pos+itemOffsetSize])
   666  
   667  	return itemOffset
   668  }
   669  
   670  func (a *arrayTable) getKey(i int) ([]byte, []byte) {
   671  	itemOffset := a.getItemOffset(i)
   672  	if itemOffset == 0 {
   673  		return nil, nil
   674  	}
   675  
   676  	keySize := uint32(binary.BigEndian.Uint16(a.tbl.getBytes(itemOffset, itemHeaderLen)))
   677  	key := a.tbl.getBytes(itemOffset+itemHeaderLen, keySize)
   678  
   679  	if a.header.version == atVersionPrefixCompress {
   680  		return a.getSharedKey(i, key, nil)
   681  	}
   682  
   683  	return key, nil
   684  }
   685  
   686  func (a *arrayTable) getMaxKey() []byte {
   687  	pos := a.num - 1
   688  	itemOffset := a.getItemOffset(pos)
   689  	if itemOffset == 0 {
   690  		return nil
   691  	}
   692  
   693  	keySize := uint32(binary.BigEndian.Uint16(a.tbl.getBytes(itemOffset, itemHeaderLen)))
   694  	key := a.tbl.getBytes(itemOffset+itemHeaderLen, keySize)
   695  
   696  	if a.header.version == atVersionPrefixCompress {
   697  		sharedKey1, sharedKey2 := a.getSharedKey(pos, key, nil)
   698  		sk1l := len(sharedKey1)
   699  		sk2l := len(sharedKey2)
   700  		rawKey := make([]byte, sk1l+sk2l)
   701  		copy(rawKey[:sk1l], sharedKey1)
   702  		copy(rawKey[sk1l:], sharedKey2)
   703  
   704  		return rawKey
   705  	}
   706  
   707  	return key
   708  }
   709  
   710  func (a *arrayTable) getKV(i int) ([]byte, []byte) {
   711  	itemOffset := a.getItemOffset(i)
   712  	if itemOffset == 0 {
   713  		return nil, nil
   714  	}
   715  
   716  	var itemSize uint32
   717  	if i == a.num-1 {
   718  		itemSize = a.header.intIndexOffset - itemOffset
   719  	} else {
   720  		itemSize = a.getItemOffset(i+1) - itemOffset
   721  	}
   722  
   723  	keySize := uint32(binary.BigEndian.Uint16(a.tbl.getBytes(itemOffset, itemHeaderLen)))
   724  	keyOffset := itemOffset + itemHeaderLen
   725  	key := a.tbl.getBytes(keyOffset, keySize)
   726  	valueSize := itemSize - keySize - itemHeaderLen
   727  	value := a.tbl.getBytes(keyOffset+keySize, valueSize)
   728  
   729  	return key, value
   730  }
   731  
   732  func (a *arrayTable) getSharedKV(i int, sharedCache *sharedInfo) ([]byte, []byte, []byte) {
   733  	key, value := a.getKV(i)
   734  	if key == nil {
   735  		return nil, nil, nil
   736  	}
   737  
   738  	if a.header.version == atVersionPrefixCompress {
   739  		sharedKey1, sharedKey2 := a.getSharedKey(i, key, sharedCache)
   740  		return sharedKey1, sharedKey2, value
   741  	}
   742  
   743  	return key, nil, value
   744  
   745  }
   746  
   747  func (a *arrayTable) get(key []byte, khash uint32) ([]byte, bool, internalKeyKind, func()) {
   748  	if a.header.version == atVersionBitrieCompress {
   749  		value, exist := a.bitrieIndex.Get(key)
   750  		if exist {
   751  			return value, true, internalKeyKindSet, nil
   752  		} else {
   753  			return nil, false, internalKeyKindInvalid, nil
   754  		}
   755  	}
   756  
   757  	var pos int
   758  	if a.useMapIndex {
   759  		pos = a.findKeyByMapIndex(khash)
   760  		sharedKey1, sharedKey2 := a.getKey(pos)
   761  		if sharedKey1 == nil {
   762  			return nil, false, internalKeyKindInvalid, nil
   763  		}
   764  		if atEqual(sharedKey1, sharedKey2, key) {
   765  			_, value := a.getKV(pos)
   766  			return value, true, internalKeyKindSet, nil
   767  		}
   768  	}
   769  
   770  	pos = a.findKeyByIntIndex(key)
   771  
   772  	if a.isNonBlock() {
   773  		sharedKey1, sharedKey2, value := a.getSharedKV(pos, nil)
   774  		if sharedKey1 == nil || !atEqual(sharedKey1, sharedKey2, key) {
   775  			return nil, false, internalKeyKindInvalid, nil
   776  		}
   777  
   778  		return value, true, internalKeyKindSet, nil
   779  	}
   780  
   781  	blockBuf, closer, blockExist := a.blockCache.GetBlock(a.cacheID, uint64(pos))
   782  	if !blockExist {
   783  		_, blockBuf = a.getKV(pos)
   784  		if len(blockBuf) == 0 {
   785  			return nil, false, internalKeyKindInvalid, nil
   786  		}
   787  
   788  		var compressedBuf []byte
   789  		compressedBuf, closer = bytepools.ReaderBytePools.GetMaxBytePool()
   790  		blockBuf, _ = compressDecode(compressedBuf, blockBuf)
   791  		_ = a.blockCache.SetBlock(a.cacheID, uint64(pos), blockBuf)
   792  	}
   793  
   794  	pb := pageBlock{}
   795  	openPageBlock(&pb, blockBuf)
   796  	value, exist, kind := pb.get(key)
   797  	if !exist && closer != nil {
   798  		closer()
   799  		closer = nil
   800  	}
   801  
   802  	return value, exist, kind, closer
   803  }
   804  
   805  func (a *arrayTable) isNonBlock() bool {
   806  	return a.header.version == atVersionDefault ||
   807  		a.header.version == atVersionPrefixCompress
   808  }
   809  
   810  func (a *arrayTable) newIter(opts *iterOptions) internalIterator {
   811  	iter := atIterPool.Get().(*arrayTableIterator)
   812  	iter.at = a
   813  
   814  	if opts != nil {
   815  		iter.disableCache = opts.DisableCache
   816  	} else {
   817  		iter.disableCache = false
   818  	}
   819  
   820  	if a.header.version == atVersionPrefixCompress {
   821  		if cap(iter.keyBuf) == 0 {
   822  			iter.keyBuf = make([]byte, 0, 1<<7)
   823  		}
   824  		if iter.sharedCache == nil {
   825  			iter.sharedCache = &sharedInfo{idx: -1, key: nil}
   826  		}
   827  	}
   828  
   829  	return iter
   830  }
   831  
   832  func (a *arrayTable) delPercent() float64 {
   833  	return 0.0
   834  }
   835  
   836  func (a *arrayTable) itemCount() int {
   837  	return a.num
   838  }
   839  
   840  func (a *arrayTable) inuseBytes() uint64 {
   841  	return uint64(a.tbl.Size())
   842  }
   843  
   844  func (a *arrayTable) dataBytes() uint64 {
   845  	return uint64(a.header.intIndexOffset - a.header.dataOffset)
   846  }
   847  
   848  func (a *arrayTable) close() error {
   849  	if a.tbl == nil {
   850  		return nil
   851  	}
   852  
   853  	if err := a.tbl.close(); err != nil {
   854  		return err
   855  	}
   856  
   857  	a.tbl = nil
   858  	return nil
   859  }
   860  
   861  func (a *arrayTable) readyForFlush() bool {
   862  	return true
   863  }
   864  
   865  func (a *arrayTable) path() string {
   866  	if a.tbl == nil {
   867  		return ""
   868  	}
   869  	return a.tbl.path
   870  }
   871  
   872  func (a *arrayTable) idxFilePath() string {
   873  	return ""
   874  }
   875  
   876  func (a *arrayTable) empty() bool {
   877  	return a.num == 0
   878  }
   879  
   880  func (a *arrayTable) findKeyByMapIndex(khash uint32) int {
   881  	var pos int
   882  	v, exist := a.mapIndex.Get32(khash)
   883  	if exist {
   884  		pos = int(v - 1)
   885  	} else {
   886  		pos = a.num
   887  	}
   888  	return pos
   889  }
   890  
   891  func (a *arrayTable) findKeyByIntIndex(key []byte) int {
   892  	return sort.Search(a.num, func(i int) bool {
   893  		sharedKey1, sharedKey2 := a.getKey(i)
   894  		return atCompare(sharedKey1, sharedKey2, key) != -1
   895  	})
   896  }
   897  
   898  func atCompare(sharedKey1 []byte, sharedKey2 []byte, key []byte) int {
   899  	if sharedKey1 != nil && sharedKey2 == nil {
   900  		return bytes.Compare(sharedKey1, key)
   901  	} else {
   902  		sk1l := len(sharedKey1)
   903  		kl := len(key)
   904  		if sk1l <= kl {
   905  			if r := bytes.Compare(sharedKey1, key[:sk1l]); r != 0 {
   906  				return r
   907  			} else {
   908  				return bytes.Compare(sharedKey2, key[sk1l:])
   909  			}
   910  		} else {
   911  			return bytes.Compare(sharedKey1, key)
   912  		}
   913  	}
   914  }
   915  
   916  func atEqual(sharedKey1 []byte, sharedKey2 []byte, key []byte) bool {
   917  	if sharedKey1 != nil && sharedKey2 == nil {
   918  		return bytes.Equal(sharedKey1, key)
   919  	} else {
   920  		sk1l := len(sharedKey1)
   921  		sk2l := len(sharedKey2)
   922  		kl := len(key)
   923  		if sk1l+sk2l == kl && bytes.Equal(sharedKey1, key[:sk1l]) && bytes.Equal(sharedKey2, key[sk1l:]) {
   924  			return true
   925  		}
   926  	}
   927  
   928  	return false
   929  }
   930  
   931  func compressEncode(dst, src []byte) []byte {
   932  	return snappy.Encode(dst, src)
   933  }
   934  
   935  func compressDecode(dst, src []byte) ([]byte, error) {
   936  	return snappy.Decode(dst, src)
   937  }