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 { |
| 50 | klen uint32 |
| 51 | vlen uint32 |
| 52 | meta byte |
| 53 | userMeta byte |
| 54 | } |
| 55 | |
| 56 | const ( |
| 57 | headerBufSize = 10 |
| 58 | ) |
| 59 | |
| 60 | func (h header) Encode(out []byte) { |
| 61 | y.AssertTrue(len(out) >= headerBufSize) |
| 62 | binary.BigEndian.PutUint32(out[0:4], h.klen) |
| 63 | binary.BigEndian.PutUint32(out[4:8], h.vlen) |
| 64 | out[8] = h.meta |
| 65 | out[9] = h.userMeta |
| 66 | } |
| 67 | |
| 68 | // Decodes h from buf. |
| 69 | func (h *header) Decode(buf []byte) { |
| 70 | h.klen = binary.BigEndian.Uint32(buf[0:4]) |
| 71 | h.vlen = binary.BigEndian.Uint32(buf[4:8]) |
| 72 | h.meta = buf[8] |
| 73 | h.userMeta = buf[9] |
| 74 | } |
| 75 | |
| 76 | // Entry provides Key, Value and if required, CASCounterCheck to kv.BatchSet() API. |
| 77 | // If CASCounterCheck is provided, it would be compared against the current casCounter |
| 78 | // assigned to this key-value. Set be done on this key only if the counters match. |
| 79 | type Entry struct { |
| 80 | Key []byte |
| 81 | Value []byte |
| 82 | Meta byte |
| 83 | UserMeta byte |
| 84 | |
| 85 | // Fields maintained internally. |
| 86 | offset uint32 |
| 87 | } |
| 88 | |
| 89 | func (e *Entry) estimateSize(threshold int) int { |
| 90 | if len(e.Value) < threshold { |
| 91 | return len(e.Key) + len(e.Value) + 2 // Meta, UserMeta |
| 92 | } |
| 93 | return len(e.Key) + 12 + 2 // 12 for ValuePointer, 2 for metas. |
| 94 | } |
| 95 | |
| 96 | // Encodes e to buf. Returns number of bytes written. |
| 97 | func encodeEntry(e *Entry, buf *bytes.Buffer) (int, error) { |
| 98 | var h header |
| 99 | h.klen = uint32(len(e.Key)) |
| 100 | h.vlen = uint32(len(e.Value)) |
| 101 | h.meta = e.Meta |
| 102 | h.userMeta = e.UserMeta |
| 103 | |
| 104 | var headerEnc [headerBufSize]byte |
| 105 | h.Encode(headerEnc[:]) |
| 106 | |
| 107 | hash := crc32.New(y.CastagnoliCrcTable) |
| 108 | |
| 109 | buf.Write(headerEnc[:]) |
| 110 | hash.Write(headerEnc[:]) |
| 111 | |
| 112 | buf.Write(e.Key) |
| 113 | hash.Write(e.Key) |
| 114 | |
| 115 | buf.Write(e.Value) |
| 116 | hash.Write(e.Value) |
| 117 | |
| 118 | var crcBuf [4]byte |
| 119 | binary.BigEndian.PutUint32(crcBuf[:], hash.Sum32()) |
| 120 | buf.Write(crcBuf[:]) |
| 121 | |
| 122 | return len(headerEnc) + len(e.Key) + len(e.Value) + len(crcBuf), nil |
| 123 | } |
| 124 | |
| 125 | func (e Entry) print(prefix string) { |
| 126 | fmt.Printf("%s Key: %s Meta: %d UserMeta: %d Offset: %d len(val)=%d", |
| 127 | prefix, e.Key, e.Meta, e.UserMeta, e.offset, len(e.Value)) |
| 128 | } |