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  }