Upgrade versions of vendored libs
This commit is contained in:
411
vendor/github.com/cockroachdb/pebble/db.go
generated
vendored
411
vendor/github.com/cockroachdb/pebble/db.go
generated
vendored
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/cockroachdb/pebble/sstable"
|
||||
"github.com/cockroachdb/pebble/vfs"
|
||||
"github.com/cockroachdb/pebble/vfs/atomicfs"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -140,22 +141,12 @@ type Writer interface {
|
||||
// It is safe to modify the contents of the arguments after Set returns.
|
||||
Set(key, value []byte, o *WriteOptions) error
|
||||
|
||||
// Experimental returns the experimental write API.
|
||||
Experimental() ExperimentalWriter
|
||||
}
|
||||
|
||||
// ExperimentalWriter provides access to experimental features of a Batch.
|
||||
type ExperimentalWriter interface {
|
||||
Writer
|
||||
|
||||
// RangeKeySet sets a range key mapping the key range [start, end) at the MVCC
|
||||
// timestamp suffix to value. The suffix is optional. If any portion of the key
|
||||
// range [start, end) is already set by a range key with the same suffix value,
|
||||
// RangeKeySet overrides it.
|
||||
//
|
||||
// It is safe to modify the contents of the arguments after RangeKeySet returns.
|
||||
//
|
||||
// WARNING: This is an experimental feature with limited functionality.
|
||||
RangeKeySet(start, end, suffix, value []byte, opts *WriteOptions) error
|
||||
|
||||
// RangeKeyUnset removes a range key mapping the key range [start, end) at the
|
||||
@@ -166,8 +157,6 @@ type ExperimentalWriter interface {
|
||||
//
|
||||
// It is safe to modify the contents of the arguments after RangeKeyUnset
|
||||
// returns.
|
||||
//
|
||||
// WARNING: This is an experimental feature with limited functionality.
|
||||
RangeKeyUnset(start, end, suffix []byte, opts *WriteOptions) error
|
||||
|
||||
// RangeKeyDelete deletes all of the range keys in the range [start,end)
|
||||
@@ -177,11 +166,43 @@ type ExperimentalWriter interface {
|
||||
//
|
||||
// It is safe to modify the contents of the arguments after RangeKeyDelete
|
||||
// returns.
|
||||
//
|
||||
// WARNING: This is an experimental feature with limited functionality.
|
||||
RangeKeyDelete(start, end []byte, opts *WriteOptions) error
|
||||
}
|
||||
|
||||
// CPUWorkHandle represents a handle used by the CPUWorkPermissionGranter API.
|
||||
type CPUWorkHandle interface {
|
||||
// Permitted indicates whether Pebble can use additional CPU resources.
|
||||
Permitted() bool
|
||||
}
|
||||
|
||||
// CPUWorkPermissionGranter is used to request permission to opportunistically
|
||||
// use additional CPUs to speed up internal background work.
|
||||
type CPUWorkPermissionGranter interface {
|
||||
// GetPermission returns a handle regardless of whether permission is granted
|
||||
// or not. In the latter case, the handle is only useful for recording
|
||||
// the CPU time actually spent on this calling goroutine.
|
||||
GetPermission(time.Duration) CPUWorkHandle
|
||||
// CPUWorkDone must be called regardless of whether CPUWorkHandle.Permitted
|
||||
// returns true or false.
|
||||
CPUWorkDone(CPUWorkHandle)
|
||||
}
|
||||
|
||||
// Use a default implementation for the CPU work granter to avoid excessive nil
|
||||
// checks in the code.
|
||||
type defaultCPUWorkHandle struct{}
|
||||
|
||||
func (d defaultCPUWorkHandle) Permitted() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type defaultCPUWorkGranter struct{}
|
||||
|
||||
func (d defaultCPUWorkGranter) GetPermission(_ time.Duration) CPUWorkHandle {
|
||||
return defaultCPUWorkHandle{}
|
||||
}
|
||||
|
||||
func (d defaultCPUWorkGranter) CPUWorkDone(_ CPUWorkHandle) {}
|
||||
|
||||
// DB provides a concurrent, persistent ordered key/value store.
|
||||
//
|
||||
// A DB's basic operations (Get, Set, Delete) should be self-explanatory. Get
|
||||
@@ -222,16 +243,6 @@ type DB struct {
|
||||
memTableCount int64
|
||||
memTableReserved int64 // number of bytes reserved in the cache for memtables
|
||||
|
||||
// bytesFlushed is the number of bytes flushed in the current flush. This
|
||||
// must be read/written atomically since it is accessed by both the flush
|
||||
// and compaction routines.
|
||||
bytesFlushed uint64
|
||||
|
||||
// bytesCompacted is the number of bytes compacted in the current compaction.
|
||||
// This is used as a dummy variable to increment during compaction, and the
|
||||
// value is not used anywhere.
|
||||
bytesCompacted uint64
|
||||
|
||||
// The size of the current log file (i.e. db.mu.log.queue[len(queue)-1].
|
||||
logSize uint64
|
||||
|
||||
@@ -281,9 +292,7 @@ type DB struct {
|
||||
closed *atomic.Value
|
||||
closedCh chan struct{}
|
||||
|
||||
compactionLimiter limiter
|
||||
flushLimiter limiter
|
||||
deletionLimiter limiter
|
||||
deletionLimiter limiter
|
||||
|
||||
// Async deletion jobs spawned by cleaners increment this WaitGroup, and
|
||||
// call Done when completed. Once `d.mu.cleaning` is false, the db.Close()
|
||||
@@ -355,7 +364,10 @@ type DB struct {
|
||||
// (i.e. makeRoomForWrite).
|
||||
*record.LogWriter
|
||||
// Can be nil.
|
||||
metrics *record.LogWriterMetrics
|
||||
metrics struct {
|
||||
fsyncLatency prometheus.Histogram
|
||||
record.LogWriterMetrics
|
||||
}
|
||||
}
|
||||
|
||||
mem struct {
|
||||
@@ -461,11 +473,6 @@ type DB struct {
|
||||
}
|
||||
}
|
||||
|
||||
// rangeKeys is a temporary field so that Pebble can provide a non-durable
|
||||
// implementation of range keys in advance of the real implementation.
|
||||
// TODO(jackson): Remove this.
|
||||
rangeKeys *RangeKeysArena
|
||||
|
||||
// Normally equal to time.Now() but may be overridden in tests.
|
||||
timeNow func() time.Time
|
||||
}
|
||||
@@ -542,15 +549,13 @@ func (d *DB) getInternal(key []byte, b *Batch, s *Snapshot) ([]byte, io.Closer,
|
||||
}
|
||||
|
||||
i := &buf.dbi
|
||||
pointIter := base.WrapIterWithStats(get)
|
||||
pointIter := get
|
||||
*i = Iterator{
|
||||
getIterAlloc: buf,
|
||||
cmp: d.cmp,
|
||||
equal: d.equal,
|
||||
iter: pointIter,
|
||||
pointIter: pointIter,
|
||||
merge: d.merge,
|
||||
split: d.split,
|
||||
comparer: *d.opts.Comparer,
|
||||
readState: readState,
|
||||
keyBuf: buf.keyBuf,
|
||||
}
|
||||
@@ -658,21 +663,16 @@ func (d *DB) LogData(data []byte, opts *WriteOptions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Experimental returns the experimental write API.
|
||||
func (d *DB) Experimental() ExperimentalWriter {
|
||||
return experimentalDB{d}
|
||||
}
|
||||
|
||||
type experimentalDB struct {
|
||||
*DB
|
||||
}
|
||||
|
||||
// RangeKeySet implements the ExperimentalWriter interface.
|
||||
func (e experimentalDB) RangeKeySet(start, end, suffix, value []byte, opts *WriteOptions) error {
|
||||
b := newBatch(e.DB)
|
||||
eb := b.Experimental()
|
||||
_ = eb.RangeKeySet(start, end, suffix, value, opts)
|
||||
if err := e.Apply(b, opts); err != nil {
|
||||
// RangeKeySet sets a range key mapping the key range [start, end) at the MVCC
|
||||
// timestamp suffix to value. The suffix is optional. If any portion of the key
|
||||
// range [start, end) is already set by a range key with the same suffix value,
|
||||
// RangeKeySet overrides it.
|
||||
//
|
||||
// It is safe to modify the contents of the arguments after RangeKeySet returns.
|
||||
func (d *DB) RangeKeySet(start, end, suffix, value []byte, opts *WriteOptions) error {
|
||||
b := newBatch(d)
|
||||
_ = b.RangeKeySet(start, end, suffix, value, opts)
|
||||
if err := d.Apply(b, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
// Only release the batch on success.
|
||||
@@ -680,12 +680,18 @@ func (e experimentalDB) RangeKeySet(start, end, suffix, value []byte, opts *Writ
|
||||
return nil
|
||||
}
|
||||
|
||||
// RangeKeyUnset implements the ExperimentalWriter interface.
|
||||
func (e experimentalDB) RangeKeyUnset(start, end, suffix []byte, opts *WriteOptions) error {
|
||||
b := newBatch(e.DB)
|
||||
eb := b.Experimental()
|
||||
_ = eb.RangeKeyUnset(start, end, suffix, opts)
|
||||
if err := e.Apply(b, opts); err != nil {
|
||||
// RangeKeyUnset removes a range key mapping the key range [start, end) at the
|
||||
// MVCC timestamp suffix. The suffix may be omitted to remove an unsuffixed
|
||||
// range key. RangeKeyUnset only removes portions of range keys that fall within
|
||||
// the [start, end) key span, and only range keys with suffixes that exactly
|
||||
// match the unset suffix.
|
||||
//
|
||||
// It is safe to modify the contents of the arguments after RangeKeyUnset
|
||||
// returns.
|
||||
func (d *DB) RangeKeyUnset(start, end, suffix []byte, opts *WriteOptions) error {
|
||||
b := newBatch(d)
|
||||
_ = b.RangeKeyUnset(start, end, suffix, opts)
|
||||
if err := d.Apply(b, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
// Only release the batch on success.
|
||||
@@ -693,12 +699,17 @@ func (e experimentalDB) RangeKeyUnset(start, end, suffix []byte, opts *WriteOpti
|
||||
return nil
|
||||
}
|
||||
|
||||
// RangeKeyDelete implements the ExperimentalWriter interface.
|
||||
func (e experimentalDB) RangeKeyDelete(start, end []byte, opts *WriteOptions) error {
|
||||
b := newBatch(e.DB)
|
||||
eb := b.Experimental()
|
||||
_ = eb.RangeKeyDelete(start, end, opts)
|
||||
if err := e.Apply(b, opts); err != nil {
|
||||
// RangeKeyDelete deletes all of the range keys in the range [start,end)
|
||||
// (inclusive on start, exclusive on end). It does not delete point keys (for
|
||||
// that use DeleteRange). RangeKeyDelete removes all range keys within the
|
||||
// bounds, including those with or without suffixes.
|
||||
//
|
||||
// It is safe to modify the contents of the arguments after RangeKeyDelete
|
||||
// returns.
|
||||
func (d *DB) RangeKeyDelete(start, end []byte, opts *WriteOptions) error {
|
||||
b := newBatch(d)
|
||||
_ = b.RangeKeyDelete(start, end, opts)
|
||||
if err := d.Apply(b, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
// Only release the batch on success.
|
||||
@@ -735,9 +746,6 @@ func (d *DB) Apply(batch *Batch, opts *WriteOptions) error {
|
||||
if d.split == nil {
|
||||
return errNoSplit
|
||||
}
|
||||
if d.opts.Experimental.RangeKeys == nil {
|
||||
panic("pebble: range keys require the Experimental.RangeKeys option")
|
||||
}
|
||||
if d.FormatMajorVersion() < FormatRangeKeys {
|
||||
panic(fmt.Sprintf(
|
||||
"pebble: range keys require at least format major version %d (current: %d)",
|
||||
@@ -785,9 +793,18 @@ func (d *DB) commitApply(b *Batch, mem *memTable) error {
|
||||
// If the batch contains range tombstones and the database is configured
|
||||
// to flush range deletions, schedule a delayed flush so that disk space
|
||||
// may be reclaimed without additional writes or an explicit flush.
|
||||
if b.countRangeDels > 0 && d.opts.Experimental.DeleteRangeFlushDelay > 0 {
|
||||
if b.countRangeDels > 0 && d.opts.FlushDelayDeleteRange > 0 {
|
||||
d.mu.Lock()
|
||||
d.maybeScheduleDelayedFlush(mem)
|
||||
d.maybeScheduleDelayedFlush(mem, d.opts.FlushDelayDeleteRange)
|
||||
d.mu.Unlock()
|
||||
}
|
||||
|
||||
// If the batch contains range keys and the database is configured to flush
|
||||
// range keys, schedule a delayed flush so that the range keys are cleared
|
||||
// from the memtable.
|
||||
if b.countRangeKeys > 0 && d.opts.FlushDelayRangeKey > 0 {
|
||||
d.mu.Lock()
|
||||
d.maybeScheduleDelayedFlush(mem, d.opts.FlushDelayRangeKey)
|
||||
d.mu.Unlock()
|
||||
}
|
||||
|
||||
@@ -881,9 +898,6 @@ func (d *DB) newIterInternal(batch *Batch, s *Snapshot, o *IterOptions) *Iterato
|
||||
panic(err)
|
||||
}
|
||||
if o.rangeKeys() {
|
||||
if d.opts.Experimental.RangeKeys == nil {
|
||||
panic("pebble: range keys require the Experimental.RangeKeys option")
|
||||
}
|
||||
if d.FormatMajorVersion() < FormatRangeKeys {
|
||||
panic(fmt.Sprintf(
|
||||
"pebble: range keys require at least format major version %d (current: %d)",
|
||||
@@ -921,24 +935,28 @@ func (d *DB) newIterInternal(batch *Batch, s *Snapshot, o *IterOptions) *Iterato
|
||||
dbi := &buf.dbi
|
||||
*dbi = Iterator{
|
||||
alloc: buf,
|
||||
cmp: d.cmp,
|
||||
equal: d.equal,
|
||||
merge: d.merge,
|
||||
split: d.split,
|
||||
comparer: *d.opts.Comparer,
|
||||
readState: readState,
|
||||
keyBuf: buf.keyBuf,
|
||||
prefixOrFullSeekKey: buf.prefixOrFullSeekKey,
|
||||
boundsBuf: buf.boundsBuf,
|
||||
batch: batch,
|
||||
newIters: d.newIters,
|
||||
newIterRangeKey: d.tableNewRangeKeyIter,
|
||||
seqNum: seqNum,
|
||||
db: d,
|
||||
}
|
||||
if o != nil {
|
||||
dbi.opts = *o
|
||||
dbi.saveBounds(o.LowerBound, o.UpperBound)
|
||||
}
|
||||
dbi.opts.logger = d.opts.Logger
|
||||
if d.opts.private.disableLazyCombinedIteration {
|
||||
dbi.opts.disableLazyCombinedIteration = true
|
||||
}
|
||||
if batch != nil {
|
||||
dbi.batchSeqNum = dbi.batch.nextSeqNum()
|
||||
}
|
||||
return finishInitializingIter(buf)
|
||||
}
|
||||
|
||||
@@ -963,45 +981,95 @@ func finishInitializingIter(buf *iterAlloc) *Iterator {
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the point iterator. This function either returns a pointer to
|
||||
// dbi.merging (if points are enabled) or an emptyIter. If this is called
|
||||
// during a SetOptions call and this Iterator has already initialized
|
||||
// dbi.merging, constructPointIter returns the existing, unmodified point
|
||||
// iterator which is stored in dbi.pointIter.
|
||||
dbi.iter = constructPointIter(dbi, dbi.batch, memtables, buf)
|
||||
if dbi.opts.pointKeys() {
|
||||
// Construct the point iterator, initializing dbi.pointIter to point to
|
||||
// dbi.merging. If this is called during a SetOptions call and this
|
||||
// Iterator has already initialized dbi.merging, constructPointIter is a
|
||||
// noop and an initialized pointIter already exists in dbi.pointIter.
|
||||
dbi.constructPointIter(memtables, buf)
|
||||
dbi.iter = dbi.pointIter
|
||||
} else {
|
||||
dbi.iter = emptyIter
|
||||
}
|
||||
|
||||
// If range keys are enabled, construct the range key iterator stack too.
|
||||
if dbi.opts.rangeKeys() {
|
||||
if dbi.rangeKey == nil {
|
||||
dbi.rangeKey = iterRangeKeyStateAllocPool.Get().(*iteratorRangeKeyState)
|
||||
dbi.rangeKey.keys.cmp = dbi.cmp
|
||||
dbi.rangeKey.rangeKeyIter = dbi.db.newRangeKeyIter(dbi.rangeKey, dbi.seqNum, dbi.batch, dbi.readState, &dbi.opts)
|
||||
dbi.rangeKeyMasking.init(dbi, dbi.comparer.Compare, dbi.comparer.Split)
|
||||
|
||||
// When iterating over both point and range keys, don't create the
|
||||
// range-key iterator stack immediately if we can avoid it. This
|
||||
// optimization takes advantage of the expected sparseness of range
|
||||
// keys, and configures the point-key iterator to dynamically switch to
|
||||
// combined iteration when it observes a file containing range keys.
|
||||
//
|
||||
// Lazy combined iteration is not possible if a batch or a memtable
|
||||
// contains any range keys.
|
||||
useLazyCombinedIteration := dbi.rangeKey == nil &&
|
||||
dbi.opts.KeyTypes == IterKeyTypePointsAndRanges &&
|
||||
(dbi.batch == nil || dbi.batch.countRangeKeys == 0) &&
|
||||
!dbi.opts.disableLazyCombinedIteration
|
||||
if useLazyCombinedIteration {
|
||||
// The user requested combined iteration, and there's no indexed
|
||||
// batch currently containing range keys that would prevent lazy
|
||||
// combined iteration. Check the memtables to see if they contain
|
||||
// any range keys.
|
||||
for i := range memtables {
|
||||
if memtables[i].containsRangeKeys() {
|
||||
useLazyCombinedIteration = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap the point iterator (currently dbi.iter) with an interleaving
|
||||
// iterator that interleaves range keys pulled from
|
||||
// dbi.rangeKey.rangeKeyIter.
|
||||
if useLazyCombinedIteration {
|
||||
dbi.lazyCombinedIter = lazyCombinedIter{
|
||||
parent: dbi,
|
||||
pointIter: dbi.pointIter,
|
||||
combinedIterState: combinedIterState{
|
||||
initialized: false,
|
||||
},
|
||||
}
|
||||
dbi.iter = &dbi.lazyCombinedIter
|
||||
} else {
|
||||
dbi.lazyCombinedIter.combinedIterState = combinedIterState{
|
||||
initialized: true,
|
||||
}
|
||||
if dbi.rangeKey == nil {
|
||||
dbi.rangeKey = iterRangeKeyStateAllocPool.Get().(*iteratorRangeKeyState)
|
||||
dbi.rangeKey.init(dbi.comparer.Compare, dbi.comparer.Split, &dbi.opts)
|
||||
dbi.constructRangeKeyIter()
|
||||
} else {
|
||||
dbi.rangeKey.iterConfig.SetBounds(dbi.opts.LowerBound, dbi.opts.UpperBound)
|
||||
}
|
||||
|
||||
// Wrap the point iterator (currently dbi.iter) with an interleaving
|
||||
// iterator that interleaves range keys pulled from
|
||||
// dbi.rangeKey.rangeKeyIter.
|
||||
//
|
||||
// NB: The interleaving iterator is always reinitialized, even if
|
||||
// dbi already had an initialized range key iterator, in case the point
|
||||
// iterator changed or the range key masking suffix changed.
|
||||
dbi.rangeKey.iiter.Init(&dbi.comparer, dbi.iter, dbi.rangeKey.rangeKeyIter,
|
||||
&dbi.rangeKeyMasking, dbi.opts.LowerBound, dbi.opts.UpperBound)
|
||||
dbi.iter = &dbi.rangeKey.iiter
|
||||
}
|
||||
} else {
|
||||
// !dbi.opts.rangeKeys()
|
||||
//
|
||||
// NB: The interleaving iterator is always reinitialized, even if
|
||||
// dbi already had an initialized range key iterator, in case the point
|
||||
// iterator changed or the range key masking suffix changed.
|
||||
dbi.rangeKey.iter.Init(dbi.cmp, dbi.iter, dbi.rangeKey.rangeKeyIter, keyspan.Hooks{
|
||||
SpanChanged: dbi.rangeKeySpanChanged,
|
||||
SkipPoint: dbi.rangeKeySkipPoint,
|
||||
}, dbi.opts.LowerBound, dbi.opts.UpperBound)
|
||||
dbi.iter = &dbi.rangeKey.iter
|
||||
// Reset the combined iterator state. The initialized=true ensures the
|
||||
// iterator doesn't unnecessarily try to switch to combined iteration.
|
||||
dbi.lazyCombinedIter.combinedIterState = combinedIterState{initialized: true}
|
||||
}
|
||||
return dbi
|
||||
}
|
||||
|
||||
func constructPointIter(
|
||||
dbi *Iterator, batch *Batch, memtables flushableList, buf *iterAlloc,
|
||||
) internalIteratorWithStats {
|
||||
if !dbi.opts.pointKeys() {
|
||||
return emptyIter
|
||||
func (i *Iterator) constructPointIter(memtables flushableList, buf *iterAlloc) {
|
||||
if i.pointIter != nil {
|
||||
// Already have one.
|
||||
return
|
||||
}
|
||||
if dbi.pointIter != nil {
|
||||
return dbi.pointIter
|
||||
internalOpts := internalIterOpts{stats: &i.stats.InternalStats}
|
||||
if i.opts.RangeKeyMasking.Filter != nil {
|
||||
internalOpts.boundLimitedFilter = &i.rangeKeyMasking
|
||||
}
|
||||
|
||||
// Merging levels and levels from iterAlloc.
|
||||
@@ -1013,12 +1081,12 @@ func constructPointIter(
|
||||
// should improve the performance.
|
||||
numMergingLevels := 0
|
||||
numLevelIters := 0
|
||||
if batch != nil {
|
||||
if i.batch != nil {
|
||||
numMergingLevels++
|
||||
}
|
||||
numMergingLevels += len(memtables)
|
||||
|
||||
current := dbi.readState.current
|
||||
current := i.readState.current
|
||||
numMergingLevels += len(current.L0SublevelFiles)
|
||||
numLevelIters += len(current.L0SublevelFiles)
|
||||
for level := 1; level < len(current.Levels); level++ {
|
||||
@@ -1037,19 +1105,39 @@ func constructPointIter(
|
||||
}
|
||||
|
||||
// Top-level is the batch, if any.
|
||||
if batch != nil {
|
||||
mlevels = append(mlevels, mergingIterLevel{
|
||||
iter: base.WrapIterWithStats(batch.newInternalIter(&dbi.opts)),
|
||||
rangeDelIter: batch.newRangeDelIter(&dbi.opts),
|
||||
})
|
||||
if i.batch != nil {
|
||||
if i.batch.index == nil {
|
||||
// This isn't an indexed batch. Include an error iterator so that
|
||||
// the resulting iterator correctly surfaces ErrIndexed.
|
||||
mlevels = append(mlevels, mergingIterLevel{
|
||||
iter: newErrorIter(ErrNotIndexed),
|
||||
rangeDelIter: newErrorKeyspanIter(ErrNotIndexed),
|
||||
})
|
||||
} else {
|
||||
i.batch.initInternalIter(&i.opts, &i.batchPointIter)
|
||||
i.batch.initRangeDelIter(&i.opts, &i.batchRangeDelIter, i.batchSeqNum)
|
||||
// Only include the batch's rangedel iterator if it's non-empty.
|
||||
// This requires some subtle logic in the case a rangedel is later
|
||||
// written to the batch and the view of the batch is refreshed
|
||||
// during a call to SetOptions—in this case, we need to reconstruct
|
||||
// the point iterator to add the batch rangedel iterator.
|
||||
var rangeDelIter keyspan.FragmentIterator
|
||||
if i.batchRangeDelIter.Count() > 0 {
|
||||
rangeDelIter = &i.batchRangeDelIter
|
||||
}
|
||||
mlevels = append(mlevels, mergingIterLevel{
|
||||
iter: &i.batchPointIter,
|
||||
rangeDelIter: rangeDelIter,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Next are the memtables.
|
||||
for i := len(memtables) - 1; i >= 0; i-- {
|
||||
mem := memtables[i]
|
||||
for j := len(memtables) - 1; j >= 0; j-- {
|
||||
mem := memtables[j]
|
||||
mlevels = append(mlevels, mergingIterLevel{
|
||||
iter: base.WrapIterWithStats(mem.newIter(&dbi.opts)),
|
||||
rangeDelIter: mem.newRangeDelIter(&dbi.opts),
|
||||
iter: mem.newIter(&i.opts),
|
||||
rangeDelIter: mem.newRangeDelIter(&i.opts),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1058,16 +1146,13 @@ func constructPointIter(
|
||||
levelsIndex := len(levels)
|
||||
mlevels = mlevels[:numMergingLevels]
|
||||
levels = levels[:numLevelIters]
|
||||
|
||||
addLevelIterForFiles := func(files manifest.LevelIterator, level manifest.Level) {
|
||||
li := &levels[levelsIndex]
|
||||
|
||||
li.init(dbi.opts, dbi.cmp, dbi.split, dbi.newIters, files, level, nil)
|
||||
li.init(i.opts, i.comparer.Compare, i.comparer.Split, i.newIters, files, level, internalOpts)
|
||||
li.initRangeDel(&mlevels[mlevelsIndex].rangeDelIter)
|
||||
li.initSmallestLargestUserKey(&mlevels[mlevelsIndex].smallestUserKey,
|
||||
&mlevels[mlevelsIndex].largestUserKey,
|
||||
&mlevels[mlevelsIndex].isLargestUserKeyRangeDelSentinel)
|
||||
li.initIsSyntheticIterBoundsKey(&mlevels[mlevelsIndex].isSyntheticIterBoundsKey)
|
||||
li.initBoundaryContext(&mlevels[mlevelsIndex].levelIterBoundaryContext)
|
||||
li.initCombinedIterState(&i.lazyCombinedIter.combinedIterState)
|
||||
mlevels[mlevelsIndex].iter = li
|
||||
|
||||
levelsIndex++
|
||||
@@ -1087,11 +1172,13 @@ func constructPointIter(
|
||||
}
|
||||
addLevelIterForFiles(current.Levels[level].Iter(), manifest.Level(level))
|
||||
}
|
||||
buf.merging.init(&dbi.opts, dbi.cmp, dbi.split, mlevels...)
|
||||
buf.merging.snapshot = dbi.seqNum
|
||||
buf.merging.init(&i.opts, &i.stats.InternalStats, i.comparer.Compare, i.comparer.Split, mlevels...)
|
||||
buf.merging.snapshot = i.seqNum
|
||||
buf.merging.batchSnapshot = i.batchSeqNum
|
||||
buf.merging.elideRangeTombstones = true
|
||||
dbi.pointIter = &buf.merging
|
||||
return &buf.merging
|
||||
buf.merging.combinedIterState = &i.lazyCombinedIter.combinedIterState
|
||||
i.pointIter = &buf.merging
|
||||
i.merging = &buf.merging
|
||||
}
|
||||
|
||||
// NewBatch returns a new empty write-only batch. Any reads on the batch will
|
||||
@@ -1150,6 +1237,18 @@ func (d *DB) NewSnapshot() *Snapshot {
|
||||
// or to call Close concurrently with any other DB method. It is not valid
|
||||
// to call any of a DB's methods after the DB has been closed.
|
||||
func (d *DB) Close() error {
|
||||
// Lock the commit pipeline for the duration of Close. This prevents a race
|
||||
// with makeRoomForWrite. Rotating the WAL in makeRoomForWrite requires
|
||||
// dropping d.mu several times for I/O. If Close only holds d.mu, an
|
||||
// in-progress WAL rotation may re-acquire d.mu only once the database is
|
||||
// closed.
|
||||
//
|
||||
// Additionally, locking the commit pipeline makes it more likely that
|
||||
// (illegal) concurrent writes will observe d.closed.Load() != nil, creating
|
||||
// more understable panics if the database is improperly used concurrently
|
||||
// during Close.
|
||||
d.commit.mu.Lock()
|
||||
defer d.commit.mu.Unlock()
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if err := d.closed.Load(); err != nil {
|
||||
@@ -1239,10 +1338,22 @@ func (d *DB) Close() error {
|
||||
d.compactionSchedulers.Wait()
|
||||
d.mu.Lock()
|
||||
|
||||
// As a sanity check, ensure that there are no zombie tables. A non-zero count
|
||||
// hints at a reference count leak.
|
||||
if ztbls := len(d.mu.versions.zombieTables); ztbls > 0 {
|
||||
err = firstError(err, errors.Errorf("non-zero zombie file count: %d", ztbls))
|
||||
}
|
||||
|
||||
// If the options include a closer to 'close' the filesystem, close it.
|
||||
if d.opts.private.fsCloser != nil {
|
||||
d.opts.private.fsCloser.Close()
|
||||
}
|
||||
|
||||
// Return an error if the user failed to close all open snapshots.
|
||||
if v := d.mu.snapshots.count(); v > 0 {
|
||||
err = firstError(err, errors.Errorf("leaked snapshots: %d open snapshots on DB %p", v, d))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1426,36 +1537,18 @@ func (d *DB) AsyncFlush() (<-chan struct{}, error) {
|
||||
return flushed, nil
|
||||
}
|
||||
|
||||
// InternalIntervalMetrics returns the InternalIntervalMetrics and resets for
|
||||
// the next interval (which is until the next call to this method).
|
||||
func (d *DB) InternalIntervalMetrics() *InternalIntervalMetrics {
|
||||
m := &InternalIntervalMetrics{}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.mu.log.metrics != nil {
|
||||
m.LogWriter.WriteThroughput = d.mu.log.metrics.WriteThroughput
|
||||
m.LogWriter.PendingBufferUtilization =
|
||||
d.mu.log.metrics.PendingBufferLen.Mean() / record.CapAllocatedBlocks
|
||||
m.LogWriter.SyncQueueUtilization = d.mu.log.metrics.SyncQueueLen.Mean() / record.SyncConcurrency
|
||||
m.LogWriter.SyncLatencyMicros = d.mu.log.metrics.SyncLatencyMicros
|
||||
d.mu.log.metrics = nil
|
||||
}
|
||||
m.Flush.WriteThroughput = d.mu.compact.flushWriteThroughput
|
||||
d.mu.compact.flushWriteThroughput = ThroughputMetric{}
|
||||
return m
|
||||
}
|
||||
|
||||
// Metrics returns metrics about the database.
|
||||
func (d *DB) Metrics() *Metrics {
|
||||
metrics := &Metrics{}
|
||||
recycledLogsCount, recycledLogSize := d.logRecycler.stats()
|
||||
|
||||
d.mu.Lock()
|
||||
vers := d.mu.versions.currentVersion()
|
||||
*metrics = d.mu.versions.metrics
|
||||
metrics.Compact.EstimatedDebt = d.mu.versions.picker.estimatedCompactionDebt(0)
|
||||
metrics.Compact.InProgressBytes = atomic.LoadInt64(&d.mu.versions.atomic.atomicInProgressBytes)
|
||||
metrics.Compact.NumInProgress = int64(d.mu.compact.compactingCount)
|
||||
metrics.Compact.MarkedFiles = d.mu.versions.currentVersion().Stats.MarkedForCompaction
|
||||
metrics.Compact.MarkedFiles = vers.Stats.MarkedForCompaction
|
||||
for _, m := range d.mu.mem.queue {
|
||||
metrics.MemTable.Size += m.totalBytes()
|
||||
}
|
||||
@@ -1499,9 +1592,18 @@ func (d *DB) Metrics() *Metrics {
|
||||
}
|
||||
metrics.private.optionsFileSize = d.optionsFileSize
|
||||
|
||||
metrics.Keys.RangeKeySetsCount = countRangeKeySetFragments(vers)
|
||||
|
||||
d.mu.versions.logLock()
|
||||
metrics.private.manifestFileSize = uint64(d.mu.versions.manifest.Size())
|
||||
d.mu.versions.logUnlock()
|
||||
|
||||
metrics.LogWriter.FsyncLatency = d.mu.log.metrics.fsyncLatency
|
||||
if err := metrics.LogWriter.Merge(&d.mu.log.metrics.LogWriterMetrics); err != nil {
|
||||
d.opts.Logger.Infof("metrics error: %s", err)
|
||||
}
|
||||
metrics.Flush.WriteThroughput = d.mu.compact.flushWriteThroughput
|
||||
|
||||
d.mu.Unlock()
|
||||
|
||||
metrics.BlockCache = d.opts.Cache.Metrics()
|
||||
@@ -1791,12 +1893,8 @@ func (d *DB) makeRoomForWrite(b *Batch) error {
|
||||
err = d.mu.log.LogWriter.Close()
|
||||
metrics := d.mu.log.LogWriter.Metrics()
|
||||
d.mu.Lock()
|
||||
if d.mu.log.metrics == nil {
|
||||
d.mu.log.metrics = metrics
|
||||
} else {
|
||||
if err := d.mu.log.metrics.Merge(metrics); err != nil {
|
||||
d.opts.Logger.Infof("metrics error: %s", err)
|
||||
}
|
||||
if err := d.mu.log.metrics.Merge(metrics); err != nil {
|
||||
d.opts.Logger.Infof("metrics error: %s", err)
|
||||
}
|
||||
d.mu.Unlock()
|
||||
|
||||
@@ -1848,6 +1946,7 @@ func (d *DB) makeRoomForWrite(b *Batch) error {
|
||||
newLogFile.Close()
|
||||
} else if err == nil {
|
||||
newLogFile = vfs.NewSyncingFile(newLogFile, vfs.SyncingFileOptions{
|
||||
NoSyncOnClose: d.opts.NoSyncOnClose,
|
||||
BytesPerSync: d.opts.WALBytesPerSync,
|
||||
PreallocateSize: d.walPreallocateSize(),
|
||||
})
|
||||
@@ -1883,8 +1982,10 @@ func (d *DB) makeRoomForWrite(b *Batch) error {
|
||||
|
||||
if !d.opts.DisableWAL {
|
||||
d.mu.log.queue = append(d.mu.log.queue, fileInfo{fileNum: newLogNum, fileSize: newLogSize})
|
||||
d.mu.log.LogWriter = record.NewLogWriter(newLogFile, newLogNum)
|
||||
d.mu.log.LogWriter.SetMinSyncInterval(d.opts.WALMinSyncInterval)
|
||||
d.mu.log.LogWriter = record.NewLogWriter(newLogFile, newLogNum, record.LogWriterConfig{
|
||||
WALFsyncLatency: d.mu.log.metrics.fsyncLatency,
|
||||
WALMinSyncInterval: d.opts.WALMinSyncInterval,
|
||||
})
|
||||
}
|
||||
|
||||
immMem := d.mu.mem.mutable
|
||||
@@ -1946,7 +2047,7 @@ func (d *DB) makeRoomForWrite(b *Batch) error {
|
||||
var entry *flushableEntry
|
||||
d.mu.mem.mutable, entry = d.newMemTable(newLogNum, logSeqNum)
|
||||
d.mu.mem.queue = append(d.mu.mem.queue, entry)
|
||||
d.updateReadStateLocked(nil, nil)
|
||||
d.updateReadStateLocked(nil)
|
||||
if immMem.writerUnref() {
|
||||
d.maybeScheduleFlush()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user