You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
2.9 KiB
132 lines
2.9 KiB
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 [4]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)) |
|
}
|
|
|