dubbo.apache.org/dubbo-go/v3@v3.1.1/metrics/util/aggregate/aggregator.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package aggregate
    19  
    20  import (
    21  	"math"
    22  	"sync"
    23  	"time"
    24  )
    25  
    26  // TimeWindowAggregator wrappers sliding window to aggregate data.
    27  //
    28  // It is concurrent-safe.
    29  // It uses custom struct aggregator to aggregate data.
    30  // The window is divided into several panes, and each pane's value is an aggregator instance.
    31  type TimeWindowAggregator struct {
    32  	window *slidingWindow
    33  	mux    sync.RWMutex
    34  }
    35  
    36  func NewTimeWindowAggregator(paneCount int, timeWindowSeconds int64) *TimeWindowAggregator {
    37  	return &TimeWindowAggregator{
    38  		window: newSlidingWindow(paneCount, timeWindowSeconds*1000),
    39  	}
    40  }
    41  
    42  type Result struct {
    43  	Total float64
    44  	Min   float64
    45  	Max   float64
    46  	Avg   float64
    47  	Count uint64
    48  	Last  float64
    49  }
    50  
    51  func NewResult() *Result {
    52  	return &Result{
    53  		Min:  math.MaxFloat64,
    54  		Max:  math.SmallestNonzeroFloat64,
    55  		Last: math.NaN(),
    56  	}
    57  }
    58  
    59  func (r *Result) Update(v float64) {
    60  	r.Min = math.Min(r.Min, v)
    61  	r.Max = math.Max(r.Max, v)
    62  	r.Last = v
    63  	r.Total += v
    64  	r.Count++
    65  }
    66  
    67  func (r *Result) Merge(o *Result) {
    68  	r.Min = math.Min(r.Min, o.Min)
    69  	r.Max = math.Max(r.Max, o.Max)
    70  	r.Total += o.Total
    71  	r.Count += o.Count
    72  	r.Last = o.Last
    73  }
    74  
    75  func (r *Result) Get() *Result {
    76  	if r.Count > 0 {
    77  		r.Avg = r.Total / float64(r.Count)
    78  	}
    79  	return r
    80  }
    81  
    82  // Result returns the aggregate result of the sliding window by aggregating all panes.
    83  func (t *TimeWindowAggregator) Result() *Result {
    84  	t.mux.RLock()
    85  	defer t.mux.RUnlock()
    86  	res := NewResult()
    87  	for _, v := range t.window.values(time.Now().UnixMilli()) {
    88  		res.Merge(v.(*Result)) // Last not as expect, but agg result has no Last value
    89  	}
    90  	return res.Get()
    91  }
    92  
    93  // Add adds a value to the sliding window's current pane.
    94  func (t *TimeWindowAggregator) Add(v float64) {
    95  	t.mux.Lock()
    96  	defer t.mux.Unlock()
    97  
    98  	t.window.currentPane(time.Now().UnixMilli(), t.newEmptyValue).value.(*Result).Update(v)
    99  }
   100  
   101  func (t *TimeWindowAggregator) newEmptyValue() interface{} {
   102  	return NewResult()
   103  }