github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/data/cache/store/memcache.go (about) 1 package store 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 "time" 8 9 "github.com/bradfitz/gomemcache/memcache" 10 ) 11 12 const ( 13 // MemcacheType represents the storage type as a string value 14 MemcacheType = "memcache" 15 // MemcacheTagPattern represents the tag pattern to be used as a key in specified storage 16 MemcacheTagPattern = "gocache_tag_%s" 17 ) 18 19 // MemcacheStore is a store for Memcache 20 type MemcacheStore struct { 21 // MemcacheClientInterface represents a bradfitz/gomemcache client 22 client *memcache.Client 23 options *Options 24 } 25 26 // NewMemcache creates a new store to Memcache instance(s) 27 func NewMemcache(client *memcache.Client, options *Options) *MemcacheStore { 28 if options == nil { 29 options = &Options{} 30 } 31 32 return &MemcacheStore{ 33 client: client, 34 options: options, 35 } 36 } 37 38 // Get returns data stored from a given key 39 func (s *MemcacheStore) Get(key string) (interface{}, error) { 40 item, err := s.client.Get(key) 41 if err != nil { 42 return nil, err 43 } 44 if item == nil { 45 return nil, errors.New("unable to retrieve data from memcache") 46 } 47 48 return item.Value, err 49 } 50 51 // TTL returns a expiration time 52 func (s *MemcacheStore) TTL(key string) (time.Duration, error) { 53 item, err := s.client.Get(key) 54 if err != nil { 55 return 0, err 56 } 57 if item == nil { 58 return 0, errors.New("unable to retrieve data from memcache") 59 } 60 61 return time.Second * time.Duration(item.Expiration), err 62 } 63 64 // Set defines data in Memcache for given key identifier 65 func (s *MemcacheStore) Set(key string, value interface{}, options *Options) error { 66 if options == nil { 67 options = s.options 68 } 69 70 item := &memcache.Item{ 71 Key: key, 72 Value: value.([]byte), 73 Expiration: int32(options.ExpirationValue().Seconds()), 74 } 75 76 err := s.client.Set(item) 77 if err != nil { 78 return err 79 } 80 81 if tags := options.TagsValue(); len(tags) > 0 { 82 s.setTags(key, tags) 83 } 84 85 return nil 86 } 87 88 func (s *MemcacheStore) setTags(key string, tags []string) { 89 for _, tag := range tags { 90 var tagKey = fmt.Sprintf(MemcacheTagPattern, tag) 91 var cacheKeys = []string{} 92 93 if result, err := s.Get(tagKey); err == nil { 94 if bytes, ok := result.([]byte); ok { 95 cacheKeys = strings.Split(string(bytes), ",") 96 } 97 } 98 99 var alreadyInserted = false 100 for _, cacheKey := range cacheKeys { 101 if cacheKey == key { 102 alreadyInserted = true 103 break 104 } 105 } 106 107 if !alreadyInserted { 108 cacheKeys = append(cacheKeys, key) 109 } 110 111 s.Set(tagKey, []byte(strings.Join(cacheKeys, ",")), &Options{ 112 Expiration: 720 * time.Hour, 113 }) 114 } 115 } 116 117 // Delete removes data from Memcache for given key identifier 118 func (s *MemcacheStore) Delete(key string) error { 119 return s.client.Delete(key) 120 } 121 122 // Invalidate invalidates some cache data in Redis for given options 123 func (s *MemcacheStore) Invalidate(options InvalidateOptions) error { 124 if tags := options.TagsValue(); len(tags) > 0 { 125 for _, tag := range tags { 126 var tagKey = fmt.Sprintf(MemcacheTagPattern, tag) 127 result, err := s.Get(tagKey) 128 if err != nil { 129 return nil 130 } 131 132 var cacheKeys = []string{} 133 if bytes, ok := result.([]byte); ok { 134 cacheKeys = strings.Split(string(bytes), ",") 135 } 136 137 for _, cacheKey := range cacheKeys { 138 s.Delete(cacheKey) 139 } 140 } 141 } 142 143 return nil 144 } 145 146 // Clear resets all data in the store 147 func (s *MemcacheStore) Clear() error { 148 return s.client.FlushAll() 149 } 150 151 // GetType returns the store type 152 func (s *MemcacheStore) GetType() string { 153 return MemcacheType 154 }