mirror of
https://github.com/luxfi/zapdb.git
synced 2026-10-30 15:12:20 +00:00
As explained in https://discuss.dgraph.io/t/go-modules-on-badger-and-dgraph/4662, Go Modules force an import path rename that currently breaks support for most other dependency management systems, including dep. It seems an effort is being made to add support for this import path renaming by patching the go tool itself, but until the community hasn't settled and Go Modules is an easier option to adopt, we are simply not supporting them. For those willing to use badger v2 from Go modules it is still very simple, you might notice that once you set the version to be v2.0.0 a +incompatible will be added to it indicating the dependency has not opted-in into Go Modules. That's normal and not to be a concern.
187 lines
4.9 KiB
Go
187 lines
4.9 KiB
Go
package badger
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"hash/crc32"
|
|
"time"
|
|
|
|
"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
|
|
skipVlog bool
|
|
}
|
|
|
|
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[:])
|
|
if _, err := hash.Write(headerEnc[:]); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
buf.Write(e.Key)
|
|
if _, err := hash.Write(e.Key); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
buf.Write(e.Value)
|
|
if _, err := hash.Write(e.Value); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
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))
|
|
}
|
|
|
|
// NewEntry creates a new entry with key and value passed in args. This newly created entry can be
|
|
// set in a transaction by calling txn.SetEntry(). All other properties of Entry can be set by
|
|
// calling WithMeta, WithDiscard, WithTTL methods on it.
|
|
// This function uses key and value reference, hence users must
|
|
// not modify key and value until the end of transaction.
|
|
func NewEntry(key, value []byte) *Entry {
|
|
return &Entry{
|
|
Key: key,
|
|
Value: value,
|
|
}
|
|
}
|
|
|
|
// WithMeta adds meta data to Entry e. This byte is stored alongside the key
|
|
// and can be used as an aid to interpret the value or store other contextual
|
|
// bits corresponding to the key-value pair of entry.
|
|
func (e *Entry) WithMeta(meta byte) *Entry {
|
|
e.UserMeta = meta
|
|
return e
|
|
}
|
|
|
|
// WithDiscard adds a marker to Entry e. This means all the previous versions of the key (of the
|
|
// Entry) will be eligible for garbage collection.
|
|
// This method is only useful if you have set a higher limit for options.NumVersionsToKeep. The
|
|
// default setting is 1, in which case, this function doesn't add any more benefit. If however, you
|
|
// have a higher setting for NumVersionsToKeep (in Dgraph, we set it to infinity), you can use this
|
|
// method to indicate that all the older versions can be discarded and removed during compactions.
|
|
func (e *Entry) WithDiscard() *Entry {
|
|
e.meta = bitDiscardEarlierVersions
|
|
return e
|
|
}
|
|
|
|
// WithTTL adds time to live duration to Entry e. Entry stored with a TTL would automatically expire
|
|
// after the time has elapsed, and will be eligible for garbage collection.
|
|
func (e *Entry) WithTTL(dur time.Duration) *Entry {
|
|
e.ExpiresAt = uint64(time.Now().Add(dur).Unix())
|
|
return e
|
|
}
|
|
|
|
// withMergeBit sets merge bit in entry's metadata. This
|
|
// function is called by MergeOperator's Add method.
|
|
func (e *Entry) withMergeBit() *Entry {
|
|
e.meta = bitMergeEntry
|
|
return e
|
|
}
|