github.com/lingyao2333/mo-zero@v1.4.1/core/stores/cache/cache.go (about) 1 package cache 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "log" 8 "time" 9 10 "github.com/lingyao2333/mo-zero/core/errorx" 11 "github.com/lingyao2333/mo-zero/core/hash" 12 "github.com/lingyao2333/mo-zero/core/syncx" 13 ) 14 15 type ( 16 // Cache interface is used to define the cache implementation. 17 Cache interface { 18 // Del deletes cached values with keys. 19 Del(keys ...string) error 20 // DelCtx deletes cached values with keys. 21 DelCtx(ctx context.Context, keys ...string) error 22 // Get gets the cache with key and fills into v. 23 Get(key string, val interface{}) error 24 // GetCtx gets the cache with key and fills into v. 25 GetCtx(ctx context.Context, key string, val interface{}) error 26 // IsNotFound checks if the given error is the defined errNotFound. 27 IsNotFound(err error) bool 28 // Set sets the cache with key and v, using c.expiry. 29 Set(key string, val interface{}) error 30 // SetCtx sets the cache with key and v, using c.expiry. 31 SetCtx(ctx context.Context, key string, val interface{}) error 32 // SetWithExpire sets the cache with key and v, using given expire. 33 SetWithExpire(key string, val interface{}, expire time.Duration) error 34 // SetWithExpireCtx sets the cache with key and v, using given expire. 35 SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error 36 // Take takes the result from cache first, if not found, 37 // query from DB and set cache using c.expiry, then return the result. 38 Take(val interface{}, key string, query func(val interface{}) error) error 39 // TakeCtx takes the result from cache first, if not found, 40 // query from DB and set cache using c.expiry, then return the result. 41 TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error 42 // TakeWithExpire takes the result from cache first, if not found, 43 // query from DB and set cache using given expire, then return the result. 44 TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error 45 // TakeWithExpireCtx takes the result from cache first, if not found, 46 // query from DB and set cache using given expire, then return the result. 47 TakeWithExpireCtx(ctx context.Context, val interface{}, key string, 48 query func(val interface{}, expire time.Duration) error) error 49 } 50 51 cacheCluster struct { 52 dispatcher *hash.ConsistentHash 53 errNotFound error 54 } 55 ) 56 57 // New returns a Cache. 58 func New(c ClusterConf, barrier syncx.SingleFlight, st *Stat, errNotFound error, 59 opts ...Option) Cache { 60 if len(c) == 0 || TotalWeights(c) <= 0 { 61 log.Fatal("no cache nodes") 62 } 63 64 if len(c) == 1 { 65 return NewNode(c[0].NewRedis(), barrier, st, errNotFound, opts...) 66 } 67 68 dispatcher := hash.NewConsistentHash() 69 for _, node := range c { 70 cn := NewNode(node.NewRedis(), barrier, st, errNotFound, opts...) 71 dispatcher.AddWithWeight(cn, node.Weight) 72 } 73 74 return cacheCluster{ 75 dispatcher: dispatcher, 76 errNotFound: errNotFound, 77 } 78 } 79 80 // Del deletes cached values with keys. 81 func (cc cacheCluster) Del(keys ...string) error { 82 return cc.DelCtx(context.Background(), keys...) 83 } 84 85 // DelCtx deletes cached values with keys. 86 func (cc cacheCluster) DelCtx(ctx context.Context, keys ...string) error { 87 switch len(keys) { 88 case 0: 89 return nil 90 case 1: 91 key := keys[0] 92 c, ok := cc.dispatcher.Get(key) 93 if !ok { 94 return cc.errNotFound 95 } 96 97 return c.(Cache).DelCtx(ctx, key) 98 default: 99 var be errorx.BatchError 100 nodes := make(map[interface{}][]string) 101 for _, key := range keys { 102 c, ok := cc.dispatcher.Get(key) 103 if !ok { 104 be.Add(fmt.Errorf("key %q not found", key)) 105 continue 106 } 107 108 nodes[c] = append(nodes[c], key) 109 } 110 for c, ks := range nodes { 111 if err := c.(Cache).DelCtx(ctx, ks...); err != nil { 112 be.Add(err) 113 } 114 } 115 116 return be.Err() 117 } 118 } 119 120 // Get gets the cache with key and fills into v. 121 func (cc cacheCluster) Get(key string, val interface{}) error { 122 return cc.GetCtx(context.Background(), key, val) 123 } 124 125 // GetCtx gets the cache with key and fills into v. 126 func (cc cacheCluster) GetCtx(ctx context.Context, key string, val interface{}) error { 127 c, ok := cc.dispatcher.Get(key) 128 if !ok { 129 return cc.errNotFound 130 } 131 132 return c.(Cache).GetCtx(ctx, key, val) 133 } 134 135 // IsNotFound checks if the given error is the defined errNotFound. 136 func (cc cacheCluster) IsNotFound(err error) bool { 137 return errors.Is(err, cc.errNotFound) 138 } 139 140 // Set sets the cache with key and v, using c.expiry. 141 func (cc cacheCluster) Set(key string, val interface{}) error { 142 return cc.SetCtx(context.Background(), key, val) 143 } 144 145 // SetCtx sets the cache with key and v, using c.expiry. 146 func (cc cacheCluster) SetCtx(ctx context.Context, key string, val interface{}) error { 147 c, ok := cc.dispatcher.Get(key) 148 if !ok { 149 return cc.errNotFound 150 } 151 152 return c.(Cache).SetCtx(ctx, key, val) 153 } 154 155 // SetWithExpire sets the cache with key and v, using given expire. 156 func (cc cacheCluster) SetWithExpire(key string, val interface{}, expire time.Duration) error { 157 return cc.SetWithExpireCtx(context.Background(), key, val, expire) 158 } 159 160 // SetWithExpireCtx sets the cache with key and v, using given expire. 161 func (cc cacheCluster) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error { 162 c, ok := cc.dispatcher.Get(key) 163 if !ok { 164 return cc.errNotFound 165 } 166 167 return c.(Cache).SetWithExpireCtx(ctx, key, val, expire) 168 } 169 170 // Take takes the result from cache first, if not found, 171 // query from DB and set cache using c.expiry, then return the result. 172 func (cc cacheCluster) Take(val interface{}, key string, query func(val interface{}) error) error { 173 return cc.TakeCtx(context.Background(), val, key, query) 174 } 175 176 // TakeCtx takes the result from cache first, if not found, 177 // query from DB and set cache using c.expiry, then return the result. 178 func (cc cacheCluster) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error { 179 c, ok := cc.dispatcher.Get(key) 180 if !ok { 181 return cc.errNotFound 182 } 183 184 return c.(Cache).TakeCtx(ctx, val, key, query) 185 } 186 187 // TakeWithExpire takes the result from cache first, if not found, 188 // query from DB and set cache using given expire, then return the result. 189 func (cc cacheCluster) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error { 190 return cc.TakeWithExpireCtx(context.Background(), val, key, query) 191 } 192 193 // TakeWithExpireCtx takes the result from cache first, if not found, 194 // query from DB and set cache using given expire, then return the result. 195 func (cc cacheCluster) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error { 196 c, ok := cc.dispatcher.Get(key) 197 if !ok { 198 return cc.errNotFound 199 } 200 201 return c.(Cache).TakeWithExpireCtx(ctx, val, key, query) 202 }