github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/admission/admissionpb/io_threshold.go (about)

     1  // Copyright 2022 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package admissionpb
    12  
    13  import (
    14  	"math"
    15  
    16  	"github.com/cockroachdb/redact"
    17  	"github.com/cockroachdb/redact/interfaces"
    18  )
    19  
    20  // Score returns, as the second return value, whether IO admission control is
    21  // considering the Store overloaded wrt compaction of L0. The first return
    22  // value is a 1-normalized float (i.e. 1.0 is the threshold at which the
    23  // second value flips to true).
    24  //
    25  // The zero value returns (0, false). Use of the nil pointer is not allowed.
    26  //
    27  // TODO(sumeer): consider whether we need to enhance this to incorporate
    28  // overloading via flush bandwidth. I suspect we can get away without
    29  // incorporating flush bandwidth since typically chronic overload will be due
    30  // to compactions falling behind (though that may change if we increase the
    31  // max number of compactions). And we will need to incorporate overload due to
    32  // disk bandwidth bottleneck.
    33  func (iot *IOThreshold) Score() (float64, bool) {
    34  	// iot.L0NumFilesThreshold and iot.L0NumSubLevelsThreshold are initialized to
    35  	// 0 by default, and there appears to be a period of time before we update
    36  	// iot.L0NumFilesThreshold and iot.L0NumSubLevelsThreshold to their
    37  	// appropriate values. During this period of time, to prevent dividing by 0
    38  	// below and Score() returning NaN, we check if iot.L0NumFilesThreshold or
    39  	// iot.L0NumSubLevelsThreshold are 0 (i.e. currently uninitialized) and
    40  	// return 0 as the score if so.
    41  	if iot == nil || iot.L0NumFilesThreshold == 0 || iot.L0NumSubLevelsThreshold == 0 {
    42  		return 0, false
    43  	}
    44  	numSubLevels := iot.L0NumSubLevels
    45  	if iot.L0MinimumSizePerSubLevel > 0 {
    46  		// Upper-bound on number of sub-levels. See the comment for the cluster
    47  		// setting admission.l0_sub_level_count_overload_threshold.
    48  		maxNumSubLevels := int64(math.Round(float64(iot.L0Size) / float64(iot.L0MinimumSizePerSubLevel)))
    49  		// Say numSubLevels is 30 and maxNumSubLevels is 5. We don't want to
    50  		// ignore the huge disparity, since that could allow the numSubLevels to
    51  		// grow to a huge value. So we place a lower-bound. The divisor of 3 was
    52  		// chosen somewhat arbitrarily.
    53  		//
    54  		// NB: the lower-bound can be greater than the upper-bound, in which case
    55  		// the lower-bound takes precedence.
    56  		minNumSubLevels := numSubLevels / 3
    57  		if numSubLevels > maxNumSubLevels {
    58  			numSubLevels = maxNumSubLevels
    59  		}
    60  		if numSubLevels < minNumSubLevels {
    61  			numSubLevels = minNumSubLevels
    62  		}
    63  	}
    64  	f := math.Max(
    65  		float64(iot.L0NumFiles)/float64(iot.L0NumFilesThreshold),
    66  		float64(numSubLevels)/float64(iot.L0NumSubLevelsThreshold),
    67  	)
    68  	return f, f > 1.0
    69  }
    70  
    71  // SafeFormat implements redact.SafeFormatter.
    72  func (iot *IOThreshold) SafeFormat(s interfaces.SafePrinter, _ rune) {
    73  	if iot == nil {
    74  		s.Printf("N/A")
    75  		return
    76  	}
    77  	sc, overload := iot.Score()
    78  	s.Printf("%.3f", redact.SafeFloat(sc))
    79  	if overload {
    80  		s.Printf("[L0-overload]")
    81  	}
    82  }
    83  
    84  func (iot *IOThreshold) String() string {
    85  	return redact.StringWithoutMarkers(iot)
    86  }