github.com/vicanso/pike@v1.0.1-0.20210630235453-9099e041f6ec/cache/dispatcher.go (about) 1 // MIT License 2 3 // Copyright (c) 2020 Tree Xie 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 // SOFTWARE. 22 23 // 创建缓存分发组件,初始化时创建128长度的lru缓存数组,每次根据缓存的key生成hash, 24 // 根据hash的值判断使用对应的lru,减少锁的冲突,提升性能 25 26 package cache 27 28 import ( 29 "sync" 30 31 "github.com/golang/groupcache/lru" 32 "github.com/vicanso/pike/log" 33 "github.com/vicanso/pike/store" 34 "github.com/vicanso/pike/util" 35 "go.uber.org/zap" 36 ) 37 38 // defaultZoneSize default zone size 39 const defaultZoneSize = 128 40 41 type ( 42 // httpLRUCache http lru cache 43 httpLRUCache struct { 44 cache *lru.Cache 45 mu *sync.Mutex 46 } 47 // dispatcher http cache dispatcher 48 dispatcher struct { 49 zoneSize uint64 50 hitForPass int 51 list []*httpLRUCache 52 store store.Store 53 } 54 // dispatchers http cache dispatchers 55 dispatchers struct { 56 m *sync.Map 57 } 58 // DispatcherOption dispatcher option 59 DispatcherOption struct { 60 Name string 61 Size int 62 HitForPass int 63 Store string 64 } 65 ) 66 67 func newHTTPLRUCache(size int) *httpLRUCache { 68 c := &httpLRUCache{ 69 cache: lru.New(size), 70 mu: &sync.Mutex{}, 71 } 72 return c 73 } 74 75 // getCache get http cache by key 76 func (lru *httpLRUCache) getCache(key []byte) (*httpCache, bool) { 77 value, ok := lru.cache.Get(byteSliceToString(key)) 78 if !ok { 79 return nil, false 80 } 81 if hc, ok := value.(*httpCache); ok { 82 return hc, true 83 } 84 return nil, false 85 } 86 87 // addCache add http cache by key 88 func (lru *httpLRUCache) addCache(key []byte, hc *httpCache) { 89 lru.cache.Add(byteSliceToString(key), hc) 90 } 91 92 // removeCache remove http cache by key 93 func (lru *httpLRUCache) removeCache(key []byte) { 94 lru.cache.Remove(byteSliceToString(key)) 95 } 96 97 // NewDispatcher new a http cache dispatcher 98 func NewDispatcher(option DispatcherOption) *dispatcher { 99 zoneSize := defaultZoneSize 100 size := option.Size 101 if option.Size <= 0 { 102 size = zoneSize * 100 103 } 104 // 如果配置lru缓存数量较小,则zone的空间调小 105 if size < 1024 { 106 zoneSize = 8 107 } 108 109 // 按zoneSize与size创建二维缓存,存放的是LRU缓存实例 110 lruSize := size / zoneSize 111 list := make([]*httpLRUCache, zoneSize) 112 // 根据zone size生成一个缓存对列 113 for i := 0; i < zoneSize; i++ { 114 list[i] = newHTTPLRUCache(lruSize) 115 } 116 disp := &dispatcher{ 117 zoneSize: uint64(zoneSize), 118 list: list, 119 hitForPass: option.HitForPass, 120 } 121 // 如果有配置store 122 if option.Store != "" { 123 store, err := store.NewStore(option.Store) 124 if err != nil { 125 log.Default().Error("new store fail", 126 zap.String("url", option.Store), 127 zap.Error(err), 128 ) 129 } 130 if store != nil { 131 disp.store = store 132 } 133 } 134 return disp 135 } 136 137 func (d *dispatcher) getLRU(key []byte) *httpLRUCache { 138 // 计算hash值 139 index := MemHash(key) % d.zoneSize 140 // 从预定义的列表中取对应的缓存 141 return d.list[index] 142 } 143 144 // GetHTTPCache get http cache through key 145 func (d *dispatcher) GetHTTPCache(key []byte) *httpCache { 146 // 锁只在public的方法在使用,public方法之间不互相调用 147 lru := d.getLRU(key) 148 lru.mu.Lock() 149 defer lru.mu.Unlock() 150 hc, ok := lru.getCache(key) 151 if ok { 152 return hc 153 } 154 if d.store != nil { 155 hc = NewHTTPStoreCache(key, d.store) 156 } else { 157 hc = NewHTTPCache() 158 } 159 lru.addCache(key, hc) 160 return hc 161 } 162 163 // RemoveHTTPCache remove http cache 164 func (d *dispatcher) RemoveHTTPCache(key []byte) { 165 lru := d.getLRU(key) 166 lru.mu.Lock() 167 defer lru.mu.Unlock() 168 lru.removeCache(key) 169 if d.store != nil { 170 err := d.store.Delete(key) 171 if err != nil { 172 log.Default().Error("delete from store fail", 173 zap.String("key", string(key)), 174 zap.Error(err), 175 ) 176 } 177 } 178 } 179 180 // GetHitForPass get hit for pass 181 func (d *dispatcher) GetHitForPass() int { 182 return d.hitForPass 183 } 184 185 // NewDispatchers new dispatchers 186 func NewDispatchers(opts []DispatcherOption) *dispatchers { 187 ds := &dispatchers{ 188 m: &sync.Map{}, 189 } 190 for _, opt := range opts { 191 ds.m.Store(opt.Name, NewDispatcher(opt)) 192 } 193 return ds 194 } 195 196 // Get get dispatcher by name 197 func (ds *dispatchers) Get(name string) *dispatcher { 198 value, ok := ds.m.Load(name) 199 if !ok { 200 return nil 201 } 202 d, ok := value.(*dispatcher) 203 if !ok { 204 return nil 205 } 206 return d 207 } 208 209 // RemoveHTTPCache remove http cache 210 func (ds *dispatchers) RemoveHTTPCache(name string, key []byte) { 211 if name != "" { 212 d := ds.Get(name) 213 if d == nil { 214 return 215 } 216 d.RemoveHTTPCache(key) 217 return 218 } 219 // 如果未指定名称,则从所有缓存中删除 220 ds.m.Range(func(_, v interface{}) bool { 221 d, ok := v.(*dispatcher) 222 if ok { 223 d.RemoveHTTPCache(key) 224 } 225 return true 226 }) 227 } 228 229 // Reset reset the dispatchers, remove not exists dispatchers and create new dispatcher. If the dispatcher is exists, then use the old one. 230 func (ds *dispatchers) Reset(opts []DispatcherOption) { 231 // 删除不再使用的dispatcher 232 _ = util.MapDelete(ds.m, func(key string) bool { 233 // 如果不存在的,则删除 234 exists := false 235 for _, opt := range opts { 236 if opt.Name == key { 237 exists = true 238 break 239 } 240 } 241 return !exists 242 }) 243 244 for _, opt := range opts { 245 _, ok := ds.m.Load(opt.Name) 246 // 如果当前dispatcher不存在,则创建 247 // 如果存在,对原来的size不调整 248 if !ok { 249 ds.m.Store(opt.Name, NewDispatcher(opt)) 250 } 251 } 252 }