github.com/flower-corp/rosedb@v1.1.2-0.20230117132829-21dc4f7b319a/logfile/log_entry.go (about)

     1  package logfile
     2  
     3  import (
     4  	"encoding/binary"
     5  	"hash/crc32"
     6  )
     7  
     8  // MaxHeaderSize max entry header size.
     9  // crc32	typ    kSize	vSize	expiredAt
    10  //  4    +   1   +   5   +   5    +    10      = 25 (refer to binary.MaxVarintLen32 and binary.MaxVarintLen64)
    11  const MaxHeaderSize = 25
    12  
    13  // EntryType type of Entry.
    14  type EntryType byte
    15  
    16  const (
    17  	// TypeDelete represents entry type is delete.
    18  	TypeDelete EntryType = iota + 1
    19  	// TypeListMeta represents entry is list meta.
    20  	TypeListMeta
    21  )
    22  
    23  // LogEntry is the data will be appended in log file.
    24  type LogEntry struct {
    25  	Key       []byte
    26  	Value     []byte
    27  	ExpiredAt int64 // time.Unix
    28  	Type      EntryType
    29  }
    30  
    31  type entryHeader struct {
    32  	crc32     uint32 // check sum
    33  	typ       EntryType
    34  	kSize     uint32
    35  	vSize     uint32
    36  	expiredAt int64 // time.Unix
    37  }
    38  
    39  // EncodeEntry will encode entry into a byte slice.
    40  // The encoded Entry looks like:
    41  // +-------+--------+----------+------------+-----------+-------+---------+
    42  // |  crc  |  type  | key size | value size | expiresAt |  key  |  value  |
    43  // +-------+--------+----------+------------+-----------+-------+---------+
    44  // |------------------------HEADER----------------------|
    45  //         |--------------------------crc check---------------------------|
    46  func EncodeEntry(e *LogEntry) ([]byte, int) {
    47  	if e == nil {
    48  		return nil, 0
    49  	}
    50  	header := make([]byte, MaxHeaderSize)
    51  	// encode header.
    52  	header[4] = byte(e.Type)
    53  	var index = 5
    54  	index += binary.PutVarint(header[index:], int64(len(e.Key)))
    55  	index += binary.PutVarint(header[index:], int64(len(e.Value)))
    56  	index += binary.PutVarint(header[index:], e.ExpiredAt)
    57  
    58  	var size = index + len(e.Key) + len(e.Value)
    59  	buf := make([]byte, size)
    60  	copy(buf[:index], header[:])
    61  	// key and value.
    62  	copy(buf[index:], e.Key)
    63  	copy(buf[index+len(e.Key):], e.Value)
    64  
    65  	// crc32.
    66  	crc := crc32.ChecksumIEEE(buf[4:])
    67  	binary.LittleEndian.PutUint32(buf[:4], crc)
    68  	return buf, size
    69  }
    70  
    71  func decodeHeader(buf []byte) (*entryHeader, int64) {
    72  	if len(buf) <= 4 {
    73  		return nil, 0
    74  	}
    75  	h := &entryHeader{
    76  		crc32: binary.LittleEndian.Uint32(buf[:4]),
    77  		typ:   EntryType(buf[4]),
    78  	}
    79  	var index = 5
    80  	ksize, n := binary.Varint(buf[index:])
    81  	h.kSize = uint32(ksize)
    82  	index += n
    83  
    84  	vsize, n := binary.Varint(buf[index:])
    85  	h.vSize = uint32(vsize)
    86  	index += n
    87  
    88  	expiredAt, n := binary.Varint(buf[index:])
    89  	h.expiredAt = expiredAt
    90  	return h, int64(index + n)
    91  }
    92  
    93  func getEntryCrc(e *LogEntry, h []byte) uint32 {
    94  	if e == nil {
    95  		return 0
    96  	}
    97  	crc := crc32.ChecksumIEEE(h[:])
    98  	crc = crc32.Update(crc, crc32.IEEETable, e.Key)
    99  	crc = crc32.Update(crc, crc32.IEEETable, e.Value)
   100  	return crc
   101  }