| package badger |
| |
| import ( |
| "bytes" |
| "encoding/binary" |
| "fmt" |
| "hash/crc32" |
| |
| "github.com/dgraph-io/badger/y" |
| ) |
| |
| type valuePointer struct { |
| Fid uint32 |
| Len uint32 |
| Offset uint32 |
| } |
| |
| func (p valuePointer) Less(o valuePointer) bool { |
| if p.Fid != o.Fid { |
| return p.Fid < o.Fid |
| } |
| if p.Offset != o.Offset { |
| return p.Offset < o.Offset |
| } |
| return p.Len < o.Len |
| } |
| |
| func (p valuePointer) IsZero() bool { |
| return p.Fid == 0 && p.Offset == 0 && p.Len == 0 |
| } |
| |
| const vptrSize = 12 |
| |
| // Encode encodes Pointer into byte buffer. |
| func (p valuePointer) Encode(b []byte) []byte { |
| binary.BigEndian.PutUint32(b[:4], p.Fid) |
| binary.BigEndian.PutUint32(b[4:8], p.Len) |
| binary.BigEndian.PutUint32(b[8:12], p.Offset) |
| return b[:vptrSize] |
| } |
| |
| func (p *valuePointer) Decode(b []byte) { |
| p.Fid = binary.BigEndian.Uint32(b[:4]) |
| p.Len = binary.BigEndian.Uint32(b[4:8]) |
| p.Offset = binary.BigEndian.Uint32(b[8:12]) |
| } |
| |
| // header is used in value log as a header before Entry. |
| type header struct { |
| klen uint32 |
| vlen uint32 |
| expiresAt uint64 |
| meta byte |
| userMeta byte |
| } |
| |
| const ( |
| headerBufSize = 18 |
| ) |
| |
| func (h header) Encode(out []byte) { |
| y.AssertTrue(len(out) >= headerBufSize) |
| binary.BigEndian.PutUint32(out[0:4], h.klen) |
| binary.BigEndian.PutUint32(out[4:8], h.vlen) |
| binary.BigEndian.PutUint64(out[8:16], h.expiresAt) |
| out[16] = h.meta |
| out[17] = h.userMeta |
| } |
| |
| // Decodes h from buf. |
| func (h *header) Decode(buf []byte) { |
| h.klen = binary.BigEndian.Uint32(buf[0:4]) |
| h.vlen = binary.BigEndian.Uint32(buf[4:8]) |
| h.expiresAt = binary.BigEndian.Uint64(buf[8:16]) |
| h.meta = buf[16] |
| h.userMeta = buf[17] |
| } |
| |
| // Entry provides Key, Value, UserMeta and ExpiresAt. This struct can be used by the user to set data. |
| type Entry struct { |
| Key []byte |
| Value []byte |
| UserMeta byte |
| ExpiresAt uint64 // time.Unix |
| meta byte |
| |
| // Fields maintained internally. |
| offset uint32 |
| } |
| |
| func (e *Entry) estimateSize(threshold int) int { |
| if len(e.Value) < threshold { |
| return len(e.Key) + len(e.Value) + 2 // Meta, UserMeta |
| } |
| return len(e.Key) + 12 + 2 // 12 for ValuePointer, 2 for metas. |
| } |
| |
| // Encodes e to buf. Returns number of bytes written. |
| func encodeEntry(e *Entry, buf *bytes.Buffer) (int, error) { |
| h := header{ |
| klen: uint32(len(e.Key)), |
| vlen: uint32(len(e.Value)), |
| expiresAt: e.ExpiresAt, |
| meta: e.meta, |
| userMeta: e.UserMeta, |
| } |
| |
| var headerEnc [headerBufSize]byte |
| h.Encode(headerEnc[:]) |
| |
| hash := crc32.New(y.CastagnoliCrcTable) |
| |
| buf.Write(headerEnc[:]) |
| hash.Write(headerEnc[:]) |
| |
| buf.Write(e.Key) |
| hash.Write(e.Key) |
| |
| buf.Write(e.Value) |
| hash.Write(e.Value) |
| |
| var crcBuf [crc32.Size]byte |
| binary.BigEndian.PutUint32(crcBuf[:], hash.Sum32()) |
| buf.Write(crcBuf[:]) |
| |
| return len(headerEnc) + len(e.Key) + len(e.Value) + len(crcBuf), nil |
| } |
| |
| func (e Entry) print(prefix string) { |
| fmt.Printf("%s Key: %s Meta: %d UserMeta: %d Offset: %d len(val)=%d", |
| prefix, e.Key, e.meta, e.UserMeta, e.offset, len(e.Value)) |
| } |