github.com/nutsdb/nutsdb@v1.0.4/entry.go (about)

     1  // Copyright 2019 The nutsdb Author. All rights reserved.
     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 nutsdb
    16  
    17  import (
    18  	"encoding/binary"
    19  	"errors"
    20  	"hash/crc32"
    21  	"sort"
    22  	"strings"
    23  
    24  	"github.com/xujiajun/utils/strconv2"
    25  )
    26  
    27  var (
    28  	ErrPayLoadSizeMismatch   = errors.New("the payload size in Meta mismatch with the payload size needed")
    29  	ErrHeaderSizeOutOfBounds = errors.New("the header size is out of bounds")
    30  )
    31  
    32  const (
    33  	MaxEntryHeaderSize = 4 + binary.MaxVarintLen32*3 + binary.MaxVarintLen64*3 + binary.MaxVarintLen16*3
    34  	MinEntryHeaderSize = 4 + 9
    35  )
    36  
    37  type (
    38  	// Entry represents the data item.
    39  	Entry struct {
    40  		Key   []byte
    41  		Value []byte
    42  		Meta  *MetaData
    43  	}
    44  )
    45  
    46  // Size returns the size of the entry.
    47  func (e *Entry) Size() int64 {
    48  	return e.Meta.Size() + int64(e.Meta.KeySize+e.Meta.ValueSize)
    49  }
    50  
    51  // Encode returns the slice after the entry be encoded.
    52  //
    53  //	the entry stored format:
    54  //	|----------------------------------------------------------------------------------------------------------|
    55  //	|  crc  | timestamp | ksz | valueSize | flag  | TTL  | status | ds   | txId |  bucketId |  key  | value    |
    56  //	|----------------------------------------------------------------------------------------------------------|
    57  //	| uint32| uint64  |uint32 |  uint32 | uint16  | uint32| uint16 | uint16 |uint64 | uint64 | []byte | []byte |
    58  //	|----------------------------------------------------------------------------------------------------------|
    59  func (e *Entry) Encode() []byte {
    60  	keySize := e.Meta.KeySize
    61  	valueSize := e.Meta.ValueSize
    62  
    63  	buf := make([]byte, MaxEntryHeaderSize+keySize+valueSize)
    64  
    65  	index := e.setEntryHeaderBuf(buf)
    66  	copy(buf[index:], e.Key)
    67  	index += int(keySize)
    68  	copy(buf[index:], e.Value)
    69  	index += int(valueSize)
    70  
    71  	buf = buf[:index]
    72  
    73  	c32 := crc32.ChecksumIEEE(buf[4:])
    74  	binary.LittleEndian.PutUint32(buf[0:4], c32)
    75  
    76  	return buf
    77  }
    78  
    79  // setEntryHeaderBuf sets the entry header buff.
    80  func (e *Entry) setEntryHeaderBuf(buf []byte) int {
    81  	index := 4
    82  
    83  	index += binary.PutUvarint(buf[index:], e.Meta.Timestamp)
    84  	index += binary.PutUvarint(buf[index:], uint64(e.Meta.KeySize))
    85  	index += binary.PutUvarint(buf[index:], uint64(e.Meta.ValueSize))
    86  	index += binary.PutUvarint(buf[index:], uint64(e.Meta.Flag))
    87  	index += binary.PutUvarint(buf[index:], uint64(e.Meta.TTL))
    88  	index += binary.PutUvarint(buf[index:], uint64(e.Meta.Status))
    89  	index += binary.PutUvarint(buf[index:], uint64(e.Meta.Ds))
    90  	index += binary.PutUvarint(buf[index:], e.Meta.TxID)
    91  	index += binary.PutUvarint(buf[index:], e.Meta.BucketId)
    92  
    93  	return index
    94  }
    95  
    96  // IsZero checks if the entry is zero or not.
    97  func (e *Entry) IsZero() bool {
    98  	if e.Meta.Crc == 0 && e.Meta.KeySize == 0 && e.Meta.ValueSize == 0 && e.Meta.Timestamp == 0 {
    99  		return true
   100  	}
   101  	return false
   102  }
   103  
   104  // GetCrc returns the crc at given buf slice.
   105  func (e *Entry) GetCrc(buf []byte) uint32 {
   106  	crc := crc32.ChecksumIEEE(buf[4:])
   107  	crc = crc32.Update(crc, crc32.IEEETable, e.Key)
   108  	crc = crc32.Update(crc, crc32.IEEETable, e.Value)
   109  
   110  	return crc
   111  }
   112  
   113  // ParsePayload means this function will parse a byte array to bucket, key, size of an entry
   114  func (e *Entry) ParsePayload(data []byte) error {
   115  	meta := e.Meta
   116  	keyLowBound := 0
   117  	keyHighBound := meta.KeySize
   118  	valueLowBound := keyHighBound
   119  	valueHighBound := meta.KeySize + meta.ValueSize
   120  
   121  	// parse key
   122  	e.Key = data[keyLowBound:keyHighBound]
   123  	// parse value
   124  	e.Value = data[valueLowBound:valueHighBound]
   125  	return nil
   126  }
   127  
   128  // checkPayloadSize checks the payload size
   129  func (e *Entry) checkPayloadSize(size int64) error {
   130  	if e.Meta.PayloadSize() != size {
   131  		return ErrPayLoadSizeMismatch
   132  	}
   133  	return nil
   134  }
   135  
   136  // ParseMeta parse Meta object to entry
   137  func (e *Entry) ParseMeta(buf []byte) (int64, error) {
   138  	// If the length of the header is less than MinEntryHeaderSize,
   139  	// it means that the final remaining capacity of the file is not enough to write a record,
   140  	// and an error needs to be returned.
   141  	if len(buf) < MinEntryHeaderSize {
   142  		return 0, ErrHeaderSizeOutOfBounds
   143  	}
   144  
   145  	e.Meta = NewMetaData()
   146  
   147  	e.Meta.WithCrc(binary.LittleEndian.Uint32(buf[0:4]))
   148  
   149  	index := 4
   150  
   151  	timestamp, n := binary.Uvarint(buf[index:])
   152  	index += n
   153  	keySize, n := binary.Uvarint(buf[index:])
   154  	index += n
   155  	valueSize, n := binary.Uvarint(buf[index:])
   156  	index += n
   157  	flag, n := binary.Uvarint(buf[index:])
   158  	index += n
   159  	ttl, n := binary.Uvarint(buf[index:])
   160  	index += n
   161  	status, n := binary.Uvarint(buf[index:])
   162  	index += n
   163  	ds, n := binary.Uvarint(buf[index:])
   164  	index += n
   165  	txId, n := binary.Uvarint(buf[index:])
   166  	index += n
   167  	bucketId, n := binary.Uvarint(buf[index:])
   168  	index += n
   169  
   170  	e.Meta.
   171  		WithTimeStamp(timestamp).
   172  		WithKeySize(uint32(keySize)).
   173  		WithValueSize(uint32(valueSize)).
   174  		WithFlag(uint16(flag)).
   175  		WithTTL(uint32(ttl)).
   176  		WithStatus(uint16(status)).
   177  		WithDs(uint16(ds)).
   178  		WithTxID(txId).
   179  		WithBucketId(bucketId)
   180  
   181  	return int64(index), nil
   182  }
   183  
   184  // isFilter to confirm if this entry is can be filtered
   185  func (e *Entry) isFilter() bool {
   186  	meta := e.Meta
   187  	var filterDataSet = []uint16{
   188  		DataDeleteFlag,
   189  		DataRPopFlag,
   190  		DataLPopFlag,
   191  		DataLRemFlag,
   192  		DataLTrimFlag,
   193  		DataZRemFlag,
   194  		DataZRemRangeByRankFlag,
   195  		DataZPopMaxFlag,
   196  		DataZPopMinFlag,
   197  		DataLRemByIndex,
   198  	}
   199  	return OneOfUint16Array(meta.Flag, filterDataSet)
   200  }
   201  
   202  // valid check the entry fields valid or not
   203  func (e *Entry) valid() error {
   204  	if len(e.Key) == 0 {
   205  		return ErrKeyEmpty
   206  	}
   207  	if len(e.Key) > MAX_SIZE || len(e.Value) > MAX_SIZE {
   208  		return ErrDataSizeExceed
   209  	}
   210  	return nil
   211  }
   212  
   213  // NewEntry new Entry Object
   214  func NewEntry() *Entry {
   215  	return new(Entry)
   216  }
   217  
   218  // WithKey set key to Entry
   219  func (e *Entry) WithKey(key []byte) *Entry {
   220  	e.Key = key
   221  	return e
   222  }
   223  
   224  // WithValue set value to Entry
   225  func (e *Entry) WithValue(value []byte) *Entry {
   226  	e.Value = value
   227  	return e
   228  }
   229  
   230  // WithMeta set Meta to Entry
   231  func (e *Entry) WithMeta(meta *MetaData) *Entry {
   232  	e.Meta = meta
   233  	return e
   234  }
   235  
   236  // GetTxIDBytes return the bytes of TxID
   237  func (e *Entry) GetTxIDBytes() []byte {
   238  	return []byte(strconv2.Int64ToStr(int64(e.Meta.TxID)))
   239  }
   240  
   241  func (e *Entry) IsBelongsToBPlusTree() bool {
   242  	return e.Meta.IsBPlusTree()
   243  }
   244  
   245  func (e *Entry) IsBelongsToList() bool {
   246  	return e.Meta.IsList()
   247  }
   248  
   249  func (e *Entry) IsBelongsToSet() bool {
   250  	return e.Meta.IsSet()
   251  }
   252  
   253  func (e *Entry) IsBelongsToSortSet() bool {
   254  	return e.Meta.IsSortSet()
   255  }
   256  
   257  // Entries represents entries
   258  type Entries []*Entry
   259  
   260  func (e Entries) Len() int { return len(e) }
   261  
   262  func (e Entries) Less(i, j int) bool {
   263  	l := string(e[i].Key)
   264  	r := string(e[j].Key)
   265  
   266  	return strings.Compare(l, r) == -1
   267  }
   268  
   269  func (e Entries) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
   270  
   271  func (e Entries) processEntriesScanOnDisk() (result []*Entry) {
   272  	sort.Sort(e)
   273  	for _, ele := range e {
   274  		curE := ele
   275  		if !IsExpired(curE.Meta.TTL, curE.Meta.Timestamp) && curE.Meta.Flag != DataDeleteFlag {
   276  			result = append(result, curE)
   277  		}
   278  	}
   279  
   280  	return result
   281  }
   282  
   283  func (e Entries) ToCEntries(lFunc func(l, r string) bool) CEntries {
   284  	return CEntries{
   285  		Entries:  e,
   286  		LessFunc: lFunc,
   287  	}
   288  }
   289  
   290  type CEntries struct {
   291  	Entries
   292  	LessFunc func(l, r string) bool
   293  }
   294  
   295  func (c CEntries) Len() int { return len(c.Entries) }
   296  
   297  func (c CEntries) Less(i, j int) bool {
   298  	l := string(c.Entries[i].Key)
   299  	r := string(c.Entries[j].Key)
   300  	if c.LessFunc != nil {
   301  		return c.LessFunc(l, r)
   302  	}
   303  
   304  	return c.Entries.Less(i, j)
   305  }
   306  
   307  func (c CEntries) Swap(i, j int) { c.Entries[i], c.Entries[j] = c.Entries[j], c.Entries[i] }
   308  
   309  func (c CEntries) processEntriesScanOnDisk() (result []*Entry) {
   310  	sort.Sort(c)
   311  	for _, ele := range c.Entries {
   312  		curE := ele
   313  		if !IsExpired(curE.Meta.TTL, curE.Meta.Timestamp) && curE.Meta.Flag != DataDeleteFlag {
   314  			result = append(result, curE)
   315  		}
   316  	}
   317  
   318  	return result
   319  }
   320  
   321  type EntryWhenRecovery struct {
   322  	Entry
   323  	fid int64
   324  	off int64
   325  }
   326  
   327  type dataInTx struct {
   328  	es       []*EntryWhenRecovery
   329  	txId     uint64
   330  	startOff int64
   331  }
   332  
   333  func (dt *dataInTx) isSameTx(e *EntryWhenRecovery) bool {
   334  	return dt.txId == e.Meta.TxID
   335  }
   336  
   337  func (dt *dataInTx) appendEntry(e *EntryWhenRecovery) {
   338  	dt.es = append(dt.es, e)
   339  }
   340  
   341  func (dt *dataInTx) reset() {
   342  	dt.es = make([]*EntryWhenRecovery, 0)
   343  	dt.txId = 0
   344  }