Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 1 | package badger |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "encoding/binary" |
| 6 | "fmt" |
| 7 | "hash/crc32" |
| 8 | |
| 9 | "github.com/dgraph-io/badger/y" |
| 10 | ) |
| 11 | |
| 12 | type valuePointer struct { |
| 13 | Fid uint32 |
| 14 | Len uint32 |
| 15 | Offset uint32 |
| 16 | } |
| 17 | |
| 18 | func (p valuePointer) Less(o valuePointer) bool { |
| 19 | if p.Fid != o.Fid { |
| 20 | return p.Fid < o.Fid |
| 21 | } |
| 22 | if p.Offset != o.Offset { |
| 23 | return p.Offset < o.Offset |
| 24 | } |
| 25 | return p.Len < o.Len |
| 26 | } |
| 27 | |
| 28 | func (p valuePointer) IsZero() bool { |
| 29 | return p.Fid == 0 && p.Offset == 0 && p.Len == 0 |
| 30 | } |
| 31 | |
| 32 | const vptrSize = 12 |
| 33 | |
| 34 | // Encode encodes Pointer into byte buffer. |
| 35 | func (p valuePointer) Encode(b []byte) []byte { |
| 36 | binary.BigEndian.PutUint32(b[:4], p.Fid) |
| 37 | binary.BigEndian.PutUint32(b[4:8], p.Len) |
| 38 | binary.BigEndian.PutUint32(b[8:12], p.Offset) |
| 39 | return b[:vptrSize] |
| 40 | } |
| 41 | |
| 42 | func (p *valuePointer) Decode(b []byte) { |
| 43 | p.Fid = binary.BigEndian.Uint32(b[:4]) |
| 44 | p.Len = binary.BigEndian.Uint32(b[4:8]) |
| 45 | p.Offset = binary.BigEndian.Uint32(b[8:12]) |
| 46 | } |
| 47 | |
| 48 | // header is used in value log as a header before Entry. |
| 49 | type header struct { |
Deepak Jois | a5499e5 | 2017-11-02 02:03:14 | [diff] [blame] | 50 | klen uint32 |
| 51 | vlen uint32 |
| 52 | expiresAt uint64 |
| 53 | meta byte |
| 54 | userMeta byte |
Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 55 | } |
| 56 | |
| 57 | const ( |
Deepak Jois | a5499e5 | 2017-11-02 02:03:14 | [diff] [blame] | 58 | headerBufSize = 18 |
Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 59 | ) |
| 60 | |
| 61 | func (h header) Encode(out []byte) { |
| 62 | y.AssertTrue(len(out) >= headerBufSize) |
| 63 | binary.BigEndian.PutUint32(out[0:4], h.klen) |
| 64 | binary.BigEndian.PutUint32(out[4:8], h.vlen) |
Deepak Jois | a5499e5 | 2017-11-02 02:03:14 | [diff] [blame] | 65 | binary.BigEndian.PutUint64(out[8:16], h.expiresAt) |
| 66 | out[16] = h.meta |
| 67 | out[17] = h.userMeta |
Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | // Decodes h from buf. |
| 71 | func (h *header) Decode(buf []byte) { |
| 72 | h.klen = binary.BigEndian.Uint32(buf[0:4]) |
| 73 | h.vlen = binary.BigEndian.Uint32(buf[4:8]) |
Deepak Jois | a5499e5 | 2017-11-02 02:03:14 | [diff] [blame] | 74 | h.expiresAt = binary.BigEndian.Uint64(buf[8:16]) |
| 75 | h.meta = buf[16] |
| 76 | h.userMeta = buf[17] |
Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 77 | } |
| 78 | |
Deepak Jois | 5bc2e16 | 2017-11-30 03:04:57 | [diff] [blame] | 79 | // Entry provides Key, Value, UserMeta and ExpiresAt. This struct can be used by the user to set data. |
| 80 | type Entry struct { |
Deepak Jois | a5499e5 | 2017-11-02 02:03:14 | [diff] [blame] | 81 | Key []byte |
| 82 | Value []byte |
| 83 | UserMeta byte |
Deepak Jois | 33ae1e8 | 2017-12-05 04:53:05 | [diff] [blame] | 84 | ExpiresAt uint64 // time.Unix |
Deepak Jois | a5499e5 | 2017-11-02 02:03:14 | [diff] [blame] | 85 | meta byte |
Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 86 | |
| 87 | // Fields maintained internally. |
| 88 | offset uint32 |
| 89 | } |
| 90 | |
Deepak Jois | 5bc2e16 | 2017-11-30 03:04:57 | [diff] [blame] | 91 | func (e *Entry) estimateSize(threshold int) int { |
Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 92 | if len(e.Value) < threshold { |
| 93 | return len(e.Key) + len(e.Value) + 2 // Meta, UserMeta |
| 94 | } |
| 95 | return len(e.Key) + 12 + 2 // 12 for ValuePointer, 2 for metas. |
| 96 | } |
| 97 | |
| 98 | // Encodes e to buf. Returns number of bytes written. |
Deepak Jois | 5bc2e16 | 2017-11-30 03:04:57 | [diff] [blame] | 99 | func encodeEntry(e *Entry, buf *bytes.Buffer) (int, error) { |
Deepak Jois | a5499e5 | 2017-11-02 02:03:14 | [diff] [blame] | 100 | h := header{ |
| 101 | klen: uint32(len(e.Key)), |
| 102 | vlen: uint32(len(e.Value)), |
| 103 | expiresAt: e.ExpiresAt, |
| 104 | meta: e.meta, |
| 105 | userMeta: e.UserMeta, |
| 106 | } |
Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 107 | |
| 108 | var headerEnc [headerBufSize]byte |
| 109 | h.Encode(headerEnc[:]) |
| 110 | |
| 111 | hash := crc32.New(y.CastagnoliCrcTable) |
| 112 | |
| 113 | buf.Write(headerEnc[:]) |
| 114 | hash.Write(headerEnc[:]) |
| 115 | |
| 116 | buf.Write(e.Key) |
| 117 | hash.Write(e.Key) |
| 118 | |
| 119 | buf.Write(e.Value) |
| 120 | hash.Write(e.Value) |
| 121 | |
Steven Allen | 5242a99 | 2018-10-04 21:40:52 | [diff] [blame] | 122 | var crcBuf [crc32.Size]byte |
Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 123 | binary.BigEndian.PutUint32(crcBuf[:], hash.Sum32()) |
| 124 | buf.Write(crcBuf[:]) |
| 125 | |
| 126 | return len(headerEnc) + len(e.Key) + len(e.Value) + len(crcBuf), nil |
| 127 | } |
| 128 | |
Deepak Jois | 5bc2e16 | 2017-11-30 03:04:57 | [diff] [blame] | 129 | func (e Entry) print(prefix string) { |
Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 130 | fmt.Printf("%s Key: %s Meta: %d UserMeta: %d Offset: %d len(val)=%d", |
Deepak Jois | a5499e5 | 2017-11-02 02:03:14 | [diff] [blame] | 131 | prefix, e.Key, e.meta, e.UserMeta, e.offset, len(e.Value)) |
Manish R Jain | ffd14f0 | 2017-09-28 08:54:33 | [diff] [blame] | 132 | } |