Initial commit
This commit is contained in:
506
vendor/github.com/cockroachdb/pebble/internal/base/internal.go
generated
vendored
Normal file
506
vendor/github.com/cockroachdb/pebble/internal/base/internal.go
generated
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
// Copyright 2011 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
||||
// of this source code is governed by a BSD-style license that can be found in
|
||||
// the LICENSE file.
|
||||
|
||||
package base // import "github.com/cockroachdb/pebble/internal/base"
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/redact"
|
||||
)
|
||||
|
||||
const (
|
||||
// SeqNumZero is the zero sequence number, set by compactions if they can
|
||||
// guarantee there are no keys underneath an internal key.
|
||||
SeqNumZero = uint64(0)
|
||||
// SeqNumStart is the first sequence number assigned to a key. Sequence
|
||||
// numbers 1-9 are reserved for potential future use.
|
||||
SeqNumStart = uint64(10)
|
||||
)
|
||||
|
||||
// InternalKeyKind enumerates the kind of key: a deletion tombstone, a set
|
||||
// value, a merged value, etc.
|
||||
type InternalKeyKind uint8
|
||||
|
||||
// These constants are part of the file format, and should not be changed.
|
||||
const (
|
||||
InternalKeyKindDelete InternalKeyKind = 0
|
||||
InternalKeyKindSet InternalKeyKind = 1
|
||||
InternalKeyKindMerge InternalKeyKind = 2
|
||||
InternalKeyKindLogData InternalKeyKind = 3
|
||||
//InternalKeyKindColumnFamilyDeletion InternalKeyKind = 4
|
||||
//InternalKeyKindColumnFamilyValue InternalKeyKind = 5
|
||||
//InternalKeyKindColumnFamilyMerge InternalKeyKind = 6
|
||||
|
||||
// InternalKeyKindSingleDelete (SINGLEDEL) is a performance optimization
|
||||
// solely for compactions (to reduce write amp and space amp). Readers other
|
||||
// than compactions should treat SINGLEDEL as equivalent to a DEL.
|
||||
// Historically, it was simpler for readers other than compactions to treat
|
||||
// SINGLEDEL as equivalent to DEL, but as of the introduction of
|
||||
// InternalKeyKindSSTableInternalObsoleteBit, this is also necessary for
|
||||
// correctness.
|
||||
InternalKeyKindSingleDelete InternalKeyKind = 7
|
||||
//InternalKeyKindColumnFamilySingleDelete InternalKeyKind = 8
|
||||
//InternalKeyKindBeginPrepareXID InternalKeyKind = 9
|
||||
//InternalKeyKindEndPrepareXID InternalKeyKind = 10
|
||||
//InternalKeyKindCommitXID InternalKeyKind = 11
|
||||
//InternalKeyKindRollbackXID InternalKeyKind = 12
|
||||
//InternalKeyKindNoop InternalKeyKind = 13
|
||||
//InternalKeyKindColumnFamilyRangeDelete InternalKeyKind = 14
|
||||
InternalKeyKindRangeDelete InternalKeyKind = 15
|
||||
//InternalKeyKindColumnFamilyBlobIndex InternalKeyKind = 16
|
||||
//InternalKeyKindBlobIndex InternalKeyKind = 17
|
||||
|
||||
// InternalKeyKindSeparator is a key used for separator / successor keys
|
||||
// written to sstable block indexes.
|
||||
//
|
||||
// NOTE: the RocksDB value has been repurposed. This was done to ensure that
|
||||
// keys written to block indexes with value "17" (when 17 happened to be the
|
||||
// max value, and InternalKeyKindMax was therefore set to 17), remain stable
|
||||
// when new key kinds are supported in Pebble.
|
||||
InternalKeyKindSeparator InternalKeyKind = 17
|
||||
|
||||
// InternalKeyKindSetWithDelete keys are SET keys that have met with a
|
||||
// DELETE or SINGLEDEL key in a prior compaction. This key kind is
|
||||
// specific to Pebble. See
|
||||
// https://github.com/cockroachdb/pebble/issues/1255.
|
||||
InternalKeyKindSetWithDelete InternalKeyKind = 18
|
||||
|
||||
// InternalKeyKindRangeKeyDelete removes all range keys within a key range.
|
||||
// See the internal/rangekey package for more details.
|
||||
InternalKeyKindRangeKeyDelete InternalKeyKind = 19
|
||||
// InternalKeyKindRangeKeySet and InternalKeyKindRangeUnset represent
|
||||
// keys that set and unset values associated with ranges of key
|
||||
// space. See the internal/rangekey package for more details.
|
||||
InternalKeyKindRangeKeyUnset InternalKeyKind = 20
|
||||
InternalKeyKindRangeKeySet InternalKeyKind = 21
|
||||
|
||||
// InternalKeyKindIngestSST is used to distinguish a batch that corresponds to
|
||||
// the WAL entry for ingested sstables that are added to the flushable
|
||||
// queue. This InternalKeyKind cannot appear, amongst other key kinds in a
|
||||
// batch, or in an sstable.
|
||||
InternalKeyKindIngestSST InternalKeyKind = 22
|
||||
|
||||
// InternalKeyKindDeleteSized keys behave identically to
|
||||
// InternalKeyKindDelete keys, except that they hold an associated uint64
|
||||
// value indicating the (len(key)+len(value)) of the shadowed entry the
|
||||
// tombstone is expected to delete. This value is used to inform compaction
|
||||
// heuristics, but is not required to be accurate for correctness.
|
||||
InternalKeyKindDeleteSized InternalKeyKind = 23
|
||||
|
||||
// This maximum value isn't part of the file format. Future extensions may
|
||||
// increase this value.
|
||||
//
|
||||
// When constructing an internal key to pass to DB.Seek{GE,LE},
|
||||
// internalKeyComparer sorts decreasing by kind (after sorting increasing by
|
||||
// user key and decreasing by sequence number). Thus, use InternalKeyKindMax,
|
||||
// which sorts 'less than or equal to' any other valid internalKeyKind, when
|
||||
// searching for any kind of internal key formed by a certain user key and
|
||||
// seqNum.
|
||||
InternalKeyKindMax InternalKeyKind = 23
|
||||
|
||||
// Internal to the sstable format. Not exposed by any sstable iterator.
|
||||
// Declared here to prevent definition of valid key kinds that set this bit.
|
||||
InternalKeyKindSSTableInternalObsoleteBit InternalKeyKind = 64
|
||||
InternalKeyKindSSTableInternalObsoleteMask InternalKeyKind = 191
|
||||
|
||||
// InternalKeyZeroSeqnumMaxTrailer is the largest trailer with a
|
||||
// zero sequence number.
|
||||
InternalKeyZeroSeqnumMaxTrailer = uint64(255)
|
||||
|
||||
// A marker for an invalid key.
|
||||
InternalKeyKindInvalid InternalKeyKind = InternalKeyKindSSTableInternalObsoleteMask
|
||||
|
||||
// InternalKeySeqNumBatch is a bit that is set on batch sequence numbers
|
||||
// which prevents those entries from being excluded from iteration.
|
||||
InternalKeySeqNumBatch = uint64(1 << 55)
|
||||
|
||||
// InternalKeySeqNumMax is the largest valid sequence number.
|
||||
InternalKeySeqNumMax = uint64(1<<56 - 1)
|
||||
|
||||
// InternalKeyRangeDeleteSentinel is the marker for a range delete sentinel
|
||||
// key. This sequence number and kind are used for the upper stable boundary
|
||||
// when a range deletion tombstone is the largest key in an sstable. This is
|
||||
// necessary because sstable boundaries are inclusive, while the end key of a
|
||||
// range deletion tombstone is exclusive.
|
||||
InternalKeyRangeDeleteSentinel = (InternalKeySeqNumMax << 8) | uint64(InternalKeyKindRangeDelete)
|
||||
|
||||
// InternalKeyBoundaryRangeKey is the marker for a range key boundary. This
|
||||
// sequence number and kind are used during interleaved range key and point
|
||||
// iteration to allow an iterator to stop at range key start keys where
|
||||
// there exists no point key.
|
||||
InternalKeyBoundaryRangeKey = (InternalKeySeqNumMax << 8) | uint64(InternalKeyKindRangeKeySet)
|
||||
)
|
||||
|
||||
// Assert InternalKeyKindSSTableInternalObsoleteBit > InternalKeyKindMax
|
||||
const _ = uint(InternalKeyKindSSTableInternalObsoleteBit - InternalKeyKindMax - 1)
|
||||
|
||||
var internalKeyKindNames = []string{
|
||||
InternalKeyKindDelete: "DEL",
|
||||
InternalKeyKindSet: "SET",
|
||||
InternalKeyKindMerge: "MERGE",
|
||||
InternalKeyKindLogData: "LOGDATA",
|
||||
InternalKeyKindSingleDelete: "SINGLEDEL",
|
||||
InternalKeyKindRangeDelete: "RANGEDEL",
|
||||
InternalKeyKindSeparator: "SEPARATOR",
|
||||
InternalKeyKindSetWithDelete: "SETWITHDEL",
|
||||
InternalKeyKindRangeKeySet: "RANGEKEYSET",
|
||||
InternalKeyKindRangeKeyUnset: "RANGEKEYUNSET",
|
||||
InternalKeyKindRangeKeyDelete: "RANGEKEYDEL",
|
||||
InternalKeyKindIngestSST: "INGESTSST",
|
||||
InternalKeyKindDeleteSized: "DELSIZED",
|
||||
InternalKeyKindInvalid: "INVALID",
|
||||
}
|
||||
|
||||
func (k InternalKeyKind) String() string {
|
||||
if int(k) < len(internalKeyKindNames) {
|
||||
return internalKeyKindNames[k]
|
||||
}
|
||||
return fmt.Sprintf("UNKNOWN:%d", k)
|
||||
}
|
||||
|
||||
// SafeFormat implements redact.SafeFormatter.
|
||||
func (k InternalKeyKind) SafeFormat(w redact.SafePrinter, _ rune) {
|
||||
w.Print(redact.SafeString(k.String()))
|
||||
}
|
||||
|
||||
// InternalKey is a key used for the in-memory and on-disk partial DBs that
|
||||
// make up a pebble DB.
|
||||
//
|
||||
// It consists of the user key (as given by the code that uses package pebble)
|
||||
// followed by 8-bytes of metadata:
|
||||
// - 1 byte for the type of internal key: delete or set,
|
||||
// - 7 bytes for a uint56 sequence number, in little-endian format.
|
||||
type InternalKey struct {
|
||||
UserKey []byte
|
||||
Trailer uint64
|
||||
}
|
||||
|
||||
// InvalidInternalKey is an invalid internal key for which Valid() will return
|
||||
// false.
|
||||
var InvalidInternalKey = MakeInternalKey(nil, 0, InternalKeyKindInvalid)
|
||||
|
||||
// MakeInternalKey constructs an internal key from a specified user key,
|
||||
// sequence number and kind.
|
||||
func MakeInternalKey(userKey []byte, seqNum uint64, kind InternalKeyKind) InternalKey {
|
||||
return InternalKey{
|
||||
UserKey: userKey,
|
||||
Trailer: (seqNum << 8) | uint64(kind),
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTrailer constructs an internal key trailer from the specified sequence
|
||||
// number and kind.
|
||||
func MakeTrailer(seqNum uint64, kind InternalKeyKind) uint64 {
|
||||
return (seqNum << 8) | uint64(kind)
|
||||
}
|
||||
|
||||
// MakeSearchKey constructs an internal key that is appropriate for searching
|
||||
// for a the specified user key. The search key contain the maximal sequence
|
||||
// number and kind ensuring that it sorts before any other internal keys for
|
||||
// the same user key.
|
||||
func MakeSearchKey(userKey []byte) InternalKey {
|
||||
return InternalKey{
|
||||
UserKey: userKey,
|
||||
Trailer: (InternalKeySeqNumMax << 8) | uint64(InternalKeyKindMax),
|
||||
}
|
||||
}
|
||||
|
||||
// MakeRangeDeleteSentinelKey constructs an internal key that is a range
|
||||
// deletion sentinel key, used as the upper boundary for an sstable when a
|
||||
// range deletion is the largest key in an sstable.
|
||||
func MakeRangeDeleteSentinelKey(userKey []byte) InternalKey {
|
||||
return InternalKey{
|
||||
UserKey: userKey,
|
||||
Trailer: InternalKeyRangeDeleteSentinel,
|
||||
}
|
||||
}
|
||||
|
||||
// MakeExclusiveSentinelKey constructs an internal key that is an
|
||||
// exclusive sentinel key, used as the upper boundary for an sstable
|
||||
// when a ranged key is the largest key in an sstable.
|
||||
func MakeExclusiveSentinelKey(kind InternalKeyKind, userKey []byte) InternalKey {
|
||||
return InternalKey{
|
||||
UserKey: userKey,
|
||||
Trailer: (InternalKeySeqNumMax << 8) | uint64(kind),
|
||||
}
|
||||
}
|
||||
|
||||
var kindsMap = map[string]InternalKeyKind{
|
||||
"DEL": InternalKeyKindDelete,
|
||||
"SINGLEDEL": InternalKeyKindSingleDelete,
|
||||
"RANGEDEL": InternalKeyKindRangeDelete,
|
||||
"LOGDATA": InternalKeyKindLogData,
|
||||
"SET": InternalKeyKindSet,
|
||||
"MERGE": InternalKeyKindMerge,
|
||||
"INVALID": InternalKeyKindInvalid,
|
||||
"SEPARATOR": InternalKeyKindSeparator,
|
||||
"SETWITHDEL": InternalKeyKindSetWithDelete,
|
||||
"RANGEKEYSET": InternalKeyKindRangeKeySet,
|
||||
"RANGEKEYUNSET": InternalKeyKindRangeKeyUnset,
|
||||
"RANGEKEYDEL": InternalKeyKindRangeKeyDelete,
|
||||
"INGESTSST": InternalKeyKindIngestSST,
|
||||
"DELSIZED": InternalKeyKindDeleteSized,
|
||||
}
|
||||
|
||||
// ParseInternalKey parses the string representation of an internal key. The
|
||||
// format is <user-key>.<kind>.<seq-num>. If the seq-num starts with a "b" it
|
||||
// is marked as a batch-seq-num (i.e. the InternalKeySeqNumBatch bit is set).
|
||||
func ParseInternalKey(s string) InternalKey {
|
||||
x := strings.Split(s, ".")
|
||||
ukey := x[0]
|
||||
kind, ok := kindsMap[x[1]]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("unknown kind: %q", x[1]))
|
||||
}
|
||||
j := 0
|
||||
if x[2][0] == 'b' {
|
||||
j = 1
|
||||
}
|
||||
seqNum, _ := strconv.ParseUint(x[2][j:], 10, 64)
|
||||
if x[2][0] == 'b' {
|
||||
seqNum |= InternalKeySeqNumBatch
|
||||
}
|
||||
return MakeInternalKey([]byte(ukey), seqNum, kind)
|
||||
}
|
||||
|
||||
// ParseKind parses the string representation of an internal key kind.
|
||||
func ParseKind(s string) InternalKeyKind {
|
||||
kind, ok := kindsMap[s]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("unknown kind: %q", s))
|
||||
}
|
||||
return kind
|
||||
}
|
||||
|
||||
// InternalTrailerLen is the number of bytes used to encode InternalKey.Trailer.
|
||||
const InternalTrailerLen = 8
|
||||
|
||||
// DecodeInternalKey decodes an encoded internal key. See InternalKey.Encode().
|
||||
func DecodeInternalKey(encodedKey []byte) InternalKey {
|
||||
n := len(encodedKey) - InternalTrailerLen
|
||||
var trailer uint64
|
||||
if n >= 0 {
|
||||
trailer = binary.LittleEndian.Uint64(encodedKey[n:])
|
||||
encodedKey = encodedKey[:n:n]
|
||||
} else {
|
||||
trailer = uint64(InternalKeyKindInvalid)
|
||||
encodedKey = nil
|
||||
}
|
||||
return InternalKey{
|
||||
UserKey: encodedKey,
|
||||
Trailer: trailer,
|
||||
}
|
||||
}
|
||||
|
||||
// InternalCompare compares two internal keys using the specified comparison
|
||||
// function. For equal user keys, internal keys compare in descending sequence
|
||||
// number order. For equal user keys and sequence numbers, internal keys
|
||||
// compare in descending kind order (this may happen in practice among range
|
||||
// keys).
|
||||
func InternalCompare(userCmp Compare, a, b InternalKey) int {
|
||||
if x := userCmp(a.UserKey, b.UserKey); x != 0 {
|
||||
return x
|
||||
}
|
||||
if a.Trailer > b.Trailer {
|
||||
return -1
|
||||
}
|
||||
if a.Trailer < b.Trailer {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Encode encodes the receiver into the buffer. The buffer must be large enough
|
||||
// to hold the encoded data. See InternalKey.Size().
|
||||
func (k InternalKey) Encode(buf []byte) {
|
||||
i := copy(buf, k.UserKey)
|
||||
binary.LittleEndian.PutUint64(buf[i:], k.Trailer)
|
||||
}
|
||||
|
||||
// EncodeTrailer returns the trailer encoded to an 8-byte array.
|
||||
func (k InternalKey) EncodeTrailer() [8]byte {
|
||||
var buf [8]byte
|
||||
binary.LittleEndian.PutUint64(buf[:], k.Trailer)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Separator returns a separator key such that k <= x && x < other, where less
|
||||
// than is consistent with the Compare function. The buf parameter may be used
|
||||
// to store the returned InternalKey.UserKey, though it is valid to pass a
|
||||
// nil. See the Separator type for details on separator keys.
|
||||
func (k InternalKey) Separator(
|
||||
cmp Compare, sep Separator, buf []byte, other InternalKey,
|
||||
) InternalKey {
|
||||
buf = sep(buf, k.UserKey, other.UserKey)
|
||||
if len(buf) <= len(k.UserKey) && cmp(k.UserKey, buf) < 0 {
|
||||
// The separator user key is physically shorter than k.UserKey (if it is
|
||||
// longer, we'll continue to use "k"), but logically after. Tack on the max
|
||||
// sequence number to the shortened user key. Note that we could tack on
|
||||
// any sequence number and kind here to create a valid separator key. We
|
||||
// use the max sequence number to match the behavior of LevelDB and
|
||||
// RocksDB.
|
||||
return MakeInternalKey(buf, InternalKeySeqNumMax, InternalKeyKindSeparator)
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
// Successor returns a successor key such that k <= x. A simple implementation
|
||||
// may return k unchanged. The buf parameter may be used to store the returned
|
||||
// InternalKey.UserKey, though it is valid to pass a nil.
|
||||
func (k InternalKey) Successor(cmp Compare, succ Successor, buf []byte) InternalKey {
|
||||
buf = succ(buf, k.UserKey)
|
||||
if len(buf) <= len(k.UserKey) && cmp(k.UserKey, buf) < 0 {
|
||||
// The successor user key is physically shorter that k.UserKey (if it is
|
||||
// longer, we'll continue to use "k"), but logically after. Tack on the max
|
||||
// sequence number to the shortened user key. Note that we could tack on
|
||||
// any sequence number and kind here to create a valid separator key. We
|
||||
// use the max sequence number to match the behavior of LevelDB and
|
||||
// RocksDB.
|
||||
return MakeInternalKey(buf, InternalKeySeqNumMax, InternalKeyKindSeparator)
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
// Size returns the encoded size of the key.
|
||||
func (k InternalKey) Size() int {
|
||||
return len(k.UserKey) + 8
|
||||
}
|
||||
|
||||
// SetSeqNum sets the sequence number component of the key.
|
||||
func (k *InternalKey) SetSeqNum(seqNum uint64) {
|
||||
k.Trailer = (seqNum << 8) | (k.Trailer & 0xff)
|
||||
}
|
||||
|
||||
// SeqNum returns the sequence number component of the key.
|
||||
func (k InternalKey) SeqNum() uint64 {
|
||||
return k.Trailer >> 8
|
||||
}
|
||||
|
||||
// SeqNumFromTrailer returns the sequence number component of a trailer.
|
||||
func SeqNumFromTrailer(t uint64) uint64 {
|
||||
return t >> 8
|
||||
}
|
||||
|
||||
// Visible returns true if the key is visible at the specified snapshot
|
||||
// sequence number.
|
||||
func (k InternalKey) Visible(snapshot, batchSnapshot uint64) bool {
|
||||
return Visible(k.SeqNum(), snapshot, batchSnapshot)
|
||||
}
|
||||
|
||||
// Visible returns true if a key with the provided sequence number is visible at
|
||||
// the specified snapshot sequence numbers.
|
||||
func Visible(seqNum uint64, snapshot, batchSnapshot uint64) bool {
|
||||
// There are two snapshot sequence numbers, one for committed keys and one
|
||||
// for batch keys. If a seqNum is less than `snapshot`, then seqNum
|
||||
// corresponds to a committed key that is visible. If seqNum has its batch
|
||||
// bit set, then seqNum corresponds to an uncommitted batch key. Its
|
||||
// visible if its snapshot is less than batchSnapshot.
|
||||
//
|
||||
// There's one complication. The maximal sequence number
|
||||
// (`InternalKeySeqNumMax`) is used across Pebble for exclusive sentinel
|
||||
// keys and other purposes. The maximal sequence number has its batch bit
|
||||
// set, but it can never be < `batchSnapshot`, since there is no expressible
|
||||
// larger snapshot. We dictate that the maximal sequence number is always
|
||||
// visible.
|
||||
return seqNum < snapshot ||
|
||||
((seqNum&InternalKeySeqNumBatch) != 0 && seqNum < batchSnapshot) ||
|
||||
seqNum == InternalKeySeqNumMax
|
||||
}
|
||||
|
||||
// SetKind sets the kind component of the key.
|
||||
func (k *InternalKey) SetKind(kind InternalKeyKind) {
|
||||
k.Trailer = (k.Trailer &^ 0xff) | uint64(kind)
|
||||
}
|
||||
|
||||
// Kind returns the kind component of the key.
|
||||
func (k InternalKey) Kind() InternalKeyKind {
|
||||
return TrailerKind(k.Trailer)
|
||||
}
|
||||
|
||||
// TrailerKind returns the key kind of the key trailer.
|
||||
func TrailerKind(trailer uint64) InternalKeyKind {
|
||||
return InternalKeyKind(trailer & 0xff)
|
||||
}
|
||||
|
||||
// Valid returns true if the key has a valid kind.
|
||||
func (k InternalKey) Valid() bool {
|
||||
return k.Kind() <= InternalKeyKindMax
|
||||
}
|
||||
|
||||
// Clone clones the storage for the UserKey component of the key.
|
||||
func (k InternalKey) Clone() InternalKey {
|
||||
if len(k.UserKey) == 0 {
|
||||
return k
|
||||
}
|
||||
return InternalKey{
|
||||
UserKey: append([]byte(nil), k.UserKey...),
|
||||
Trailer: k.Trailer,
|
||||
}
|
||||
}
|
||||
|
||||
// CopyFrom converts this InternalKey into a clone of the passed-in InternalKey,
|
||||
// reusing any space already used for the current UserKey.
|
||||
func (k *InternalKey) CopyFrom(k2 InternalKey) {
|
||||
k.UserKey = append(k.UserKey[:0], k2.UserKey...)
|
||||
k.Trailer = k2.Trailer
|
||||
}
|
||||
|
||||
// String returns a string representation of the key.
|
||||
func (k InternalKey) String() string {
|
||||
return fmt.Sprintf("%s#%d,%d", FormatBytes(k.UserKey), k.SeqNum(), k.Kind())
|
||||
}
|
||||
|
||||
// Pretty returns a formatter for the key.
|
||||
func (k InternalKey) Pretty(f FormatKey) fmt.Formatter {
|
||||
return prettyInternalKey{k, f}
|
||||
}
|
||||
|
||||
// IsExclusiveSentinel returns whether this internal key excludes point keys
|
||||
// with the same user key if used as an end boundary. See the comment on
|
||||
// InternalKeyRangeDeletionSentinel.
|
||||
func (k InternalKey) IsExclusiveSentinel() bool {
|
||||
switch kind := k.Kind(); kind {
|
||||
case InternalKeyKindRangeDelete:
|
||||
return k.Trailer == InternalKeyRangeDeleteSentinel
|
||||
case InternalKeyKindRangeKeyDelete, InternalKeyKindRangeKeyUnset, InternalKeyKindRangeKeySet:
|
||||
return (k.Trailer >> 8) == InternalKeySeqNumMax
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type prettyInternalKey struct {
|
||||
InternalKey
|
||||
formatKey FormatKey
|
||||
}
|
||||
|
||||
func (k prettyInternalKey) Format(s fmt.State, c rune) {
|
||||
if seqNum := k.SeqNum(); seqNum == InternalKeySeqNumMax {
|
||||
fmt.Fprintf(s, "%s#inf,%s", k.formatKey(k.UserKey), k.Kind())
|
||||
} else {
|
||||
fmt.Fprintf(s, "%s#%d,%s", k.formatKey(k.UserKey), k.SeqNum(), k.Kind())
|
||||
}
|
||||
}
|
||||
|
||||
// ParsePrettyInternalKey parses the pretty string representation of an
|
||||
// internal key. The format is <user-key>#<seq-num>,<kind>.
|
||||
func ParsePrettyInternalKey(s string) InternalKey {
|
||||
x := strings.FieldsFunc(s, func(c rune) bool { return c == '#' || c == ',' })
|
||||
ukey := x[0]
|
||||
kind, ok := kindsMap[x[2]]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("unknown kind: %q", x[2]))
|
||||
}
|
||||
var seqNum uint64
|
||||
if x[1] == "max" || x[1] == "inf" {
|
||||
seqNum = InternalKeySeqNumMax
|
||||
} else {
|
||||
seqNum, _ = strconv.ParseUint(x[1], 10, 64)
|
||||
}
|
||||
return MakeInternalKey([]byte(ukey), seqNum, kind)
|
||||
}
|
||||
Reference in New Issue
Block a user