// Copyright 2015 CoreOS, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package stats import ( "sync" "time" ) const ( queueCapacity = 200 ) // RequestStats represent the stats for a request. // It encapsulates the sending time and the size of the request. type RequestStats struct { SendingTime time.Time Size int } type statsQueue struct { items [queueCapacity]*RequestStats size int front int back int totalReqSize int rwl sync.RWMutex } func (q *statsQueue) Len() int { return q.size } func (q *statsQueue) ReqSize() int { return q.totalReqSize } // FrontAndBack gets the front and back elements in the queue // We must grab front and back together with the protection of the lock func (q *statsQueue) frontAndBack() (*RequestStats, *RequestStats) { q.rwl.RLock() defer q.rwl.RUnlock() if q.size != 0 { return q.items[q.front], q.items[q.back] } return nil, nil } // Insert function insert a RequestStats into the queue and update the records func (q *statsQueue) Insert(p *RequestStats) { q.rwl.Lock() defer q.rwl.Unlock() q.back = (q.back + 1) % queueCapacity if q.size == queueCapacity { //dequeue q.totalReqSize -= q.items[q.front].Size q.front = (q.back + 1) % queueCapacity } else { q.size++ } q.items[q.back] = p q.totalReqSize += q.items[q.back].Size } // Rate function returns the package rate and byte rate func (q *statsQueue) Rate() (float64, float64) { front, back := q.frontAndBack() if front == nil || back == nil { return 0, 0 } if time.Now().Sub(back.SendingTime) > time.Second { q.Clear() return 0, 0 } sampleDuration := back.SendingTime.Sub(front.SendingTime) pr := float64(q.Len()) / float64(sampleDuration) * float64(time.Second) br := float64(q.ReqSize()) / float64(sampleDuration) * float64(time.Second) return pr, br } // Clear function clear up the statsQueue func (q *statsQueue) Clear() { q.rwl.Lock() defer q.rwl.Unlock() q.back = -1 q.front = 0 q.size = 0 q.totalReqSize = 0 }