mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 03:07:28 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			468 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			468 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2018 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 keyspan // import "github.com/cockroachdb/pebble/internal/keyspan"
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"sort"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"unicode"
 | 
						|
 | 
						|
	"github.com/cockroachdb/pebble/internal/base"
 | 
						|
)
 | 
						|
 | 
						|
// Span represents a set of keys over a span of user key space. All of the keys
 | 
						|
// within a Span are applied across the span's key span indicated by Start and
 | 
						|
// End. Each internal key applied over the user key span appears as a separate
 | 
						|
// Key, with its own kind and sequence number. Optionally, each Key may also
 | 
						|
// have a Suffix and/or Value.
 | 
						|
//
 | 
						|
// Note that the start user key is inclusive and the end user key is exclusive.
 | 
						|
//
 | 
						|
// Currently the only supported key kinds are:
 | 
						|
//
 | 
						|
//	RANGEDEL, RANGEKEYSET, RANGEKEYUNSET, RANGEKEYDEL.
 | 
						|
type Span struct {
 | 
						|
	// Start and End encode the user key range of all the contained items, with
 | 
						|
	// an inclusive start key and exclusive end key. Both Start and End must be
 | 
						|
	// non-nil, or both nil if representing an invalid Span.
 | 
						|
	Start, End []byte
 | 
						|
	// Keys holds the set of keys applied over the [Start, End) user key range.
 | 
						|
	// Keys is sorted by (SeqNum, Kind) descending, unless otherwise specified
 | 
						|
	// by the context. If SeqNum and Kind are equal, the order of Keys is
 | 
						|
	// undefined. Keys may be empty, even if Start and End are non-nil.
 | 
						|
	//
 | 
						|
	// Keys are a decoded representation of the internal keys stored in batches
 | 
						|
	// or sstable blocks. A single internal key in a range key block may produce
 | 
						|
	// several decoded Keys.
 | 
						|
	Keys      []Key
 | 
						|
	KeysOrder KeysOrder
 | 
						|
}
 | 
						|
 | 
						|
// KeysOrder describes the ordering of Keys within a Span.
 | 
						|
type KeysOrder int8
 | 
						|
 | 
						|
const (
 | 
						|
	// ByTrailerDesc indicates a Span's keys are sorted by Trailer descending.
 | 
						|
	// This is the default ordering, and the ordering used during physical
 | 
						|
	// storage.
 | 
						|
	ByTrailerDesc KeysOrder = iota
 | 
						|
	// BySuffixAsc indicates a Span's keys are sorted by Suffix ascending. This
 | 
						|
	// ordering is used during user iteration of range keys.
 | 
						|
	BySuffixAsc
 | 
						|
)
 | 
						|
 | 
						|
// Key represents a single key applied over a span of user keys. A Key is
 | 
						|
// contained by a Span which specifies the span of user keys over which the Key
 | 
						|
// is applied.
 | 
						|
type Key struct {
 | 
						|
	// Trailer contains the key kind and sequence number.
 | 
						|
	Trailer uint64
 | 
						|
	// Suffix holds an optional suffix associated with the key. This is only
 | 
						|
	// non-nil for RANGEKEYSET and RANGEKEYUNSET keys.
 | 
						|
	Suffix []byte
 | 
						|
	// Value holds a logical value associated with the Key. It is NOT the
 | 
						|
	// internal value stored in a range key or range deletion block.  This is
 | 
						|
	// only non-nil for RANGEKEYSET keys.
 | 
						|
	Value []byte
 | 
						|
}
 | 
						|
 | 
						|
// SeqNum returns the sequence number component of the key.
 | 
						|
func (k Key) SeqNum() uint64 {
 | 
						|
	return k.Trailer >> 8
 | 
						|
}
 | 
						|
 | 
						|
// VisibleAt returns true if the provided key is visible at the provided
 | 
						|
// snapshot sequence number. It interprets batch sequence numbers as always
 | 
						|
// visible, because non-visible batch span keys are filtered when they're
 | 
						|
// fragmented.
 | 
						|
func (k Key) VisibleAt(snapshot uint64) bool {
 | 
						|
	seq := k.SeqNum()
 | 
						|
	return seq < snapshot || seq&base.InternalKeySeqNumBatch != 0
 | 
						|
}
 | 
						|
 | 
						|
// Kind returns the kind component of the key.
 | 
						|
func (k Key) Kind() base.InternalKeyKind {
 | 
						|
	return base.InternalKeyKind(k.Trailer & 0xff)
 | 
						|
}
 | 
						|
 | 
						|
// Equal returns true if this Key is equal to the given key. Two keys are said
 | 
						|
// to be equal if the two Keys have equal trailers, suffix and value. Suffix
 | 
						|
// comparison uses the provided base.Compare func. Value comparison is bytewise.
 | 
						|
func (k Key) Equal(equal base.Equal, b Key) bool {
 | 
						|
	return k.Trailer == b.Trailer &&
 | 
						|
		equal(k.Suffix, b.Suffix) &&
 | 
						|
		bytes.Equal(k.Value, b.Value)
 | 
						|
}
 | 
						|
 | 
						|
// Valid returns true if the span is defined.
 | 
						|
func (s *Span) Valid() bool {
 | 
						|
	return s.Start != nil && s.End != nil
 | 
						|
}
 | 
						|
 | 
						|
// Empty returns true if the span does not contain any keys. An empty span may
 | 
						|
// still be Valid. A non-empty span must be Valid.
 | 
						|
//
 | 
						|
// An Empty span may be produced by Visible, or be produced by iterators in
 | 
						|
// order to surface the gaps between keys.
 | 
						|
func (s *Span) Empty() bool {
 | 
						|
	return s == nil || len(s.Keys) == 0
 | 
						|
}
 | 
						|
 | 
						|
// SmallestKey returns the smallest internal key defined by the span's keys.
 | 
						|
// It requires the Span's keys be in ByTrailerDesc order. It panics if the span
 | 
						|
// contains no keys or its keys are sorted in a different order.
 | 
						|
func (s *Span) SmallestKey() base.InternalKey {
 | 
						|
	if len(s.Keys) == 0 {
 | 
						|
		panic("pebble: Span contains no keys")
 | 
						|
	} else if s.KeysOrder != ByTrailerDesc {
 | 
						|
		panic("pebble: span's keys unexpectedly not in trailer order")
 | 
						|
	}
 | 
						|
	// The first key has the highest (sequence number,kind) tuple.
 | 
						|
	return base.InternalKey{
 | 
						|
		UserKey: s.Start,
 | 
						|
		Trailer: s.Keys[0].Trailer,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// LargestKey returns the largest internal key defined by the span's keys. The
 | 
						|
// returned key will always be a "sentinel key" at the end boundary. The
 | 
						|
// "sentinel key" models the exclusive end boundary by returning an InternalKey
 | 
						|
// with the maximal sequence number, ensuring all InternalKeys with the same
 | 
						|
// user key sort after the sentinel key.
 | 
						|
//
 | 
						|
// It requires the Span's keys be in ByTrailerDesc order. It panics if the span
 | 
						|
// contains no keys or its keys are sorted in a different order.
 | 
						|
func (s *Span) LargestKey() base.InternalKey {
 | 
						|
	if len(s.Keys) == 0 {
 | 
						|
		panic("pebble: Span contains no keys")
 | 
						|
	} else if s.KeysOrder != ByTrailerDesc {
 | 
						|
		panic("pebble: span's keys unexpectedly not in trailer order")
 | 
						|
	}
 | 
						|
	// The last key has the lowest (sequence number,kind) tuple.
 | 
						|
	kind := s.Keys[len(s.Keys)-1].Kind()
 | 
						|
	return base.MakeExclusiveSentinelKey(kind, s.End)
 | 
						|
}
 | 
						|
 | 
						|
// SmallestSeqNum returns the smallest sequence number of a key contained within
 | 
						|
// the span. It requires the Span's keys be in ByTrailerDesc order. It panics if
 | 
						|
// the span contains no keys or its keys are sorted in a different order.
 | 
						|
func (s *Span) SmallestSeqNum() uint64 {
 | 
						|
	if len(s.Keys) == 0 {
 | 
						|
		panic("pebble: Span contains no keys")
 | 
						|
	} else if s.KeysOrder != ByTrailerDesc {
 | 
						|
		panic("pebble: span's keys unexpectedly not in trailer order")
 | 
						|
	}
 | 
						|
 | 
						|
	return s.Keys[len(s.Keys)-1].SeqNum()
 | 
						|
}
 | 
						|
 | 
						|
// LargestSeqNum returns the largest sequence number of a key contained within
 | 
						|
// the span. It requires the Span's keys be in ByTrailerDesc order. It panics if
 | 
						|
// the span contains no keys or its keys are sorted in a different order.
 | 
						|
func (s *Span) LargestSeqNum() uint64 {
 | 
						|
	if len(s.Keys) == 0 {
 | 
						|
		panic("pebble: Span contains no keys")
 | 
						|
	} else if s.KeysOrder != ByTrailerDesc {
 | 
						|
		panic("pebble: span's keys unexpectedly not in trailer order")
 | 
						|
	}
 | 
						|
	return s.Keys[0].SeqNum()
 | 
						|
}
 | 
						|
 | 
						|
// TODO(jackson): Replace most of the calls to Visible with more targeted calls
 | 
						|
// that avoid the need to construct a new Span.
 | 
						|
 | 
						|
// Visible returns a span with the subset of keys visible at the provided
 | 
						|
// sequence number. It requires the Span's keys be in ByTrailerDesc order. It
 | 
						|
// panics if the span's keys are sorted in a different order.
 | 
						|
//
 | 
						|
// Visible may incur an allocation, so callers should prefer targeted,
 | 
						|
// non-allocating methods when possible.
 | 
						|
func (s Span) Visible(snapshot uint64) Span {
 | 
						|
	if s.KeysOrder != ByTrailerDesc {
 | 
						|
		panic("pebble: span's keys unexpectedly not in trailer order")
 | 
						|
	}
 | 
						|
 | 
						|
	ret := Span{Start: s.Start, End: s.End}
 | 
						|
	if len(s.Keys) == 0 {
 | 
						|
		return ret
 | 
						|
	}
 | 
						|
 | 
						|
	// Keys from indexed batches may force an allocation. The Keys slice is
 | 
						|
	// ordered by sequence number, so ordinarily we can return the trailing
 | 
						|
	// subslice containing keys with sequence numbers less than `seqNum`.
 | 
						|
	//
 | 
						|
	// However, batch keys are special. Only visible batch keys are included
 | 
						|
	// when an Iterator's batch spans are fragmented. They must always be
 | 
						|
	// visible.
 | 
						|
	//
 | 
						|
	// Batch keys can create a sandwich of visible batch keys at the beginning
 | 
						|
	// of the slice and visible committed keys at the end of the slice, forcing
 | 
						|
	// us to allocate a new slice and copy the contents.
 | 
						|
	//
 | 
						|
	// Care is taking to only incur an allocation only when batch keys and
 | 
						|
	// visible keys actually sandwich non-visible keys.
 | 
						|
 | 
						|
	// lastBatchIdx and lastNonVisibleIdx are set to the last index of a batch
 | 
						|
	// key and a non-visible key respectively.
 | 
						|
	lastBatchIdx := -1
 | 
						|
	lastNonVisibleIdx := -1
 | 
						|
	for i := range s.Keys {
 | 
						|
		if seqNum := s.Keys[i].SeqNum(); seqNum&base.InternalKeySeqNumBatch != 0 {
 | 
						|
			// Batch key. Always visible.
 | 
						|
			lastBatchIdx = i
 | 
						|
		} else if seqNum >= snapshot {
 | 
						|
			// This key is not visible.
 | 
						|
			lastNonVisibleIdx = i
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// In the following comments: b = batch, h = hidden, v = visible (committed).
 | 
						|
	switch {
 | 
						|
	case lastNonVisibleIdx == -1:
 | 
						|
		// All keys are visible.
 | 
						|
		//
 | 
						|
		// [b b b], [v v v] and [b b b v v v]
 | 
						|
		ret.Keys = s.Keys
 | 
						|
	case lastBatchIdx == -1:
 | 
						|
		// There are no batch keys, so we can return the continuous subslice
 | 
						|
		// starting after the last non-visible Key.
 | 
						|
		//
 | 
						|
		// h h h [v v v]
 | 
						|
		ret.Keys = s.Keys[lastNonVisibleIdx+1:]
 | 
						|
	case lastNonVisibleIdx == len(s.Keys)-1:
 | 
						|
		// While we have a batch key and non-visible keys, there are no
 | 
						|
		// committed visible keys. The 'sandwich' is missing the bottom layer,
 | 
						|
		// so we can return the continuous sublice at the beginning.
 | 
						|
		//
 | 
						|
		// [b b b] h h h
 | 
						|
		ret.Keys = s.Keys[0 : lastBatchIdx+1]
 | 
						|
	default:
 | 
						|
		// This is the problematic sandwich case. Allocate a new slice, copying
 | 
						|
		// the batch keys and the visible keys into it.
 | 
						|
		//
 | 
						|
		// [b b b] h h h [v v v]
 | 
						|
		ret.Keys = make([]Key, (lastBatchIdx+1)+(len(s.Keys)-lastNonVisibleIdx-1))
 | 
						|
		copy(ret.Keys, s.Keys[:lastBatchIdx+1])
 | 
						|
		copy(ret.Keys[lastBatchIdx+1:], s.Keys[lastNonVisibleIdx+1:])
 | 
						|
	}
 | 
						|
	return ret
 | 
						|
}
 | 
						|
 | 
						|
// VisibleAt returns true if the span contains a key visible at the provided
 | 
						|
// snapshot. Keys with sequence numbers with the batch bit set are treated as
 | 
						|
// always visible.
 | 
						|
//
 | 
						|
// VisibleAt requires the Span's keys be in ByTrailerDesc order. It panics if
 | 
						|
// the span's keys are sorted in a different order.
 | 
						|
func (s *Span) VisibleAt(snapshot uint64) bool {
 | 
						|
	if s.KeysOrder != ByTrailerDesc {
 | 
						|
		panic("pebble: span's keys unexpectedly not in trailer order")
 | 
						|
	}
 | 
						|
	if len(s.Keys) == 0 {
 | 
						|
		return false
 | 
						|
	} else if first := s.Keys[0].SeqNum(); first&base.InternalKeySeqNumBatch != 0 {
 | 
						|
		// Only visible batch keys are included when an Iterator's batch spans
 | 
						|
		// are fragmented. They must always be visible.
 | 
						|
		return true
 | 
						|
	} else {
 | 
						|
		// Otherwise we check the last key. Since keys are ordered decreasing in
 | 
						|
		// sequence number, the last key has the lowest sequence number of any
 | 
						|
		// of the span's keys. If any of the keys are visible, the last key must
 | 
						|
		// be visible. Or put differently: if the last key is not visible, then
 | 
						|
		// no key is visible.
 | 
						|
		return s.Keys[len(s.Keys)-1].SeqNum() < snapshot
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ShallowClone returns the span with a Keys slice owned by the span itself.
 | 
						|
// None of the key byte slices are cloned (see Span.DeepClone).
 | 
						|
func (s *Span) ShallowClone() Span {
 | 
						|
	c := Span{
 | 
						|
		Start:     s.Start,
 | 
						|
		End:       s.End,
 | 
						|
		Keys:      make([]Key, len(s.Keys)),
 | 
						|
		KeysOrder: s.KeysOrder,
 | 
						|
	}
 | 
						|
	copy(c.Keys, s.Keys)
 | 
						|
	return c
 | 
						|
}
 | 
						|
 | 
						|
// DeepClone clones the span, creating copies of all contained slices. DeepClone
 | 
						|
// is intended for non-production code paths like tests, the level checker, etc
 | 
						|
// because it is allocation heavy.
 | 
						|
func (s *Span) DeepClone() Span {
 | 
						|
	c := Span{
 | 
						|
		Start:     make([]byte, len(s.Start)),
 | 
						|
		End:       make([]byte, len(s.End)),
 | 
						|
		Keys:      make([]Key, len(s.Keys)),
 | 
						|
		KeysOrder: s.KeysOrder,
 | 
						|
	}
 | 
						|
	copy(c.Start, s.Start)
 | 
						|
	copy(c.End, s.End)
 | 
						|
	for i := range s.Keys {
 | 
						|
		c.Keys[i].Trailer = s.Keys[i].Trailer
 | 
						|
		if len(s.Keys[i].Suffix) > 0 {
 | 
						|
			c.Keys[i].Suffix = make([]byte, len(s.Keys[i].Suffix))
 | 
						|
			copy(c.Keys[i].Suffix, s.Keys[i].Suffix)
 | 
						|
		}
 | 
						|
		if len(s.Keys[i].Value) > 0 {
 | 
						|
			c.Keys[i].Value = make([]byte, len(s.Keys[i].Value))
 | 
						|
			copy(c.Keys[i].Value, s.Keys[i].Value)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return c
 | 
						|
}
 | 
						|
 | 
						|
// Contains returns true if the specified key resides within the span's bounds.
 | 
						|
func (s *Span) Contains(cmp base.Compare, key []byte) bool {
 | 
						|
	return cmp(s.Start, key) <= 0 && cmp(key, s.End) < 0
 | 
						|
}
 | 
						|
 | 
						|
// Covers returns true if the span covers keys at seqNum.
 | 
						|
//
 | 
						|
// Covers requires the Span's keys be in ByTrailerDesc order. It panics if the
 | 
						|
// span's keys are sorted in a different order.
 | 
						|
func (s Span) Covers(seqNum uint64) bool {
 | 
						|
	if s.KeysOrder != ByTrailerDesc {
 | 
						|
		panic("pebble: span's keys unexpectedly not in trailer order")
 | 
						|
	}
 | 
						|
	return !s.Empty() && s.Keys[0].SeqNum() > seqNum
 | 
						|
}
 | 
						|
 | 
						|
// CoversAt returns true if the span contains a key that is visible at the
 | 
						|
// provided snapshot sequence number, and that key's sequence number is higher
 | 
						|
// than seqNum.
 | 
						|
//
 | 
						|
// Keys with sequence numbers with the batch bit set are treated as always
 | 
						|
// visible.
 | 
						|
//
 | 
						|
// CoversAt requires the Span's keys be in ByTrailerDesc order. It panics if the
 | 
						|
// span's keys are sorted in a different order.
 | 
						|
func (s *Span) CoversAt(snapshot, seqNum uint64) bool {
 | 
						|
	if s.KeysOrder != ByTrailerDesc {
 | 
						|
		panic("pebble: span's keys unexpectedly not in trailer order")
 | 
						|
	}
 | 
						|
	// NB: A key is visible at `snapshot` if its sequence number is strictly
 | 
						|
	// less than `snapshot`. See base.Visible.
 | 
						|
	for i := range s.Keys {
 | 
						|
		if kseq := s.Keys[i].SeqNum(); kseq&base.InternalKeySeqNumBatch != 0 {
 | 
						|
			// Only visible batch keys are included when an Iterator's batch spans
 | 
						|
			// are fragmented. They must always be visible.
 | 
						|
			return kseq > seqNum
 | 
						|
		} else if kseq < snapshot {
 | 
						|
			return kseq > seqNum
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// String returns a string representation of the span.
 | 
						|
func (s Span) String() string {
 | 
						|
	return fmt.Sprint(prettySpan{Span: s, formatKey: base.DefaultFormatter})
 | 
						|
}
 | 
						|
 | 
						|
// Pretty returns a formatter for the span.
 | 
						|
func (s Span) Pretty(f base.FormatKey) fmt.Formatter {
 | 
						|
	// TODO(jackson): Take a base.FormatValue to format Key.Value too.
 | 
						|
	return prettySpan{s, f}
 | 
						|
}
 | 
						|
 | 
						|
type prettySpan struct {
 | 
						|
	Span
 | 
						|
	formatKey base.FormatKey
 | 
						|
}
 | 
						|
 | 
						|
func (s prettySpan) Format(fs fmt.State, c rune) {
 | 
						|
	if !s.Valid() {
 | 
						|
		fmt.Fprintf(fs, "<invalid>")
 | 
						|
		return
 | 
						|
	}
 | 
						|
	fmt.Fprintf(fs, "%s-%s:{", s.formatKey(s.Start), s.formatKey(s.End))
 | 
						|
	for i, k := range s.Keys {
 | 
						|
		if i > 0 {
 | 
						|
			fmt.Fprint(fs, " ")
 | 
						|
		}
 | 
						|
		fmt.Fprintf(fs, "(#%d,%s", k.SeqNum(), k.Kind())
 | 
						|
		if len(k.Suffix) > 0 || len(k.Value) > 0 {
 | 
						|
			fmt.Fprintf(fs, ",%s", k.Suffix)
 | 
						|
		}
 | 
						|
		if len(k.Value) > 0 {
 | 
						|
			fmt.Fprintf(fs, ",%s", k.Value)
 | 
						|
		}
 | 
						|
		fmt.Fprint(fs, ")")
 | 
						|
	}
 | 
						|
	fmt.Fprintf(fs, "}")
 | 
						|
}
 | 
						|
 | 
						|
// SortKeysByTrailer sorts a keys slice by trailer.
 | 
						|
func SortKeysByTrailer(keys *[]Key) {
 | 
						|
	// NB: keys is a pointer to a slice instead of a slice to avoid `sorted`
 | 
						|
	// escaping to the heap.
 | 
						|
	sorted := (*keysBySeqNumKind)(keys)
 | 
						|
	sort.Sort(sorted)
 | 
						|
}
 | 
						|
 | 
						|
// KeysBySuffix implements sort.Interface, sorting its member Keys slice to by
 | 
						|
// Suffix in the order dictated by Cmp.
 | 
						|
type KeysBySuffix struct {
 | 
						|
	Cmp  base.Compare
 | 
						|
	Keys []Key
 | 
						|
}
 | 
						|
 | 
						|
func (s *KeysBySuffix) Len() int           { return len(s.Keys) }
 | 
						|
func (s *KeysBySuffix) Less(i, j int) bool { return s.Cmp(s.Keys[i].Suffix, s.Keys[j].Suffix) < 0 }
 | 
						|
func (s *KeysBySuffix) Swap(i, j int)      { s.Keys[i], s.Keys[j] = s.Keys[j], s.Keys[i] }
 | 
						|
 | 
						|
// ParseSpan parses the string representation of a Span. It's intended for
 | 
						|
// tests. ParseSpan panics if passed a malformed span representation.
 | 
						|
func ParseSpan(input string) Span {
 | 
						|
	var s Span
 | 
						|
	parts := strings.FieldsFunc(input, func(r rune) bool {
 | 
						|
		switch r {
 | 
						|
		case '-', ':', '{', '}':
 | 
						|
			return true
 | 
						|
		default:
 | 
						|
			return unicode.IsSpace(r)
 | 
						|
		}
 | 
						|
	})
 | 
						|
	s.Start, s.End = []byte(parts[0]), []byte(parts[1])
 | 
						|
 | 
						|
	// Each of the remaining parts represents a single Key.
 | 
						|
	s.Keys = make([]Key, 0, len(parts)-2)
 | 
						|
	for _, p := range parts[2:] {
 | 
						|
		keyFields := strings.FieldsFunc(p, func(r rune) bool {
 | 
						|
			switch r {
 | 
						|
			case '#', ',', '(', ')':
 | 
						|
				return true
 | 
						|
			default:
 | 
						|
				return unicode.IsSpace(r)
 | 
						|
			}
 | 
						|
		})
 | 
						|
 | 
						|
		var k Key
 | 
						|
		// Parse the sequence number.
 | 
						|
		seqNum, err := strconv.ParseUint(keyFields[0], 10, 64)
 | 
						|
		if err != nil {
 | 
						|
			panic(fmt.Sprintf("invalid sequence number: %q: %s", keyFields[0], err))
 | 
						|
		}
 | 
						|
		// Parse the key kind.
 | 
						|
		kind := base.ParseKind(keyFields[1])
 | 
						|
		k.Trailer = base.MakeTrailer(seqNum, kind)
 | 
						|
		// Parse the optional suffix.
 | 
						|
		if len(keyFields) >= 3 {
 | 
						|
			k.Suffix = []byte(keyFields[2])
 | 
						|
		}
 | 
						|
		// Parse the optional value.
 | 
						|
		if len(keyFields) >= 4 {
 | 
						|
			k.Value = []byte(keyFields[3])
 | 
						|
		}
 | 
						|
		s.Keys = append(s.Keys, k)
 | 
						|
	}
 | 
						|
	return s
 | 
						|
}
 |