github.com/haraldrudell/parl@v0.4.176/counter/cached-counters.go (about)

     1  /*
     2  © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package counter
     7  
     8  import (
     9  	"github.com/haraldrudell/parl"
    10  	"github.com/haraldrudell/parl/perrors"
    11  )
    12  
    13  // CachedCounters reduces counter map contention by only looking up the counterID once
    14  type CachedCounters struct {
    15  	counterStore      parl.CounterStore                         // uncached counters accessible by ID
    16  	counterValues     map[parl.CounterID]parl.CounterValues     // cached regular counters
    17  	rateCounterValues map[parl.CounterID]parl.RateCounterValues // cached rate counters
    18  	datapointValue    map[parl.CounterID]parl.DatapointValue    // cached datapoints
    19  }
    20  
    21  // NewCachedCounters returns a cache of parl.CounterID reducing map contention
    22  func NewCachedCounters(counterStore parl.CounterStore) (cachedCounters *CachedCounters) {
    23  	return &CachedCounters{
    24  		counterStore:      counterStore,
    25  		counterValues:     make(map[parl.CounterID]parl.CounterValues),
    26  		rateCounterValues: make(map[parl.CounterID]parl.RateCounterValues),
    27  		datapointValue:    make(map[parl.CounterID]parl.DatapointValue),
    28  	}
    29  }
    30  
    31  // CounterValues never returns nil
    32  //   - returns consumer interface for regular counter: Get and Value methods
    33  func (c *CachedCounters) CounterValues(counterID parl.CounterID) (counterValues parl.CounterValues) {
    34  
    35  	// try cached value
    36  	if counterValues = c.counterValues[counterID]; counterValues != nil {
    37  		return
    38  	}
    39  
    40  	// populate cache
    41  
    42  	// counter is the provider interface of a regular counter,
    43  	// what is returned by GetOrCreateCounter
    44  	var counter = c.counterStore.GetCounter(counterID)
    45  	counterValues = counter.(parl.CounterValues)
    46  	c.counterValues[counterID] = counterValues
    47  
    48  	return
    49  }
    50  
    51  // RateCounter may return nil
    52  //   - returns consumer interface for rate counter: Get Value Rates methods
    53  func (c *CachedCounters) RateCounter(counterID parl.CounterID) (rateCounterValues parl.RateCounterValues) {
    54  
    55  	// try cached value
    56  	if rateCounterValues = c.rateCounterValues[counterID]; rateCounterValues != nil {
    57  		return
    58  	}
    59  
    60  	// populate cache
    61  	var counterAny any
    62  	var ok bool
    63  	if counterAny = c.counterStore.GetNamedCounter(counterID); counterAny == nil {
    64  		return
    65  	} else if rateCounterValues, ok = counterAny.(parl.RateCounterValues); !ok {
    66  		panic(perrors.ErrorfPF("not a rate counter: counter ID: %s type: %T", counterID, counterAny))
    67  	}
    68  	c.rateCounterValues[counterID] = rateCounterValues
    69  
    70  	return
    71  }
    72  
    73  // RateCounter may return nil
    74  //   - returns consumer interface for rate counter: Get Value Rates methods
    75  func (c *CachedCounters) DataPoint(counterID parl.CounterID) (datapointValue parl.DatapointValue) {
    76  
    77  	// try cached value
    78  	if datapointValue = c.datapointValue[counterID]; datapointValue != nil {
    79  		return
    80  	}
    81  
    82  	// populate cache
    83  	var counterAny any
    84  	var ok bool
    85  	if counterAny = c.counterStore.GetNamedCounter(counterID); counterAny == nil {
    86  		return
    87  	} else if datapointValue, ok = counterAny.(parl.DatapointValue); !ok {
    88  		panic(perrors.ErrorfPF("not a datapoint: counter ID: %s type: %t", counterID, counterAny))
    89  	}
    90  	c.datapointValue[counterID] = datapointValue
    91  
    92  	return
    93  }