generic.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package memcache
  2. import (
  3. "fmt"
  4. "leafstalk/covenant/monitor"
  5. "leafstalk/module"
  6. "leafstalk/otherutils"
  7. "reflect"
  8. "strconv"
  9. "time"
  10. cach2 "github.com/patrickmn/go-cache"
  11. )
  12. type GenericCache[T interface{}] struct {
  13. AllPlayers *cach2.Cache
  14. tokens otherutils.RoutineTokens
  15. loadFilter otherutils.FilterInt64
  16. skeleton *module.Skeleton
  17. name string
  18. Load func(id int64) (*T, error)
  19. New func(playerId int64) *T
  20. PrePocess func(*T)
  21. }
  22. func NewCache[T interface{}](skeleton *module.Skeleton) *GenericCache[T] {
  23. c := new(GenericCache[T])
  24. c.skeleton = skeleton
  25. var tmp *T
  26. val := reflect.TypeOf(tmp)
  27. if val != nil && val.Kind() == reflect.Ptr {
  28. c.name = val.Elem().Name()
  29. }
  30. return c
  31. }
  32. type callBackFun[T interface{}] struct {
  33. fprocess func(p *T)
  34. fErrProcess func(playerId int64, errorCode int)
  35. }
  36. func (c *GenericCache[T]) Init(load func(id int64) (*T, error),
  37. newObj func(playerId int64) *T, preProcess func(*T)) {
  38. c.AllPlayers = cach2.New(30*time.Minute, 10*time.Minute)
  39. c.tokens.Init(10)
  40. c.Load = load
  41. c.New = newObj
  42. c.PrePocess = preProcess
  43. }
  44. func (c *GenericCache[T]) GetCacheData(playerID int64) *T {
  45. k := strconv.FormatInt(playerID, 10)
  46. if v, ok := c.AllPlayers.Get(k); ok {
  47. if v2, ok := v.(*T); ok {
  48. return v2
  49. }
  50. }
  51. return nil
  52. }
  53. func (c *GenericCache[T]) SetCacheData(playerID int64, v *T) {
  54. k2 := strconv.FormatInt(playerID, 10)
  55. c.AllPlayers.SetDefault(k2, v)
  56. }
  57. func (c *GenericCache[T]) LoadAndProcess(playerId int64, fprocess func(p *T), fErrProcess func(playerId int64, errorCode int)) {
  58. //找到玩家
  59. st := time.Now()
  60. p := c.GetCacheData(playerId)
  61. if p != nil {
  62. c.PrePocess(p)
  63. c.SetCacheData(playerId, p)
  64. fprocess(p)
  65. monitor.GoLoadTimeoutWarn(fmt.Sprintf("%s.LoadAndProcess", c.name), playerId, st)
  66. return
  67. }
  68. //正在加载
  69. if c.loadFilter.IsExist(playerId) {
  70. t := new(callBackFun[T])
  71. t.fprocess = fprocess
  72. t.fErrProcess = fErrProcess
  73. c.loadFilter.AppendTask(playerId, t)
  74. return
  75. }
  76. c.loadFilter.Add(playerId)
  77. var err error
  78. c.skeleton.Go(func() {
  79. //协程加载
  80. c.tokens.Get()
  81. defer c.tokens.Release()
  82. p, err = c.Load(playerId)
  83. }, func() {
  84. defer func() {
  85. s := c.loadFilter.Remove(playerId)
  86. for _, v := range s {
  87. cft := v.(*callBackFun[T])
  88. if err != nil {
  89. cft.fErrProcess(playerId, 11)
  90. } else {
  91. cft.fprocess(p)
  92. }
  93. }
  94. monitor.GoLoadTimeoutWarn(fmt.Sprintf("%s.LoadAndProcess1", c.name), playerId, st)
  95. }()
  96. if err != nil {
  97. fErrProcess(playerId, 11)
  98. return
  99. }
  100. if IsNil(p) || p == nil {
  101. p = c.New(playerId)
  102. }
  103. c.PrePocess(p)
  104. c.SetCacheData(playerId, p)
  105. fprocess(p)
  106. })
  107. }
  108. func IsNil(i interface{}) bool {
  109. vi := reflect.ValueOf(i)
  110. if vi.Kind() == reflect.Ptr {
  111. return vi.IsNil()
  112. }
  113. return false
  114. }
  115. func (c *GenericCache[T]) LoadMultiAndProcess(playerId1 int64, playerId2 int64, fprocess func(p1 *T, p2 *T), fErrProcess func(errorCode int)) {
  116. c.LoadAndProcess(playerId1, func(p1 *T) {
  117. c.LoadAndProcess(playerId2, func(p2 *T) {
  118. fprocess(p1, p2)
  119. }, func(playerId int64, errorCode int) {
  120. fErrProcess(errorCode)
  121. })
  122. }, func(playerId int64, errorCode int) {
  123. fErrProcess(errorCode)
  124. })
  125. }