Skip to content

Commit d1ae979

Browse files
committed
storage: refactor computeStatsForIterWithVisitors
Refactor computeStatsForIterWithVisitors to make the control flow more obvious and document the conditions more completely. This refactor duplicates some code by extracting the case for non-MVCC values. This duplication leads to more understandable code through removing deeply nested conditional state. Epic: none Informs #149835. Release note: None
1 parent c994ab7 commit d1ae979

File tree

1 file changed

+103
-84
lines changed

1 file changed

+103
-84
lines changed

pkg/storage/mvcc.go

Lines changed: 103 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -7425,6 +7425,52 @@ func computeStatsForIterWithVisitors(
74257425
implicitMeta := isValue && !bytes.Equal(unsafeKey.Key, prevKey)
74267426
prevKey = append(prevKey[:0], unsafeKey.Key...)
74277427

7428+
if !isValue {
7429+
// The key-value is not a MVCC value (i.e., the key has a zero
7430+
// timestamp). The stats accounting for non-MVCC values is simpler.
7431+
metaKeySize := int64(len(unsafeKey.Key)) + 1
7432+
metaValSize := int64(iter.ValueLen())
7433+
totalBytes := metaKeySize + metaValSize
7434+
first = true
7435+
7436+
if isSys {
7437+
// The key is an internal system key. It contributes to
7438+
// Sys{Bytes,Count} instead of {Key,Val}{Count,Bytes}.
7439+
ms.SysBytes += totalBytes
7440+
ms.SysCount++
7441+
if isAbortSpanKey(unsafeKey.Key) {
7442+
ms.AbortSpanBytes += totalBytes
7443+
}
7444+
continue
7445+
}
7446+
// A non-system key. Decode the value as a MVCCMetadata.
7447+
v, err := iter.UnsafeValue()
7448+
if err != nil {
7449+
return enginepb.MVCCStats{}, err
7450+
}
7451+
if err := protoutil.Unmarshal(v, &meta); err != nil {
7452+
return ms, errors.Wrap(err, "unable to decode MVCCMetadata")
7453+
}
7454+
if meta.Deleted {
7455+
// First value is deleted, so it's GC'able; add meta key & value
7456+
// bytes to age stat.
7457+
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - meta.Timestamp.WallTime/1e9)
7458+
} else {
7459+
ms.LiveBytes += totalBytes
7460+
ms.LiveCount++
7461+
}
7462+
ms.KeyBytes += metaKeySize
7463+
ms.ValBytes += metaValSize
7464+
ms.KeyCount++
7465+
if meta.IsInline() {
7466+
ms.ValCount++
7467+
}
7468+
continue
7469+
}
7470+
7471+
// The key-value is a MVCC value (i.e., the key has a non-zero
7472+
// timestamp).
7473+
74287474
// Find the closest range tombstone above the point key. Range tombstones
74297475
// cannot exist above intents, and are undefined across inline values, so we
74307476
// only take them into account for versioned values.
@@ -7434,25 +7480,15 @@ func computeStatsForIterWithVisitors(
74347480
// stack as we descend through older versions, resetting once we hit a new
74357481
// key.
74367482
var nextRangeTombstone hlc.Timestamp
7437-
if isValue {
7438-
if !rangeTombstones.IsEmpty() && unsafeKey.Timestamp.LessEq(rangeTombstones.Newest()) {
7439-
if v, ok := rangeTombstones.FirstAtOrAbove(unsafeKey.Timestamp); ok {
7440-
nextRangeTombstone = v.Timestamp
7441-
}
7483+
if !rangeTombstones.IsEmpty() && unsafeKey.Timestamp.LessEq(rangeTombstones.Newest()) {
7484+
if v, ok := rangeTombstones.FirstAtOrAbove(unsafeKey.Timestamp); ok {
7485+
nextRangeTombstone = v.Timestamp
74427486
}
74437487
}
74447488

7445-
var valueLen int
7446-
var mvccValueIsTombstone bool
7447-
if isValue {
7448-
// MVCC value
7449-
var err error
7450-
valueLen, mvccValueIsTombstone, err = iter.MVCCValueLenAndIsTombstone()
7451-
if err != nil {
7452-
return enginepb.MVCCStats{}, errors.Wrap(err, "unable to decode MVCCValue")
7453-
}
7454-
} else {
7455-
valueLen = iter.ValueLen()
7489+
valueLen, mvccValueIsTombstone, err := iter.MVCCValueLenAndIsTombstone()
7490+
if err != nil {
7491+
return enginepb.MVCCStats{}, errors.Wrap(err, "unable to decode MVCCValue")
74567492
}
74577493
if implicitMeta {
74587494
// INVARIANT: implicitMeta => isValue.
@@ -7462,34 +7498,21 @@ func computeStatsForIterWithVisitors(
74627498
meta.ValBytes = int64(valueLen)
74637499
meta.Deleted = mvccValueIsTombstone
74647500
meta.Timestamp.WallTime = unsafeKey.Timestamp.WallTime
7465-
}
74667501

7467-
if !isValue || implicitMeta {
74687502
metaKeySize := int64(len(unsafeKey.Key)) + 1
7469-
var metaValSize int64
7470-
if !implicitMeta {
7471-
metaValSize = int64(valueLen)
7472-
}
7473-
totalBytes := metaKeySize + metaValSize
7503+
totalBytes := metaKeySize
74747504
first = true
74757505

74767506
if isSys {
74777507
ms.SysBytes += totalBytes
74787508
ms.SysCount++
7479-
if isAbortSpanKey(unsafeKey.Key) {
7480-
ms.AbortSpanBytes += totalBytes
7509+
// We don't need to account for the abort-span key here because
7510+
// that key is not versioned.
7511+
if buildutil.CrdbTestBuild && isAbortSpanKey(unsafeKey.Key) {
7512+
return enginepb.MVCCStats{}, errors.AssertionFailedf(
7513+
"versioned abort span key encountered by ComputeStats: %s", unsafeKey.Key)
74817514
}
74827515
} else {
7483-
if !implicitMeta {
7484-
v, err := iter.UnsafeValue()
7485-
if err != nil {
7486-
return enginepb.MVCCStats{}, err
7487-
}
7488-
if err := protoutil.Unmarshal(v, &meta); err != nil {
7489-
return ms, errors.Wrap(err, "unable to decode MVCCMetadata")
7490-
}
7491-
}
7492-
74937516
if meta.Deleted {
74947517
// First value is deleted, so it's GC'able; add meta key & value bytes to age stat.
74957518
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - meta.Timestamp.WallTime/1e9)
@@ -7502,68 +7525,64 @@ func computeStatsForIterWithVisitors(
75027525
ms.LiveCount++
75037526
}
75047527
ms.KeyBytes += metaKeySize
7505-
ms.ValBytes += metaValSize
75067528
ms.KeyCount++
75077529
if meta.IsInline() {
75087530
ms.ValCount++
75097531
}
75107532
}
7511-
if !implicitMeta {
7512-
continue
7513-
}
75147533
}
75157534

75167535
totalBytes := int64(valueLen) + MVCCVersionTimestampSize
75177536
if isSys {
75187537
ms.SysBytes += totalBytes
7538+
continue
7539+
}
7540+
ms.KeyBytes += MVCCVersionTimestampSize
7541+
ms.ValBytes += int64(valueLen)
7542+
ms.ValCount++
7543+
if first {
7544+
first = false
7545+
if meta.Deleted {
7546+
// First value is deleted, so it's GC'able; add key & value bytes to age stat.
7547+
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - meta.Timestamp.WallTime/1e9)
7548+
} else if nextRangeTombstone.IsSet() {
7549+
// First value was deleted by a range tombstone; add key & value bytes to
7550+
// age stat from range tombstone onwards.
7551+
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - nextRangeTombstone.WallTime/1e9)
7552+
} else {
7553+
ms.LiveBytes += totalBytes
7554+
}
7555+
if meta.Txn != nil {
7556+
ms.IntentBytes += totalBytes
7557+
ms.IntentCount++
7558+
ms.LockCount++
7559+
ms.LockAge += nowNanos/1e9 - meta.Timestamp.WallTime/1e9
7560+
}
7561+
if meta.KeyBytes != MVCCVersionTimestampSize {
7562+
return ms, errors.Errorf("expected mvcc metadata key bytes to equal %d; got %d "+
7563+
"(meta: %s)", MVCCVersionTimestampSize, meta.KeyBytes, &meta)
7564+
}
7565+
if meta.ValBytes != int64(valueLen) {
7566+
return ms, errors.Errorf("expected mvcc metadata val bytes to equal %d; got %d "+
7567+
"(meta: %s)", valueLen, meta.ValBytes, &meta)
7568+
}
7569+
accrueGCAgeNanos = meta.Timestamp.WallTime
75197570
} else {
7520-
if first {
7521-
first = false
7522-
if meta.Deleted {
7523-
// First value is deleted, so it's GC'able; add key & value bytes to age stat.
7524-
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - meta.Timestamp.WallTime/1e9)
7525-
} else if nextRangeTombstone.IsSet() {
7526-
// First value was deleted by a range tombstone; add key & value bytes to
7527-
// age stat from range tombstone onwards.
7528-
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - nextRangeTombstone.WallTime/1e9)
7529-
} else {
7530-
ms.LiveBytes += totalBytes
7531-
}
7532-
if meta.Txn != nil {
7533-
ms.IntentBytes += totalBytes
7534-
ms.IntentCount++
7535-
ms.LockCount++
7536-
ms.LockAge += nowNanos/1e9 - meta.Timestamp.WallTime/1e9
7537-
}
7538-
if meta.KeyBytes != MVCCVersionTimestampSize {
7539-
return ms, errors.Errorf("expected mvcc metadata key bytes to equal %d; got %d "+
7540-
"(meta: %s)", MVCCVersionTimestampSize, meta.KeyBytes, &meta)
7541-
}
7542-
if meta.ValBytes != int64(valueLen) {
7543-
return ms, errors.Errorf("expected mvcc metadata val bytes to equal %d; got %d "+
7544-
"(meta: %s)", valueLen, meta.ValBytes, &meta)
7545-
}
7546-
accrueGCAgeNanos = meta.Timestamp.WallTime
7571+
// Overwritten value. Is it a deletion tombstone?
7572+
if mvccValueIsTombstone {
7573+
// The contribution of the tombstone picks up GCByteAge from its own timestamp on.
7574+
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - unsafeKey.Timestamp.WallTime/1e9)
7575+
} else if nextRangeTombstone.IsSet() && nextRangeTombstone.WallTime < accrueGCAgeNanos {
7576+
// The kv pair was deleted by a range tombstone below the next
7577+
// version, so it accumulates garbage from the range tombstone.
7578+
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - nextRangeTombstone.WallTime/1e9)
75477579
} else {
7548-
// Overwritten value. Is it a deletion tombstone?
7549-
if mvccValueIsTombstone {
7550-
// The contribution of the tombstone picks up GCByteAge from its own timestamp on.
7551-
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - unsafeKey.Timestamp.WallTime/1e9)
7552-
} else if nextRangeTombstone.IsSet() && nextRangeTombstone.WallTime < accrueGCAgeNanos {
7553-
// The kv pair was deleted by a range tombstone below the next
7554-
// version, so it accumulates garbage from the range tombstone.
7555-
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - nextRangeTombstone.WallTime/1e9)
7556-
} else {
7557-
// The kv pair is an overwritten value, so it became non-live when the closest more
7558-
// recent value was written.
7559-
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - accrueGCAgeNanos/1e9)
7560-
}
7561-
// Update for the next version we may end up looking at.
7562-
accrueGCAgeNanos = unsafeKey.Timestamp.WallTime
7580+
// The kv pair is an overwritten value, so it became non-live when the closest more
7581+
// recent value was written.
7582+
ms.GCBytesAge += totalBytes * (nowNanos/1e9 - accrueGCAgeNanos/1e9)
75637583
}
7564-
ms.KeyBytes += MVCCVersionTimestampSize
7565-
ms.ValBytes += int64(valueLen)
7566-
ms.ValCount++
7584+
// Update for the next version we may end up looking at.
7585+
accrueGCAgeNanos = unsafeKey.Timestamp.WallTime
75677586
}
75687587
}
75697588

0 commit comments

Comments
 (0)