cache.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package hashcache
  15. import (
  16. "crypto/md5"
  17. "crypto/sha1"
  18. "crypto/sha256"
  19. "crypto/sha512"
  20. "sync"
  21. "time"
  22. )
  23. var initTime = time.Time{}
  24. type cacheNode struct {
  25. key string
  26. expire time.Time
  27. value interface{}
  28. }
  29. func (node *cacheNode) reset() {
  30. if !node.expire.IsZero() {
  31. node.key = ""
  32. node.expire = initTime
  33. node.value = nil
  34. }
  35. }
  36. type Cache struct {
  37. table []cacheNode
  38. lock *sync.Mutex
  39. size uint32
  40. defaultTtl time.Duration
  41. }
  42. func NewCache(size uint32, defaultTTL time.Duration) *Cache {
  43. ca := &Cache{table: make([]cacheNode, size), lock: &sync.Mutex{}, size: size, defaultTtl: defaultTTL}
  44. return ca
  45. }
  46. const (
  47. HASH_ALG_MD5 int = iota
  48. HASH_ALG_SHA1
  49. HASH_ALG_SHA256
  50. HASH_ALG_SHA512
  51. )
  52. func bytes2int(b []byte) uint32 {
  53. return ((uint32(b[0]) << 24) | (uint32(b[1]) << 16) | (uint32(b[2]) << 8) | (uint32(b[3])))
  54. }
  55. func checksum(alg int, key string) uint32 {
  56. var hash uint32 = 0
  57. switch alg {
  58. case HASH_ALG_MD5:
  59. v := md5.Sum([]byte(key))
  60. hash = bytes2int(v[0:4])
  61. case HASH_ALG_SHA1:
  62. v := sha1.Sum([]byte(key))
  63. hash = bytes2int(v[0:4])
  64. case HASH_ALG_SHA256:
  65. v := sha256.Sum224([]byte(key))
  66. hash = bytes2int(v[0:4])
  67. case HASH_ALG_SHA512:
  68. v := sha512.Sum512([]byte(key))
  69. hash = bytes2int(v[0:4])
  70. }
  71. return hash
  72. }
  73. func (c *Cache) find(key string) (bool, uint32) {
  74. var idx uint32
  75. now := time.Now()
  76. for _, alg := range []int{HASH_ALG_MD5, HASH_ALG_SHA1, HASH_ALG_SHA256, HASH_ALG_SHA512} {
  77. idx = checksum(alg, key) % c.size
  78. if c.table[idx].key == key {
  79. if c.table[idx].expire.IsZero() || c.table[idx].expire.After(now) {
  80. return true, idx
  81. }
  82. break
  83. }
  84. }
  85. return false, idx
  86. }
  87. func (c *Cache) Get(key string) interface{} {
  88. find, idx := c.find(key)
  89. if find {
  90. return c.table[idx].value
  91. }
  92. return nil
  93. }
  94. func (c *Cache) AtomicGet(key string) interface{} {
  95. c.lock.Lock()
  96. defer c.lock.Unlock()
  97. return c.Get(key)
  98. }
  99. func (c *Cache) Set(key string, val interface{}, expire ...time.Time) {
  100. find, idx := c.find(key)
  101. if !find {
  102. c.table[idx].key = key
  103. }
  104. c.table[idx].value = val
  105. if len(expire) > 0 && !expire[0].IsZero() {
  106. c.table[idx].expire = expire[0]
  107. } else if c.defaultTtl > time.Millisecond {
  108. c.table[idx].expire = time.Now().Add(c.defaultTtl)
  109. } else {
  110. c.table[idx].expire = time.Time{}
  111. }
  112. }
  113. func (c *Cache) AtomicSet(key string, val interface{}) {
  114. c.lock.Lock()
  115. defer c.lock.Unlock()
  116. c.Set(key, val)
  117. }
  118. func (c *Cache) Remove(key string) {
  119. find, idx := c.find(key)
  120. if !find {
  121. return
  122. }
  123. c.table[idx].reset()
  124. }
  125. func (c *Cache) AtomicRemove(key string) {
  126. c.lock.Lock()
  127. defer c.lock.Unlock()
  128. c.Remove(key)
  129. }
  130. func (c *Cache) Invalidate() {
  131. c.lock.Lock()
  132. defer c.lock.Unlock()
  133. for i := range c.table {
  134. c.table[i].reset()
  135. }
  136. }