@@ -7426,6 +7426,52 @@ func computeStatsForIterWithVisitors(
74267426 implicitMeta := isValue && ! bytes .Equal (unsafeKey .Key , prevKey )
74277427 prevKey = append (prevKey [:0 ], unsafeKey .Key ... )
74287428
7429+ if ! isValue {
7430+ // The key-value is not a MVCC value (i.e., the key has a zero
7431+ // timestamp). The stats accounting for non-MVCC values is simpler.
7432+ metaKeySize := int64 (len (unsafeKey .Key )) + 1
7433+ metaValSize := int64 (iter .ValueLen ())
7434+ totalBytes := metaKeySize + metaValSize
7435+ first = true
7436+
7437+ if isSys {
7438+ // The key is an internal system key. It contributes to
7439+ // Sys{Bytes,Count} instead of {Key,Val}{Count,Bytes}.
7440+ ms .SysBytes += totalBytes
7441+ ms .SysCount ++
7442+ if isAbortSpanKey (unsafeKey .Key ) {
7443+ ms .AbortSpanBytes += totalBytes
7444+ }
7445+ continue
7446+ }
7447+ // A non-system key. Decode the value as a MVCCMetadata.
7448+ v , err := iter .UnsafeValue ()
7449+ if err != nil {
7450+ return enginepb.MVCCStats {}, err
7451+ }
7452+ if err := protoutil .Unmarshal (v , & meta ); err != nil {
7453+ return ms , errors .Wrap (err , "unable to decode MVCCMetadata" )
7454+ }
7455+ if meta .Deleted {
7456+ // First value is deleted, so it's GC'able; add meta key & value
7457+ // bytes to age stat.
7458+ ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - meta .Timestamp .WallTime / 1e9 )
7459+ } else {
7460+ ms .LiveBytes += totalBytes
7461+ ms .LiveCount ++
7462+ }
7463+ ms .KeyBytes += metaKeySize
7464+ ms .ValBytes += metaValSize
7465+ ms .KeyCount ++
7466+ if meta .IsInline () {
7467+ ms .ValCount ++
7468+ }
7469+ continue
7470+ }
7471+
7472+ // The key-value is a MVCC value (i.e., the key has a non-zero
7473+ // timestamp).
7474+
74297475 // Find the closest range tombstone above the point key. Range tombstones
74307476 // cannot exist above intents, and are undefined across inline values, so we
74317477 // only take them into account for versioned values.
@@ -7435,25 +7481,15 @@ func computeStatsForIterWithVisitors(
74357481 // stack as we descend through older versions, resetting once we hit a new
74367482 // key.
74377483 var nextRangeTombstone hlc.Timestamp
7438- if isValue {
7439- if ! rangeTombstones .IsEmpty () && unsafeKey .Timestamp .LessEq (rangeTombstones .Newest ()) {
7440- if v , ok := rangeTombstones .FirstAtOrAbove (unsafeKey .Timestamp ); ok {
7441- nextRangeTombstone = v .Timestamp
7442- }
7484+ if ! rangeTombstones .IsEmpty () && unsafeKey .Timestamp .LessEq (rangeTombstones .Newest ()) {
7485+ if v , ok := rangeTombstones .FirstAtOrAbove (unsafeKey .Timestamp ); ok {
7486+ nextRangeTombstone = v .Timestamp
74437487 }
74447488 }
74457489
7446- var valueLen int
7447- var mvccValueIsTombstone bool
7448- if isValue {
7449- // MVCC value
7450- var err error
7451- valueLen , mvccValueIsTombstone , err = iter .MVCCValueLenAndIsTombstone ()
7452- if err != nil {
7453- return enginepb.MVCCStats {}, errors .Wrap (err , "unable to decode MVCCValue" )
7454- }
7455- } else {
7456- valueLen = iter .ValueLen ()
7490+ valueLen , mvccValueIsTombstone , err := iter .MVCCValueLenAndIsTombstone ()
7491+ if err != nil {
7492+ return enginepb.MVCCStats {}, errors .Wrap (err , "unable to decode MVCCValue" )
74577493 }
74587494 if implicitMeta {
74597495 // INVARIANT: implicitMeta => isValue.
@@ -7463,34 +7499,21 @@ func computeStatsForIterWithVisitors(
74637499 meta .ValBytes = int64 (valueLen )
74647500 meta .Deleted = mvccValueIsTombstone
74657501 meta .Timestamp .WallTime = unsafeKey .Timestamp .WallTime
7466- }
74677502
7468- if ! isValue || implicitMeta {
74697503 metaKeySize := int64 (len (unsafeKey .Key )) + 1
7470- var metaValSize int64
7471- if ! implicitMeta {
7472- metaValSize = int64 (valueLen )
7473- }
7474- totalBytes := metaKeySize + metaValSize
7504+ totalBytes := metaKeySize
74757505 first = true
74767506
74777507 if isSys {
74787508 ms .SysBytes += totalBytes
74797509 ms .SysCount ++
7480- if isAbortSpanKey (unsafeKey .Key ) {
7481- ms .AbortSpanBytes += totalBytes
7510+ // We don't need to account for the abort-span key here because
7511+ // that key is not versioned.
7512+ if buildutil .CrdbTestBuild && isAbortSpanKey (unsafeKey .Key ) {
7513+ return enginepb.MVCCStats {}, errors .AssertionFailedf (
7514+ "versioned abort span key encountered by ComputeStats: %s" , unsafeKey .Key )
74827515 }
74837516 } else {
7484- if ! implicitMeta {
7485- v , err := iter .UnsafeValue ()
7486- if err != nil {
7487- return enginepb.MVCCStats {}, err
7488- }
7489- if err := protoutil .Unmarshal (v , & meta ); err != nil {
7490- return ms , errors .Wrap (err , "unable to decode MVCCMetadata" )
7491- }
7492- }
7493-
74947517 if meta .Deleted {
74957518 // First value is deleted, so it's GC'able; add meta key & value bytes to age stat.
74967519 ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - meta .Timestamp .WallTime / 1e9 )
@@ -7503,68 +7526,64 @@ func computeStatsForIterWithVisitors(
75037526 ms .LiveCount ++
75047527 }
75057528 ms .KeyBytes += metaKeySize
7506- ms .ValBytes += metaValSize
75077529 ms .KeyCount ++
75087530 if meta .IsInline () {
75097531 ms .ValCount ++
75107532 }
75117533 }
7512- if ! implicitMeta {
7513- continue
7514- }
75157534 }
75167535
75177536 totalBytes := int64 (valueLen ) + MVCCVersionTimestampSize
75187537 if isSys {
75197538 ms .SysBytes += totalBytes
7539+ continue
7540+ }
7541+ ms .KeyBytes += MVCCVersionTimestampSize
7542+ ms .ValBytes += int64 (valueLen )
7543+ ms .ValCount ++
7544+ if first {
7545+ first = false
7546+ if meta .Deleted {
7547+ // First value is deleted, so it's GC'able; add key & value bytes to age stat.
7548+ ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - meta .Timestamp .WallTime / 1e9 )
7549+ } else if nextRangeTombstone .IsSet () {
7550+ // First value was deleted by a range tombstone; add key & value bytes to
7551+ // age stat from range tombstone onwards.
7552+ ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - nextRangeTombstone .WallTime / 1e9 )
7553+ } else {
7554+ ms .LiveBytes += totalBytes
7555+ }
7556+ if meta .Txn != nil {
7557+ ms .IntentBytes += totalBytes
7558+ ms .IntentCount ++
7559+ ms .LockCount ++
7560+ ms .LockAge += nowNanos / 1e9 - meta .Timestamp .WallTime / 1e9
7561+ }
7562+ if meta .KeyBytes != MVCCVersionTimestampSize {
7563+ return ms , errors .Errorf ("expected mvcc metadata key bytes to equal %d; got %d " +
7564+ "(meta: %s)" , MVCCVersionTimestampSize , meta .KeyBytes , & meta )
7565+ }
7566+ if meta .ValBytes != int64 (valueLen ) {
7567+ return ms , errors .Errorf ("expected mvcc metadata val bytes to equal %d; got %d " +
7568+ "(meta: %s)" , valueLen , meta .ValBytes , & meta )
7569+ }
7570+ accrueGCAgeNanos = meta .Timestamp .WallTime
75207571 } else {
7521- if first {
7522- first = false
7523- if meta .Deleted {
7524- // First value is deleted, so it's GC'able; add key & value bytes to age stat.
7525- ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - meta .Timestamp .WallTime / 1e9 )
7526- } else if nextRangeTombstone .IsSet () {
7527- // First value was deleted by a range tombstone; add key & value bytes to
7528- // age stat from range tombstone onwards.
7529- ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - nextRangeTombstone .WallTime / 1e9 )
7530- } else {
7531- ms .LiveBytes += totalBytes
7532- }
7533- if meta .Txn != nil {
7534- ms .IntentBytes += totalBytes
7535- ms .IntentCount ++
7536- ms .LockCount ++
7537- ms .LockAge += nowNanos / 1e9 - meta .Timestamp .WallTime / 1e9
7538- }
7539- if meta .KeyBytes != MVCCVersionTimestampSize {
7540- return ms , errors .Errorf ("expected mvcc metadata key bytes to equal %d; got %d " +
7541- "(meta: %s)" , MVCCVersionTimestampSize , meta .KeyBytes , & meta )
7542- }
7543- if meta .ValBytes != int64 (valueLen ) {
7544- return ms , errors .Errorf ("expected mvcc metadata val bytes to equal %d; got %d " +
7545- "(meta: %s)" , valueLen , meta .ValBytes , & meta )
7546- }
7547- accrueGCAgeNanos = meta .Timestamp .WallTime
7572+ // Overwritten value. Is it a deletion tombstone?
7573+ if mvccValueIsTombstone {
7574+ // The contribution of the tombstone picks up GCByteAge from its own timestamp on.
7575+ ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - unsafeKey .Timestamp .WallTime / 1e9 )
7576+ } else if nextRangeTombstone .IsSet () && nextRangeTombstone .WallTime < accrueGCAgeNanos {
7577+ // The kv pair was deleted by a range tombstone below the next
7578+ // version, so it accumulates garbage from the range tombstone.
7579+ ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - nextRangeTombstone .WallTime / 1e9 )
75487580 } else {
7549- // Overwritten value. Is it a deletion tombstone?
7550- if mvccValueIsTombstone {
7551- // The contribution of the tombstone picks up GCByteAge from its own timestamp on.
7552- ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - unsafeKey .Timestamp .WallTime / 1e9 )
7553- } else if nextRangeTombstone .IsSet () && nextRangeTombstone .WallTime < accrueGCAgeNanos {
7554- // The kv pair was deleted by a range tombstone below the next
7555- // version, so it accumulates garbage from the range tombstone.
7556- ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - nextRangeTombstone .WallTime / 1e9 )
7557- } else {
7558- // The kv pair is an overwritten value, so it became non-live when the closest more
7559- // recent value was written.
7560- ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - accrueGCAgeNanos / 1e9 )
7561- }
7562- // Update for the next version we may end up looking at.
7563- accrueGCAgeNanos = unsafeKey .Timestamp .WallTime
7581+ // The kv pair is an overwritten value, so it became non-live when the closest more
7582+ // recent value was written.
7583+ ms .GCBytesAge += totalBytes * (nowNanos / 1e9 - accrueGCAgeNanos / 1e9 )
75647584 }
7565- ms .KeyBytes += MVCCVersionTimestampSize
7566- ms .ValBytes += int64 (valueLen )
7567- ms .ValCount ++
7585+ // Update for the next version we may end up looking at.
7586+ accrueGCAgeNanos = unsafeKey .Timestamp .WallTime
75687587 }
75697588 }
75707589
0 commit comments