github.com/coocood/badger@v1.5.1-0.20200528065104-c02ac3616d04/table/sstable/hash_index.go (about)

     1  package sstable
     2  
     3  import (
     4  	"encoding/binary"
     5  )
     6  
     7  const (
     8  	resultNoEntry  = 65535
     9  	resultFallback = 65534
    10  	maxBlockCnt    = 65533
    11  )
    12  
    13  type hashEntry struct {
    14  	entryPosition
    15  	hash uint64
    16  }
    17  
    18  type entryPosition struct {
    19  	// blockIdx is the index of block which contains this key.
    20  	blockIdx uint16
    21  
    22  	// offset is the index of this key in block.
    23  	offset uint8
    24  }
    25  
    26  func (e *entryPosition) encode() []byte {
    27  	b := make([]byte, 3)
    28  	binary.LittleEndian.PutUint16(b, e.blockIdx)
    29  	b[2] = e.offset
    30  	return b
    31  }
    32  
    33  func (e *entryPosition) decode(b []byte) {
    34  	e.blockIdx = binary.LittleEndian.Uint16(b)
    35  	e.offset = b[2]
    36  }
    37  
    38  func buildHashIndex(hashEntries []hashEntry, hashUtilRatio float32) []byte {
    39  	if len(hashEntries) == 0 {
    40  		return u32ToBytes(0)
    41  	}
    42  
    43  	numBuckets := uint32(float32(len(hashEntries)) / hashUtilRatio)
    44  	buf := make([]byte, numBuckets*3+4)
    45  	copy(buf, u32ToBytes(numBuckets))
    46  	buckets := buf[4:]
    47  	for i := 0; i < int(numBuckets); i++ {
    48  		binary.LittleEndian.PutUint16(buckets[i*3:], resultNoEntry)
    49  	}
    50  
    51  	for _, h := range hashEntries {
    52  		idx := h.hash % uint64(numBuckets)
    53  		bucket := buckets[idx*3 : (idx+1)*3]
    54  		blkIdx := binary.LittleEndian.Uint16(bucket[:2])
    55  		if blkIdx == resultNoEntry {
    56  			binary.LittleEndian.PutUint16(bucket[:2], h.blockIdx)
    57  			bucket[2] = h.offset
    58  		} else if blkIdx != h.blockIdx {
    59  			binary.LittleEndian.PutUint16(bucket[:2], resultFallback)
    60  		}
    61  	}
    62  
    63  	return buf
    64  }
    65  
    66  type hashIndex struct {
    67  	buckets    []byte
    68  	numBuckets int
    69  }
    70  
    71  func (i *hashIndex) readIndex(buf []byte) {
    72  	i.numBuckets = int(bytesToU32(buf[:4]))
    73  	i.buckets = buf[4:]
    74  }
    75  
    76  func (i *hashIndex) lookup(keyHash uint64) (uint32, uint8) {
    77  	if i.buckets == nil {
    78  		return resultFallback, 0
    79  	}
    80  	idx := keyHash % uint64(i.numBuckets)
    81  	buf := i.buckets[idx*3:]
    82  	blkIdx := binary.LittleEndian.Uint16(buf)
    83  	return uint32(blkIdx), uint8(buf[2])
    84  }