From 0973c854d6d8ed68426bd609cf2b6eb12b79b5ef Mon Sep 17 00:00:00 2001 From: "Tim St. Clair" Date: Mon, 25 Apr 2016 16:09:42 -0700 Subject: [PATCH] Optimize TimedStore to avoid sort on every data add --- utils/timed_store.go | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/utils/timed_store.go b/utils/timed_store.go index 372ff095..321df096 100644 --- a/utils/timed_store.go +++ b/utils/timed_store.go @@ -58,19 +58,23 @@ func NewTimedStore(age time.Duration, maxItems int) *TimedStore { // Adds an element to the start of the buffer (removing one from the end if necessary). func (self *TimedStore) Add(timestamp time.Time, item interface{}) { - // Remove any elements if over our max size. - if self.maxItems >= 0 && (len(self.buffer)+1) > self.maxItems { - startIndex := len(self.buffer) + 1 - self.maxItems - self.buffer = self.buffer[startIndex:] - } - // Add the new element first and sort. We can then remove an expired element, if required. - copied := item - self.buffer = append(self.buffer, timedStoreData{ + data := timedStoreData{ timestamp: timestamp, - data: copied, - }) + data: item, + } + // Common case: data is added in order. + if len(self.buffer) == 0 || !timestamp.Before(self.buffer[len(self.buffer)-1].timestamp) { + self.buffer = append(self.buffer, data) + } else { + // Data is out of order; insert it in the correct position. + index := sort.Search(len(self.buffer), func(index int) bool { + return self.buffer[index].timestamp.After(timestamp) + }) + self.buffer = append(self.buffer, timedStoreData{}) // Make room to shift the elements + copy(self.buffer[index+1:], self.buffer[index:]) // Shift the elements over + self.buffer[index] = data + } - sort.Sort(self.buffer) // Remove any elements before eviction time. // TODO(rjnagal): This is assuming that the added entry has timestamp close to now. evictTime := timestamp.Add(-self.age) @@ -81,6 +85,11 @@ func (self *TimedStore) Add(timestamp time.Time, item interface{}) { self.buffer = self.buffer[index:] } + // Remove any elements if over our max size. + if self.maxItems >= 0 && len(self.buffer) > self.maxItems { + startIndex := len(self.buffer) - self.maxItems + self.buffer = self.buffer[startIndex:] + } } // Returns up to maxResult elements in the specified time period (inclusive).