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  }