github.com/wangyougui/gf/v2@v2.6.5/os/gcache/gcache_adapter_memory_data.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package gcache 8 9 import ( 10 "context" 11 "github.com/wangyougui/gf/v2/util/gconv" 12 "regexp" 13 "sync" 14 "time" 15 16 "github.com/wangyougui/gf/v2/os/gtime" 17 ) 18 19 type adapterMemoryData struct { 20 mu sync.RWMutex // dataMu ensures the concurrent safety of underlying data map. 21 data map[interface{}]adapterMemoryItem // data is the underlying cache data which is stored in a hash table. 22 } 23 24 func newAdapterMemoryData() *adapterMemoryData { 25 return &adapterMemoryData{ 26 data: make(map[interface{}]adapterMemoryItem), 27 } 28 } 29 30 // Update updates the value of `key` without changing its expiration and returns the old value. 31 // The returned value `exist` is false if the `key` does not exist in the cache. 32 // 33 // It deletes the `key` if given `value` is nil. 34 // It does nothing if `key` does not exist in the cache. 35 func (d *adapterMemoryData) Update(key interface{}, value interface{}) (oldValue interface{}, exist bool, err error) { 36 d.mu.Lock() 37 defer d.mu.Unlock() 38 if item, ok := d.data[key]; ok { 39 d.data[key] = adapterMemoryItem{ 40 v: value, 41 e: item.e, 42 } 43 return item.v, true, nil 44 } 45 return nil, false, nil 46 } 47 48 // UpdateExpire updates the expiration of `key` and returns the old expiration duration value. 49 // 50 // It returns -1 and does nothing if the `key` does not exist in the cache. 51 // It deletes the `key` if `duration` < 0. 52 func (d *adapterMemoryData) UpdateExpire(key interface{}, expireTime int64) (oldDuration time.Duration, err error) { 53 d.mu.Lock() 54 defer d.mu.Unlock() 55 if item, ok := d.data[key]; ok { 56 d.data[key] = adapterMemoryItem{ 57 v: item.v, 58 e: expireTime, 59 } 60 return time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil 61 } 62 return -1, nil 63 } 64 65 // Remove deletes the one or more keys from cache, and returns its value. 66 // If multiple keys are given, it returns the value of the deleted last item. 67 func (d *adapterMemoryData) Remove(keys ...interface{}) (removedKeys []interface{}, value interface{}, err error) { 68 d.mu.Lock() 69 defer d.mu.Unlock() 70 removedKeys = make([]interface{}, 0) 71 for _, key := range keys { 72 item, ok := d.data[key] 73 if ok { 74 value = item.v 75 delete(d.data, key) 76 removedKeys = append(removedKeys, key) 77 } 78 } 79 return removedKeys, value, nil 80 } 81 82 // Data returns a copy of all key-value pairs in the cache as map type. 83 func (d *adapterMemoryData) Data() (map[interface{}]interface{}, error) { 84 d.mu.RLock() 85 m := make(map[interface{}]interface{}, len(d.data)) 86 for k, v := range d.data { 87 if !v.IsExpired() { 88 m[k] = v.v 89 } 90 } 91 d.mu.RUnlock() 92 return m, nil 93 } 94 95 // Keys returns all keys in the cache as slice. 96 func (d *adapterMemoryData) Keys(regexps ...string) ([]interface{}, error) { 97 d.mu.RLock() 98 var ( 99 index = 0 100 keys = make([]interface{}, len(d.data)) 101 ) 102 for k, v := range d.data { 103 matched := true 104 for _, reg := range regexps { 105 if flag, _ := regexp.MatchString(reg, gconv.String(k)); !flag { 106 matched = false 107 } 108 } 109 if !v.IsExpired() && matched { 110 keys[index] = k 111 index++ 112 } 113 } 114 d.mu.RUnlock() 115 return keys, nil 116 } 117 118 // Values returns all values in the cache as slice. 119 func (d *adapterMemoryData) Values() ([]interface{}, error) { 120 d.mu.RLock() 121 var ( 122 index = 0 123 values = make([]interface{}, len(d.data)) 124 ) 125 for _, v := range d.data { 126 if !v.IsExpired() { 127 values[index] = v.v 128 index++ 129 } 130 } 131 d.mu.RUnlock() 132 return values, nil 133 } 134 135 // Size returns the size of the cache. 136 func (d *adapterMemoryData) Size() (size int, err error) { 137 d.mu.RLock() 138 size = len(d.data) 139 d.mu.RUnlock() 140 return size, nil 141 } 142 143 // Clear clears all data of the cache. 144 // Note that this function is sensitive and should be carefully used. 145 func (d *adapterMemoryData) Clear() error { 146 d.mu.Lock() 147 defer d.mu.Unlock() 148 d.data = make(map[interface{}]adapterMemoryItem) 149 return nil 150 } 151 152 func (d *adapterMemoryData) Get(key interface{}) (item adapterMemoryItem, ok bool) { 153 d.mu.RLock() 154 item, ok = d.data[key] 155 d.mu.RUnlock() 156 return 157 } 158 159 func (d *adapterMemoryData) Set(key interface{}, value adapterMemoryItem) { 160 d.mu.Lock() 161 d.data[key] = value 162 d.mu.Unlock() 163 } 164 165 // SetMap batch sets cache with key-value pairs by `data`, which is expired after `duration`. 166 // 167 // It does not expire if `duration` == 0. 168 // It deletes the keys of `data` if `duration` < 0 or given `value` is nil. 169 func (d *adapterMemoryData) SetMap(data map[interface{}]interface{}, expireTime int64) error { 170 d.mu.Lock() 171 for k, v := range data { 172 d.data[k] = adapterMemoryItem{ 173 v: v, 174 e: expireTime, 175 } 176 } 177 d.mu.Unlock() 178 return nil 179 } 180 181 func (d *adapterMemoryData) SetWithLock(ctx context.Context, key interface{}, value interface{}, expireTimestamp int64) (interface{}, error) { 182 d.mu.Lock() 183 defer d.mu.Unlock() 184 var ( 185 err error 186 ) 187 if v, ok := d.data[key]; ok && !v.IsExpired() { 188 return v.v, nil 189 } 190 f, ok := value.(Func) 191 if !ok { 192 // Compatible with raw function value. 193 f, ok = value.(func(ctx context.Context) (value interface{}, err error)) 194 } 195 if ok { 196 if value, err = f(ctx); err != nil { 197 return nil, err 198 } 199 if value == nil { 200 return nil, nil 201 } 202 } 203 d.data[key] = adapterMemoryItem{v: value, e: expireTimestamp} 204 return value, nil 205 } 206 207 func (d *adapterMemoryData) DeleteWithDoubleCheck(key interface{}, force ...bool) { 208 d.mu.Lock() 209 // Doubly check before really deleting it from cache. 210 if item, ok := d.data[key]; (ok && item.IsExpired()) || (len(force) > 0 && force[0]) { 211 delete(d.data, key) 212 } 213 d.mu.Unlock() 214 }