Skip to content

Commit

Permalink
performance enhancement
Browse files Browse the repository at this point in the history
  • Loading branch information
LeeGunhee committed Jun 30, 2021
1 parent cf7bc37 commit 2157586
Show file tree
Hide file tree
Showing 6 changed files with 458 additions and 27 deletions.
125 changes: 125 additions & 0 deletions scouterx/common/structure/cachemap2/cachemap2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package cachemap2

import (
"github.com/emirpasic/gods/lists/singlylinkedlist"
"strconv"
"sync"
"time"
)

var lock sync.RWMutex
var once sync.Once

type CacheMap struct {
table map[interface{}]interface{}
ordering *singlylinkedlist.List
orderPos map[interface{}]int
maxSize int
}

func (m *CacheMap) GetValues() []interface{} {
l := make([]interface{}, 0, int(float32(len(m.table)) * 1.2))
lock.RLock()
defer lock.RUnlock()
for _, v := range m.table {
lock.RUnlock()
if v != nil {
l = append(l, v)
}
lock.RLock()
}
return l
}

func New(maxSize int) *CacheMap {
m := &CacheMap{
table: make(map[interface{}]interface{}),
ordering: singlylinkedlist.New(),
orderPos: make(map[interface{}]int),
maxSize: maxSize,
}
once.Do(func() {
go func() {
for {
if m.ordering.Size() > m.maxSize/2 {
time.Sleep(500 * time.Millisecond)
//TODO
} else {
time.Sleep(100 * time.Millisecond)
//TODO
}
}
}()
})
return m
}

func (m *CacheMap) Add(key interface{}, item interface{}) {
lock.Lock()
defer lock.Unlock()
if _, contains := m.table[key]; !contains {
m.removeExceeded()
m.table[key] = item
m.ordering.Append(key)
m.orderPos[key] = m.ordering.Size() - 1
}
}

func (m *CacheMap) Remove(key interface{}) {
lock.Lock()
defer lock.Unlock()
delete(m.table, key)
//index, contains := m.orderPos[key]
//if contains {
// m.ordering.Remove(index)
// delete(m.orderPos, key)
//}
}

func (m *CacheMap) removeExceeded() {
for m.ordering.Size() >= m.maxSize {
key, exist := m.ordering.Get(0)
if exist {
m.ordering.Remove(0)
delete(m.orderPos, key)
delete(m.table, key)
}
}
}

func (m *CacheMap) Contains(key interface{}) bool {
lock.RLock()
defer lock.RUnlock()
if _, contains := m.table[key]; !contains {
return false
}
return true
}

func (m *CacheMap) Get(key interface{}) interface{} {
lock.RLock()
defer lock.RUnlock()
return m.table[key]
}

func (m *CacheMap) Empty() bool {
lock.Lock()
defer lock.Unlock()
return m.Size() == 0
}

func (m *CacheMap) Size() int {
return m.ordering.Size()
}

func (m *CacheMap) Clear() {
lock.Lock()
defer lock.Unlock()
m.table = make(map[interface{}]interface{})
m.ordering.Clear()
m.orderPos = make(map[interface{}]int)
}

func (m *CacheMap) String() string {
return "CacheMap[" + strconv.Itoa(m.ordering.Size()) + "]"
}
85 changes: 85 additions & 0 deletions scouterx/common/structure/cachemap2/cachemap2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package cachemap2

import (
"strconv"
"testing"
)

func TestCacheSet(t *testing.T) {
cacheMap := New(10)

//add "1" to "9"
for i := 0; i < 10; i++ {
cacheMap.Add(i, strconv.Itoa(i))
}

if cacheMap.Size() != 10 {
t.Error("size error.")
}

//max size preserved
cacheMap.Add(3, "3")
if cacheMap.Size() != 10 {
t.Error("size error.")
}

//0 exist
if (!cacheMap.Contains(0)) {
t.Error("contains error.")
}

//0 removed
cacheMap.Add(1000, "1000")
if cacheMap.Size() != 10 {
t.Error("size error.")
}

if cacheMap.Contains(0) {
t.Error("contains error: 0 was removed.")
}

//1 exist
if !cacheMap.Contains(1) {
t.Error("contains error: 1 should be exist.")
}

//1 removed
cacheMap.Add(1001, "1001")
if cacheMap.Size() != 10 {
t.Error("size error.")
}

if cacheMap.Contains(1) {
t.Error("contains error: 1 was removed.")
}

if !cacheMap.Contains(1001) {
t.Error("contains error: 1001 should be exist.")
}

if cacheMap.Get(1001) != "1001" {
t.Error("no matched value.")
}
}

//func TestValues(t *testing.T) {
// cacheMap := New(9000)
//
// go func() {
// for {
// time.Sleep(10 * time.Nanosecond)
// rand := rand.Intn(30000)
// cacheMap.Add(rand, rand)
// }
// }()
//
// go func() {
// for {
// values := cacheMap.GetValues()
// fmt.Println(strconv.Itoa(len(values)))
// time.Sleep(10 * time.Millisecond)
// }
// }()
//
// time.Sleep(2000 * time.Millisecond)
//}
136 changes: 136 additions & 0 deletions scouterx/common/structure/lra/lra.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package lra

import (
"container/list"
"sync"
)

var lock sync.RWMutex
var itemExists = struct{}{}

type Cache struct {
MaxEntries int
OnEvicted func(key Key, value interface{})

lst *list.List
table map[interface{}]*list.Element
}

type Key interface{}

type entry struct {
key Key
value interface{}
}

func New(maxEntries int) *Cache {
return &Cache{
MaxEntries: maxEntries,
lst: list.New(),
table: make(map[interface{}]*list.Element),
}
}

func (c *Cache) AddKey(key Key) {
c.Add(key, itemExists)
}

func (c *Cache) Add(key Key, value interface{}) {
lock.Lock()
defer lock.Unlock()
if ee, ok := c.table[key]; ok {
ee.Value.(*entry).value = value
return
}
ele := c.lst.PushFront(&entry{key, value})
c.table[key] = ele
if c.MaxEntries != 0 && c.lst.Len() > c.MaxEntries {
c.removeOldest()
}
}

// Get looks up a key's value from the cache.
func (c *Cache) Get(key Key) interface{} {
lock.RLock()
defer lock.RUnlock()
if ele, contains := c.table[key]; contains {
return ele.Value.(*entry).value
}
return nil
}

func (c *Cache) Contains(key interface{}) bool {
lock.RLock()
defer lock.RUnlock()
if _, contains := c.table[key]; !contains {
return false
}
return true
}

func (c *Cache) Empty() bool {
lock.RLock()
defer lock.RUnlock()
return c.Size() == 0
}


func (c *Cache) Remove(key Key) {
lock.Lock()
defer lock.Unlock()
if ele, hit := c.table[key]; hit {
c.removeElement(ele)
}
}

func (c *Cache) removeOldest() {
ele := c.lst.Back()
if ele != nil {
c.removeElement(ele)
}
}

func (c *Cache) removeElement(e *list.Element) {
c.lst.Remove(e)
kv := e.Value.(*entry)
delete(c.table, kv.key)
if c.OnEvicted != nil {
c.OnEvicted(kv.key, kv.value)
}
}

func (c *Cache) Size() int {
lock.RLock()
defer lock.RUnlock()
return c.lst.Len()
}

func (c *Cache) Clear() {
lock.Lock()
defer lock.Unlock()
if c.OnEvicted != nil {
for _, e := range c.table {
kv := e.Value.(*entry)
c.OnEvicted(kv.key, kv.value)
}
}
c.lst = nil
c.table = nil
}

func (c *Cache) GetValues() []interface{} {
l := make([]interface{}, 0, int(float32(c.lst.Len()) * 1.2))
lock.RLock()
defer lock.RUnlock()
for _, e := range c.table {
lock.RUnlock()
if e != nil {
kv := e.Value.(*entry)
if kv != nil && kv.value != nil {
l = append(l, kv.value)
}
}
lock.RLock()
}
return l
}
Loading

0 comments on commit 2157586

Please sign in to comment.