github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/soliton/mvmap/mvmap.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package mvmap
    15  
    16  import (
    17  	"bytes"
    18  )
    19  
    20  type entry struct {
    21  	addr   dataAddr
    22  	keyLen uint32
    23  	valLen uint32
    24  	next   entryAddr
    25  }
    26  
    27  type entryStore struct {
    28  	slices   [][]entry
    29  	sliceIdx uint32
    30  	sliceLen uint32
    31  }
    32  
    33  type dataStore struct {
    34  	slices   [][]byte
    35  	sliceIdx uint32
    36  	sliceLen uint32
    37  }
    38  
    39  type entryAddr struct {
    40  	sliceIdx uint32
    41  	offset   uint32
    42  }
    43  
    44  type dataAddr struct {
    45  	sliceIdx uint32
    46  	offset   uint32
    47  }
    48  
    49  const (
    50  	maxDataSliceLen  = 64 * 1024
    51  	maxEntrySliceLen = 8 * 1024
    52  )
    53  
    54  func (ds *dataStore) put(key, value []byte) dataAddr {
    55  	dataLen := uint32(len(key) + len(value))
    56  	if ds.sliceLen != 0 && ds.sliceLen+dataLen > maxDataSliceLen {
    57  		ds.slices = append(ds.slices, make([]byte, 0, max(maxDataSliceLen, int(dataLen))))
    58  		ds.sliceLen = 0
    59  		ds.sliceIdx++
    60  	}
    61  	addr := dataAddr{sliceIdx: ds.sliceIdx, offset: ds.sliceLen}
    62  	slice := ds.slices[ds.sliceIdx]
    63  	slice = append(slice, key...)
    64  	slice = append(slice, value...)
    65  	ds.slices[ds.sliceIdx] = slice
    66  	ds.sliceLen += dataLen
    67  	return addr
    68  }
    69  
    70  func max(a, b int) int {
    71  	if a > b {
    72  		return a
    73  	}
    74  	return b
    75  }
    76  
    77  func (ds *dataStore) get(e entry, key []byte) []byte {
    78  	slice := ds.slices[e.addr.sliceIdx]
    79  	valOffset := e.addr.offset + e.keyLen
    80  	if !bytes.Equal(key, slice[e.addr.offset:valOffset]) {
    81  		return nil
    82  	}
    83  	return slice[valOffset : valOffset+e.valLen]
    84  }
    85  
    86  func (ds *dataStore) getEntryData(e entry) (key, value []byte) {
    87  	slice := ds.slices[e.addr.sliceIdx]
    88  	keyOffset := e.addr.offset
    89  	key = slice[keyOffset : keyOffset+e.keyLen]
    90  	valOffset := e.addr.offset + e.keyLen
    91  	value = slice[valOffset : valOffset+e.valLen]
    92  	return
    93  }
    94  
    95  var nullEntryAddr = entryAddr{}
    96  
    97  func (es *entryStore) put(e entry) entryAddr {
    98  	if es.sliceLen == maxEntrySliceLen {
    99  		es.slices = append(es.slices, make([]entry, 0, maxEntrySliceLen))
   100  		es.sliceLen = 0
   101  		es.sliceIdx++
   102  	}
   103  	addr := entryAddr{sliceIdx: es.sliceIdx, offset: es.sliceLen}
   104  	slice := es.slices[es.sliceIdx]
   105  	slice = append(slice, e)
   106  	es.slices[es.sliceIdx] = slice
   107  	es.sliceLen++
   108  	return addr
   109  }
   110  
   111  func (es *entryStore) get(addr entryAddr) entry {
   112  	return es.slices[addr.sliceIdx][addr.offset]
   113  }
   114  
   115  // MVMap stores multiple value for a given key with minimum GC overhead.
   116  // A given key can causetstore multiple values.
   117  // It is not thread-safe, should only be used in one goroutine.
   118  type MVMap struct {
   119  	entryStore entryStore
   120  	dataStore  dataStore
   121  	hashBlock  map[uint64]entryAddr
   122  	length     int
   123  }
   124  
   125  // NewMVMap creates a new multi-value map.
   126  func NewMVMap() *MVMap {
   127  	m := new(MVMap)
   128  	m.hashBlock = make(map[uint64]entryAddr)
   129  	m.entryStore.slices = [][]entry{make([]entry, 0, 64)}
   130  	// Append the first empty entry, so the zero entryAddr can represent null.
   131  	m.entryStore.put(entry{})
   132  	m.dataStore.slices = [][]byte{make([]byte, 0, 1024)}
   133  	return m
   134  }
   135  
   136  // Put puts the key/value pairs to the MVMap, if the key already exists, old value will not be overwritten,
   137  // values are stored in a list.
   138  func (m *MVMap) Put(key, value []byte) {
   139  	hashKey := fnvHash64(key)
   140  	oldEntryAddr := m.hashBlock[hashKey]
   141  	dataAddr := m.dataStore.put(key, value)
   142  	e := entry{
   143  		addr:   dataAddr,
   144  		keyLen: uint32(len(key)),
   145  		valLen: uint32(len(value)),
   146  		next:   oldEntryAddr,
   147  	}
   148  	newEntryAddr := m.entryStore.put(e)
   149  	m.hashBlock[hashKey] = newEntryAddr
   150  	m.length++
   151  }
   152  
   153  // Get gets the values of the "key" and appends them to "values".
   154  func (m *MVMap) Get(key []byte, values [][]byte) [][]byte {
   155  	hashKey := fnvHash64(key)
   156  	entryAddr := m.hashBlock[hashKey]
   157  	for entryAddr != nullEntryAddr {
   158  		e := m.entryStore.get(entryAddr)
   159  		entryAddr = e.next
   160  		val := m.dataStore.get(e, key)
   161  		if val == nil {
   162  			continue
   163  		}
   164  		values = append(values, val)
   165  	}
   166  	// Keep the order of input.
   167  	for i := 0; i < len(values)/2; i++ {
   168  		j := len(values) - 1 - i
   169  		values[i], values[j] = values[j], values[i]
   170  	}
   171  	return values
   172  }
   173  
   174  // Len returns the number of values in th mv map, the number of keys may be less than Len
   175  // if the same key is put more than once.
   176  func (m *MVMap) Len() int {
   177  	return m.length
   178  }
   179  
   180  // Iterator is used to iterate the MVMap.
   181  type Iterator struct {
   182  	m        *MVMap
   183  	sliceCur int
   184  	entryCur int
   185  }
   186  
   187  // Next returns the next key/value pair of the MVMap.
   188  // It returns (nil, nil) when there is no more entries to iterate.
   189  func (i *Iterator) Next() (key, value []byte) {
   190  	for {
   191  		if i.sliceCur >= len(i.m.entryStore.slices) {
   192  			return nil, nil
   193  		}
   194  		entrySlice := i.m.entryStore.slices[i.sliceCur]
   195  		if i.entryCur >= len(entrySlice) {
   196  			i.sliceCur++
   197  			i.entryCur = 0
   198  			continue
   199  		}
   200  		entry := entrySlice[i.entryCur]
   201  		key, value = i.m.dataStore.getEntryData(entry)
   202  		i.entryCur++
   203  		return
   204  	}
   205  }
   206  
   207  // NewIterator creates a iterator for the MVMap.
   208  func (m *MVMap) NewIterator() *Iterator {
   209  	// The first entry is empty, so init entryCur to 1.
   210  	return &Iterator{m: m, entryCur: 1}
   211  }