github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/store/memory/memory.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); 2 // you may not use this file except in compliance with the License. 3 // You may obtain a copy of the License at 4 // 5 // https://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, 9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 // See the License for the specific language governing permissions and 11 // limitations under the License. 12 // 13 // Original source: github.com/micro/go-micro/v3/store/memory/memory.go 14 15 // Package memory is a in-memory store store 16 package memory 17 18 import ( 19 "path/filepath" 20 "sort" 21 "strings" 22 "sync" 23 "time" 24 25 "github.com/tickoalcantara12/micro/v3/service/store" 26 "github.com/patrickmn/go-cache" 27 "github.com/pkg/errors" 28 ) 29 30 // NewStore returns a memory store 31 func NewStore(opts ...store.Option) store.Store { 32 s := &memoryStore{ 33 options: store.Options{ 34 Database: "micro", 35 Table: "micro", 36 }, 37 stores: map[string]*cache.Cache{}, // cache.New(cache.NoExpiration, 5*time.Minute), 38 } 39 for _, o := range opts { 40 o(&s.options) 41 } 42 return s 43 } 44 45 type memoryStore struct { 46 sync.RWMutex 47 options store.Options 48 49 stores map[string]*cache.Cache 50 } 51 52 type storeRecord struct { 53 key string 54 value []byte 55 metadata map[string]interface{} 56 expiresAt time.Time 57 } 58 59 func (m *memoryStore) prefix(database, table string) string { 60 if len(database) == 0 { 61 database = m.options.Database 62 } 63 if len(table) == 0 { 64 table = m.options.Table 65 } 66 return filepath.Join(database, table) 67 } 68 69 func (m *memoryStore) getStore(prefix string) *cache.Cache { 70 m.RLock() 71 store := m.stores[prefix] 72 m.RUnlock() 73 if store == nil { 74 m.Lock() 75 if m.stores[prefix] == nil { 76 m.stores[prefix] = cache.New(cache.NoExpiration, 5*time.Minute) 77 } 78 store = m.stores[prefix] 79 m.Unlock() 80 } 81 return store 82 } 83 84 func (m *memoryStore) get(prefix, key string) (*store.Record, error) { 85 var storedRecord *storeRecord 86 r, found := m.getStore(prefix).Get(key) 87 if !found { 88 return nil, store.ErrNotFound 89 } 90 91 storedRecord, ok := r.(*storeRecord) 92 if !ok { 93 return nil, errors.New("Retrieved a non *storeRecord from the cache") 94 } 95 96 // Copy the record on the way out 97 newRecord := &store.Record{} 98 newRecord.Key = strings.TrimPrefix(storedRecord.key, prefix+"/") 99 newRecord.Value = make([]byte, len(storedRecord.value)) 100 newRecord.Metadata = make(map[string]interface{}) 101 102 // copy the value into the new record 103 copy(newRecord.Value, storedRecord.value) 104 105 // check if we need to set the expiry 106 if !storedRecord.expiresAt.IsZero() { 107 newRecord.Expiry = time.Until(storedRecord.expiresAt) 108 } 109 110 // copy in the metadata 111 for k, v := range storedRecord.metadata { 112 newRecord.Metadata[k] = v 113 } 114 115 return newRecord, nil 116 } 117 118 func (m *memoryStore) set(prefix string, r *store.Record) { 119 // copy the incoming record and then 120 // convert the expiry in to a hard timestamp 121 i := &storeRecord{} 122 i.key = r.Key 123 i.value = make([]byte, len(r.Value)) 124 i.metadata = make(map[string]interface{}) 125 126 // copy the the value 127 copy(i.value, r.Value) 128 129 // set the expiry 130 if r.Expiry != 0 { 131 i.expiresAt = time.Now().Add(r.Expiry) 132 } 133 134 // set the metadata 135 for k, v := range r.Metadata { 136 i.metadata[k] = v 137 } 138 139 m.getStore(prefix).Set(r.Key, i, r.Expiry) 140 } 141 142 func (m *memoryStore) delete(prefix, key string) { 143 m.getStore(prefix).Delete(key) 144 } 145 146 func (m *memoryStore) list(prefix string, order store.Order, limit, offset uint, prefixFilter, suffixFilter string) []string { 147 // TODO: sort they keys 148 var allItems []string 149 150 for k := range m.getStore(prefix).Items() { 151 allItems = append(allItems, k) 152 } 153 154 // sort in ascending order 155 if order == store.OrderDesc { 156 sort.Slice(allItems, func(i, j int) bool { return allItems[i] > allItems[j] }) 157 } else { 158 sort.Slice(allItems, func(i, j int) bool { return allItems[i] < allItems[j] }) 159 } 160 161 var keys []string 162 163 // filter on prefix and suffix first 164 for i := 0; i < len(allItems); i++ { 165 k := allItems[i] 166 167 if prefixFilter != "" && !strings.HasPrefix(k, prefixFilter) { 168 continue 169 } 170 if suffixFilter != "" && !strings.HasSuffix(k, suffixFilter) { 171 continue 172 } 173 174 keys = append(keys, k) 175 } 176 177 if offset > 0 { 178 // offset is greater than the keys we have 179 if int(offset) >= len(keys) { 180 return nil 181 } 182 183 // otherwise set the offset for the keys 184 keys = keys[offset:] 185 } 186 187 // check key limit 188 if v := int(limit); v == 0 || v > len(keys) { 189 limit = uint(len(keys)) 190 } 191 192 // gen the final key list 193 var keyList []string 194 195 for i := 0; i < int(limit); i++ { 196 keyList = append(keyList, keys[i]) 197 } 198 199 return keyList 200 } 201 202 func (m *memoryStore) Close() error { 203 m.Lock() 204 defer m.Unlock() 205 for _, s := range m.stores { 206 s.Flush() 207 } 208 return nil 209 } 210 211 func (m *memoryStore) Init(opts ...store.Option) error { 212 for _, o := range opts { 213 o(&m.options) 214 } 215 return nil 216 } 217 218 func (m *memoryStore) String() string { 219 return "memory" 220 } 221 222 func (m *memoryStore) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) { 223 readOpts := store.ReadOptions{ 224 Order: store.OrderAsc, 225 } 226 for _, o := range opts { 227 o(&readOpts) 228 } 229 230 prefix := m.prefix(readOpts.Database, readOpts.Table) 231 232 var keys []string 233 // Handle Prefix / suffix 234 if readOpts.Prefix || readOpts.Suffix { 235 prefixFilter := "" 236 if readOpts.Prefix { 237 prefixFilter = key 238 } 239 suffixFilter := "" 240 if readOpts.Suffix { 241 suffixFilter = key 242 } 243 keys = m.list(prefix, readOpts.Order, readOpts.Limit, readOpts.Offset, prefixFilter, suffixFilter) 244 } else { 245 keys = []string{key} 246 } 247 248 var results []*store.Record 249 250 for _, k := range keys { 251 r, err := m.get(prefix, k) 252 if err != nil { 253 return results, err 254 } 255 results = append(results, r) 256 } 257 258 return results, nil 259 } 260 261 func (m *memoryStore) Write(r *store.Record, opts ...store.WriteOption) error { 262 writeOpts := store.WriteOptions{} 263 for _, o := range opts { 264 o(&writeOpts) 265 } 266 267 prefix := m.prefix(writeOpts.Database, writeOpts.Table) 268 269 if len(opts) > 0 { 270 // Copy the record before applying options, or the incoming record will be mutated 271 newRecord := store.Record{} 272 newRecord.Key = r.Key 273 newRecord.Value = make([]byte, len(r.Value)) 274 newRecord.Metadata = make(map[string]interface{}) 275 copy(newRecord.Value, r.Value) 276 newRecord.Expiry = r.Expiry 277 278 for k, v := range r.Metadata { 279 newRecord.Metadata[k] = v 280 } 281 282 m.set(prefix, &newRecord) 283 return nil 284 } 285 286 // set 287 m.set(prefix, r) 288 289 return nil 290 } 291 292 func (m *memoryStore) Delete(key string, opts ...store.DeleteOption) error { 293 deleteOptions := store.DeleteOptions{} 294 for _, o := range opts { 295 o(&deleteOptions) 296 } 297 298 prefix := m.prefix(deleteOptions.Database, deleteOptions.Table) 299 m.delete(prefix, key) 300 return nil 301 } 302 303 func (m *memoryStore) Options() store.Options { 304 return m.options 305 } 306 307 func (m *memoryStore) List(opts ...store.ListOption) ([]string, error) { 308 listOptions := store.ListOptions{ 309 Order: store.OrderAsc, 310 } 311 312 for _, o := range opts { 313 o(&listOptions) 314 } 315 316 prefix := m.prefix(listOptions.Database, listOptions.Table) 317 keys := m.list(prefix, listOptions.Order, listOptions.Limit, listOptions.Offset, listOptions.Prefix, listOptions.Suffix) 318 return keys, nil 319 }