package readcache import ( "fmt" "leafstalk/covenant/monitor" "leafstalk/module" "leafstalk/otherutils" "reflect" "strconv" "time" cach2 "github.com/patrickmn/go-cache" ) type SameStructCache struct { Name string AllPlayers *cach2.Cache tokens otherutils.RoutineTokens loadFilter otherutils.FilterInt64 skeleton *module.Skeleton Load func(id int64) (interface{}, error) New func(playerId int64) interface{} PrePocess func(interface{}) } func NewCache(skeleton *module.Skeleton) *SameStructCache { c := new(SameStructCache) c.skeleton = skeleton return c } type callBackFun struct { fprocess func(p interface{}) fErrProcess func(playerId int64, errorCode int) } func (c *SameStructCache) Init(load func(id int64) (interface{}, error), newObj func(playerId int64) interface{}, preProcess func(interface{})) { c.AllPlayers = cach2.New(5*time.Minute, 10*time.Minute) c.tokens.Init(10) c.Load = load c.New = newObj c.PrePocess = preProcess } func (c *SameStructCache) GetCacheData(playerID int64) interface{} { k := strconv.FormatInt(playerID, 10) if v, ok := c.AllPlayers.Get(k); ok { return v } return nil } func (c *SameStructCache) SetCacheData(playerID int64, v interface{}) { k2 := strconv.FormatInt(playerID, 10) c.AllPlayers.SetDefault(k2, v) } func (c *SameStructCache) LoadAndProcess(playerId int64, fprocess func(p interface{}), fErrProcess func(playerId int64, errorCode int)) { st := time.Now() //找到玩家 p := c.GetCacheData(playerId) if p != nil { c.SetCacheData(playerId, p) c.PrePocess(p) fprocess(p) monitor.GoLoadTimeoutWarn(fmt.Sprintf("%s.LoadAndProcess", c.Name), playerId, st) return } //正在加载 if c.loadFilter.IsExist(playerId) { t := new(callBackFun) t.fprocess = fprocess t.fErrProcess = fErrProcess c.loadFilter.AppendTask(playerId, t) return } c.loadFilter.Add(playerId) var err error c.skeleton.Go(func() { //协程加载 c.tokens.Get() defer c.tokens.Release() p, err = c.Load(playerId) }, func() { defer func() { s := c.loadFilter.Remove(playerId) for _, v := range s { cft := v.(*callBackFun) if err != nil { cft.fErrProcess(playerId, 11) } else { cft.fprocess(p) } } monitor.GoLoadTimeoutWarn(fmt.Sprintf("%s.LoadAndProcess", c.Name), playerId, st) }() if err != nil { fErrProcess(playerId, 11) return } if IsNil(p) || p == nil { p = c.New(playerId) } c.SetCacheData(playerId, p) c.PrePocess(p) fprocess(p) }) } func IsNil(i interface{}) bool { vi := reflect.ValueOf(i) if vi.Kind() == reflect.Ptr { return vi.IsNil() } return false }