dubbo.apache.org/dubbo-go/v3@v3.1.1/metrics/util/aggregate/sliding_window.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 // SlidingWindow adopts sliding window algorithm for statistics. 21 // 22 // It is NOT concurrent-safe. 23 // A window contains paneCount panes. 24 // intervalInMs = paneCount * paneIntervalInMs. 25 type slidingWindow struct { 26 paneCount int 27 intervalInMs int64 28 paneIntervalInMs int64 29 paneSlice []*pane 30 } 31 32 func newSlidingWindow(paneCount int, intervalInMs int64) *slidingWindow { 33 return &slidingWindow{ 34 paneCount: paneCount, 35 intervalInMs: intervalInMs, 36 paneIntervalInMs: intervalInMs / int64(paneCount), 37 paneSlice: make([]*pane, paneCount), 38 } 39 } 40 41 // values get all values from the slidingWindow's paneSlice. 42 func (s *slidingWindow) values(timeMillis int64) []interface{} { 43 if timeMillis < 0 { 44 return make([]interface{}, 0) 45 } 46 47 res := make([]interface{}, 0, s.paneCount) 48 49 for _, p := range s.paneSlice { 50 if p == nil || s.isPaneDeprecated(p, timeMillis) { 51 continue 52 } 53 res = append(res, p.value) 54 } 55 56 return res 57 } 58 59 // isPaneDeprecated checks if the specified pane is deprecated at the specified timeMillis 60 func (s *slidingWindow) isPaneDeprecated(pane *pane, timeMillis int64) bool { 61 return timeMillis-pane.startInMs > s.intervalInMs 62 } 63 64 // currentPane get the pane at the specified timestamp or create a new one if the pane is deprecated. 65 func (s *slidingWindow) currentPane(timeMillis int64, newEmptyValue func() interface{}) *pane { 66 if timeMillis < 0 { 67 return nil 68 } 69 paneIdx := s.calcPaneIdx(timeMillis) 70 paneStart := s.calcPaneStart(timeMillis) 71 72 if s.paneSlice[paneIdx] == nil { 73 p := newPane(s.paneIntervalInMs, paneStart, newEmptyValue()) 74 s.paneSlice[paneIdx] = p 75 return p 76 } else { 77 p := s.paneSlice[paneIdx] 78 if paneStart == p.startInMs { 79 return p 80 } else if paneStart > p.startInMs { 81 // The pane has deprecated. To avoid the overhead of creating a new instance, reset the original pane directly. 82 p.resetTo(paneStart, newEmptyValue()) 83 return p 84 } else { 85 // The specified timestamp has passed. 86 return newPane(s.paneIntervalInMs, paneStart, newEmptyValue()) 87 } 88 } 89 } 90 91 func (s *slidingWindow) calcPaneIdx(timeMillis int64) int { 92 return int(timeMillis/s.paneIntervalInMs) % s.paneCount 93 } 94 95 func (s *slidingWindow) calcPaneStart(timeMillis int64) int64 { 96 return timeMillis - timeMillis%s.paneIntervalInMs 97 }