github.com/aaabigfish/gopkg@v1.1.0/cache/lrucache/synccache.go (about) 1 package lrucache 2 3 import ( 4 "hash/crc32" 5 "sync" 6 "time" 7 ) 8 9 // hashCode hashes a string to a unique hashcode. 10 // 11 // crc32 returns a uint32, but for our use we need 12 // and non negative integer. Here we cast to an integer 13 // and invert it if the result is negative. 14 func hashCode(s string) (hc int) { 15 hc = int(crc32.ChecksumIEEE([]byte(s))) 16 if hc >= 0 { 17 return hc 18 } 19 if -hc >= 0 { 20 return -hc 21 } 22 // hc == MinInt 23 return hc 24 } 25 26 // SyncCache - concurrent cache structure 27 type SyncCache struct { 28 locks []sync.Mutex 29 caches []*LRUCache 30 mask int 31 timeout int64 32 } 33 34 type scValue struct { 35 Value interface{} 36 ts int64 37 } 38 39 func nextPowOf2(cap int) int { 40 if cap < 2 { 41 return 2 42 } 43 if cap&(cap-1) == 0 { 44 return cap 45 } 46 cap |= cap >> 1 47 cap |= cap >> 2 48 cap |= cap >> 4 49 cap |= cap >> 8 50 cap |= cap >> 16 51 return cap + 1 52 } 53 54 // NewSyncCache - create sync cache 55 // `capacity` is lru cache length of each bucket 56 // store `capacity * bucket` count of element in SyncCache at most 57 // `timeout` is in seconds 58 func NewSyncCache(capacity int, bucket int, timeout int64) *SyncCache { 59 size := nextPowOf2(bucket) 60 sc := SyncCache{make([]sync.Mutex, size), make([]*LRUCache, size), size - 1, timeout} 61 for i := range sc.caches { 62 sc.caches[i] = New(capacity) 63 } 64 return &sc 65 } 66 67 // Put - put a cache item into sync cache 68 func (sc *SyncCache) Put(key string, value interface{}) { 69 idx := hashCode(key) & sc.mask 70 sc.locks[idx].Lock() 71 sc.caches[idx].Put(key, &scValue{value, time.Now().Unix()}) 72 sc.locks[idx].Unlock() 73 } 74 75 // Get - get value of key from sync cache with result 76 func (sc *SyncCache) Get(key string) (interface{}, bool) { 77 idx := hashCode(key) & sc.mask 78 sc.locks[idx].Lock() 79 v, b := sc.caches[idx].Get(key) 80 if !b { 81 sc.locks[idx].Unlock() 82 return nil, false 83 } 84 if time.Now().Unix()-v.(*scValue).ts >= sc.timeout { 85 sc.caches[idx].Delete(key) 86 sc.locks[idx].Unlock() 87 return nil, false 88 } 89 sc.locks[idx].Unlock() 90 return v.(*scValue).Value, b 91 } 92 93 // Delete - delete item by key from sync cache 94 func (sc *SyncCache) Delete(key string) { 95 idx := hashCode(key) & sc.mask 96 sc.locks[idx].Lock() 97 sc.caches[idx].Delete(key) 98 sc.locks[idx].Unlock() 99 }