cache performance enhancement

This commit is contained in:
Todd Gruben 2017-03-01 15:14:00 -06:00 committed by Travis
parent 283dfef1d9
commit cabe0fef24
3 changed files with 75 additions and 17 deletions

View file

@ -16,6 +16,8 @@ type Bitmap struct {
// Attributes associated with the bitmap.
Attrs map[string]interface{}
cacheoveride uint64
}
// NewBitmap returns a new instance of Bitmap.
@ -174,6 +176,26 @@ func (b *Bitmap) InvalidateCount() {
}
}
//increment the bitmap cached counter, note this is an optimization that assumes that the caller is aware the size increased
func (b *Bitmap) IncrementCount(i uint64) {
seg := b.segment(i / SliceWidth)
if seg != nil {
seg.n++
}
}
func (b *Bitmap) DecrementCount(i uint64) {
seg := b.segment(i / SliceWidth)
if seg != nil {
if seg.n > 0 {
seg.n--
}
}
}
func (b *Bitmap) SetCount(i uint64, count uint64) {
seg := b.segment(i / SliceWidth)
seg.n = count
}
// Count returns the number of set bits in the bitmap.
func (b *Bitmap) Count() uint64 {
var n uint64
@ -312,7 +334,6 @@ func (s *BitmapSegment) Difference(other *BitmapSegment) *BitmapSegment {
// SetBit sets the i-th bit of the bitmap.
func (s *BitmapSegment) SetBit(i uint64) (changed bool) {
s.ensureWritable()
changed, _ = s.data.Add(i)
if changed {
s.n++

View file

@ -5,6 +5,7 @@ import (
"fmt"
"io"
"sort"
"sync"
"time"
"github.com/golang/groupcache/lru"
@ -97,6 +98,7 @@ var _ Cache = &LRUCache{}
// RankCache represents a cache with sorted entries.
type RankCache struct {
mu sync.Mutex
entries map[uint64]uint64
rankings []BitmapPair // cached, ordered list
@ -117,6 +119,8 @@ func NewRankCache() *RankCache {
// Add adds a bitmap to the cache.
func (c *RankCache) Add(bitmapID uint64, n uint64) {
c.mu.Lock()
defer c.mu.Unlock()
// Ignore if the bit count on the bitmap is below the threshold.
if n < c.ThresholdValue {
return
@ -124,19 +128,13 @@ func (c *RankCache) Add(bitmapID uint64, n uint64) {
c.entries[bitmapID] = n
c.Invalidate()
// If size is larger than the threshold then trim it.
if len(c.entries) > c.ThresholdLength {
for id, n := range c.entries {
if n <= c.ThresholdValue {
delete(c.entries, id)
}
}
}
c.invalidate()
}
// BulkAdd adds a bitmap to the cache unsorted. You should Invalidate after completion.
func (c *RankCache) BulkAdd(bitmapID uint64, n uint64) {
c.mu.Lock()
defer c.mu.Unlock()
if n < c.ThresholdValue {
return
}
@ -145,13 +143,23 @@ func (c *RankCache) BulkAdd(bitmapID uint64, n uint64) {
}
// Get returns a bitmap with a given id.
func (c *RankCache) Get(bitmapID uint64) uint64 { return c.entries[bitmapID] }
func (c *RankCache) Get(bitmapID uint64) uint64 {
c.mu.Lock()
defer c.mu.Unlock()
return c.entries[bitmapID]
}
// Len returns the number of items in the cache.
func (c *RankCache) Len() int { return len(c.entries) }
func (c *RankCache) Len() int {
c.mu.Lock()
defer c.mu.Unlock()
return len(c.entries)
}
// BitmapIDs returns a list of all bitmap IDs in the cache.
func (c *RankCache) BitmapIDs() []uint64 {
c.mu.Lock()
defer c.mu.Unlock()
a := make([]uint64, 0, len(c.entries))
for id := range c.entries {
a = append(a, id)
@ -162,6 +170,15 @@ func (c *RankCache) BitmapIDs() []uint64 {
// update reorders the entries by rank.
func (c *RankCache) Invalidate() {
c.mu.Lock()
defer c.mu.Unlock()
c.invalidate()
}
func (c *RankCache) invalidate() {
if time.Now().Sub(c.updateTime).Seconds() < 10 {
return
}
//fmt.Println("RankCache Update")
// Convert cache to a sorted list.
rankings := make([]BitmapPair, 0, len(c.entries))
@ -183,6 +200,14 @@ func (c *RankCache) Invalidate() {
// Reset counters.
c.updateTime, c.updateN = time.Now(), 0
// If size is larger than the threshold then trim it.
if len(c.entries) > c.ThresholdLength {
for id, n := range c.entries {
if n <= c.ThresholdValue {
delete(c.entries, id)
}
}
}
}
// Top returns an ordered list of bitmaps.

View file

@ -351,8 +351,10 @@ func (f *Fragment) bitmap(bitmapID uint64, updateCache bool) *Bitmap {
slice: f.slice,
writable: false,
}},
cacheoveride: 0,
}
bm.InvalidateCount()
bm.cacheoveride = bm.Count()
if updateCache {
// Update cache.
@ -380,6 +382,7 @@ func (f *Fragment) setBit(bitmapID, profileID uint64) (changed bool, bool error)
}
// Write to storage.
if changed, err = f.storage.Add(pos); err != nil {
return false, err
}
@ -399,8 +402,13 @@ func (f *Fragment) setBit(bitmapID, profileID uint64) (changed bool, bool error)
// Update the cache.
bm := f.bitmap(bitmapID, true)
bm.SetBit(profileID)
bm.InvalidateCount() //maybe a perf opportunity?
if bm.cacheoveride > 0 {
bm.SetCount(profileID, bm.cacheoveride)
bm.cacheoveride = 0
} else {
bm.IncrementCount(profileID)
}
f.cache.Add(bitmapID, bm.Count())
f.stats.Count("setN", 1)
@ -443,9 +451,13 @@ func (f *Fragment) clearBit(bitmapID, profileID uint64) (bool, error) {
}
// Update the cache.
bm := f.bitmap(bitmapID, true)
bm.ClearBit(profileID)
bm.InvalidateCount() //maybe a perf opportunity?
bm := f.bitmap(bitmapID, false)
if bm.cacheoveride > 0 {
bm.SetCount(profileID, bm.cacheoveride)
bm.cacheoveride = 0
} else {
bm.DecrementCount(profileID)
}
f.cache.Add(bitmapID, bm.Count())
f.stats.Count("clearN", 1)