maybeWidenZeroBucket widens the zero bucket until it includes the existing buckets closest to the zero bucket (which could be two, if an equidistant negative and a positive bucket exists, but usually it's only one bucket to be merged into the new wider zero bucket). h.nativeHistogramMaxZeroThreshold
(hot, cold *histogramCounts)
| 1015 | // include an existing bucket, the method returns false. The caller must have |
| 1016 | // locked h.mtx. |
| 1017 | func (h *histogram) maybeWidenZeroBucket(hot, cold *histogramCounts) bool { |
| 1018 | currentZeroThreshold := math.Float64frombits(atomic.LoadUint64(&hot.nativeHistogramZeroThresholdBits)) |
| 1019 | if currentZeroThreshold >= h.nativeHistogramMaxZeroThreshold { |
| 1020 | return false |
| 1021 | } |
| 1022 | // Find the key of the bucket closest to zero. |
| 1023 | smallestKey := findSmallestKey(&hot.nativeHistogramBucketsPositive) |
| 1024 | smallestNegativeKey := findSmallestKey(&hot.nativeHistogramBucketsNegative) |
| 1025 | if smallestNegativeKey < smallestKey { |
| 1026 | smallestKey = smallestNegativeKey |
| 1027 | } |
| 1028 | if smallestKey == math.MaxInt32 { |
| 1029 | return false |
| 1030 | } |
| 1031 | newZeroThreshold := getLe(smallestKey, atomic.LoadInt32(&hot.nativeHistogramSchema)) |
| 1032 | if newZeroThreshold > h.nativeHistogramMaxZeroThreshold { |
| 1033 | return false // New threshold would exceed the max threshold. |
| 1034 | } |
| 1035 | atomic.StoreUint64(&cold.nativeHistogramZeroThresholdBits, math.Float64bits(newZeroThreshold)) |
| 1036 | // Remove applicable buckets. |
| 1037 | if _, loaded := cold.nativeHistogramBucketsNegative.LoadAndDelete(smallestKey); loaded { |
| 1038 | atomicDecUint32(&cold.nativeHistogramBucketsNumber) |
| 1039 | } |
| 1040 | if _, loaded := cold.nativeHistogramBucketsPositive.LoadAndDelete(smallestKey); loaded { |
| 1041 | atomicDecUint32(&cold.nativeHistogramBucketsNumber) |
| 1042 | } |
| 1043 | // Make cold counts the new hot counts. |
| 1044 | n := atomic.AddUint64(&h.countAndHotIdx, 1<<63) |
| 1045 | count := n & ((1 << 63) - 1) |
| 1046 | // Swap the pointer names to represent the new roles and make |
| 1047 | // the rest less confusing. |
| 1048 | hot, cold = cold, hot |
| 1049 | waitForCooldown(count, cold) |
| 1050 | // Add all the now cold counts to the new hot counts... |
| 1051 | addAndResetCounts(hot, cold) |
| 1052 | // ...adjust the new zero threshold in the cold counts, too... |
| 1053 | atomic.StoreUint64(&cold.nativeHistogramZeroThresholdBits, math.Float64bits(newZeroThreshold)) |
| 1054 | // ...and then merge the newly deleted buckets into the wider zero |
| 1055 | // bucket. |
| 1056 | mergeAndDeleteOrAddAndReset := func(hotBuckets, coldBuckets *sync.Map) func(k, v interface{}) bool { |
| 1057 | return func(k, v interface{}) bool { |
| 1058 | key := k.(int) |
| 1059 | bucket := v.(*int64) |
| 1060 | if key == smallestKey { |
| 1061 | // Merge into hot zero bucket... |
| 1062 | atomic.AddUint64(&hot.nativeHistogramZeroBucket, uint64(atomic.LoadInt64(bucket))) |
| 1063 | // ...and delete from cold counts. |
| 1064 | coldBuckets.Delete(key) |
| 1065 | atomicDecUint32(&cold.nativeHistogramBucketsNumber) |
| 1066 | } else { |
| 1067 | // Add to corresponding hot bucket... |
| 1068 | if addToBucket(hotBuckets, key, atomic.LoadInt64(bucket)) { |
| 1069 | atomic.AddUint32(&hot.nativeHistogramBucketsNumber, 1) |
| 1070 | } |
| 1071 | // ...and reset cold bucket. |
| 1072 | atomic.StoreInt64(bucket, 0) |
| 1073 | } |
| 1074 | return true |
no test coverage detected