memcache.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. package dao
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "go-common/app/admin/main/reply/model"
  7. "go-common/library/cache/memcache"
  8. "go-common/library/log"
  9. )
  10. const (
  11. _prefixSub = "s_" // sub_oid<<8|type
  12. _prefixReply = "r_" // r_rpID
  13. _prefixAdminTop = "at_" // at_rpID
  14. _prefixUpperTop = "ut_" // ut_rpID
  15. _prefixConfig = "c_%d_%d_%d" // oid_type_category
  16. _oidOverflow = 1 << 48
  17. )
  18. func keyReply(rpID int64) string {
  19. return _prefixReply + strconv.FormatInt(rpID, 10)
  20. }
  21. func keySubject(oid int64, typ int32) string {
  22. if oid > _oidOverflow {
  23. return fmt.Sprintf("%s_%d_%d", _prefixSub, oid, typ)
  24. }
  25. return _prefixSub + strconv.FormatInt((oid<<8)|int64(typ), 10)
  26. }
  27. func keyConfig(oid int64, typ, category int32) string {
  28. return fmt.Sprintf(_prefixConfig, oid, typ, category)
  29. }
  30. func keyAdminTop(oid int64, attr uint32) string {
  31. if oid > _oidOverflow {
  32. return fmt.Sprintf("%s_%d_%d", _prefixAdminTop, oid, attr)
  33. }
  34. return _prefixAdminTop + strconv.FormatInt((oid<<8)|int64(attr), 10)
  35. }
  36. func keyUpperTop(oid int64, attr uint32) string {
  37. if oid > _oidOverflow {
  38. return fmt.Sprintf("%s_%d_%d", _prefixUpperTop, oid, attr)
  39. }
  40. return _prefixUpperTop + strconv.FormatInt((oid<<8)|int64(attr), 10)
  41. }
  42. // PingMC check connection success.
  43. func (d *Dao) pingMC(c context.Context) (err error) {
  44. conn := d.mc.Get(c)
  45. item := memcache.Item{Key: "ping", Value: []byte{1}, Expiration: d.mcExpire}
  46. err = conn.Set(&item)
  47. conn.Close()
  48. return
  49. }
  50. // SubjectCache get subject from memcache.
  51. func (d *Dao) SubjectCache(c context.Context, oid int64, typ int32) (sub *model.Subject, err error) {
  52. key := keySubject(oid, typ)
  53. conn := d.mc.Get(c)
  54. defer conn.Close()
  55. item, err := conn.Get(key)
  56. if err != nil {
  57. if err == memcache.ErrNotFound {
  58. err = nil
  59. }
  60. return
  61. }
  62. sub = new(model.Subject)
  63. if err = conn.Scan(item, sub); err != nil {
  64. log.Error("conn.Scan(%s) error(%v)", item.Value, err)
  65. sub = nil
  66. }
  67. return
  68. }
  69. // AddSubjectCache add subject into memcache.
  70. func (d *Dao) AddSubjectCache(c context.Context, subs ...*model.Subject) (err error) {
  71. conn := d.mc.Get(c)
  72. for _, sub := range subs {
  73. key := keySubject(sub.Oid, sub.Type)
  74. item := &memcache.Item{Key: key, Object: sub, Expiration: d.mcExpire, Flags: memcache.FlagJSON}
  75. if err = conn.Set(item); err != nil {
  76. log.Error("conn.Set(%s,%v) error(%v)", key, sub, err)
  77. }
  78. }
  79. conn.Close()
  80. return
  81. }
  82. // DelSubjectCache delete subject from memcache.
  83. func (d *Dao) DelSubjectCache(c context.Context, oid int64, typ int32) (err error) {
  84. key := keySubject(oid, typ)
  85. conn := d.mc.Get(c)
  86. if err = conn.Delete(key); err != nil {
  87. if err == memcache.ErrNotFound {
  88. err = nil
  89. }
  90. }
  91. conn.Close()
  92. return
  93. }
  94. // ReplyCache get a reply from memcache.
  95. func (d *Dao) ReplyCache(c context.Context, rpID int64) (rp *model.Reply, err error) {
  96. key := keyReply(rpID)
  97. conn := d.mc.Get(c)
  98. defer conn.Close()
  99. item, err := conn.Get(key)
  100. if err != nil {
  101. if err == memcache.ErrNotFound {
  102. err = nil
  103. }
  104. return
  105. }
  106. rp = new(model.Reply)
  107. if err = conn.Scan(item, rp); err != nil {
  108. rp = nil
  109. }
  110. return
  111. }
  112. // RepliesCache multi get replies from memcache.
  113. func (d *Dao) RepliesCache(c context.Context, rpIDs []int64) (rpMap map[int64]*model.Reply, missed []int64, err error) {
  114. rpMap = make(map[int64]*model.Reply, len(rpIDs))
  115. keys := make([]string, len(rpIDs))
  116. mm := make(map[string]int64, len(rpIDs))
  117. for i, rpID := range rpIDs {
  118. key := keyReply(rpID)
  119. keys[i] = key
  120. mm[key] = rpID
  121. }
  122. conn := d.mc.Get(c)
  123. defer conn.Close()
  124. items, err := conn.GetMulti(keys)
  125. if err != nil {
  126. if err == memcache.ErrNotFound {
  127. err = nil
  128. }
  129. return
  130. }
  131. for _, item := range items {
  132. rp := new(model.Reply)
  133. if err = conn.Scan(item, rp); err != nil {
  134. log.Error("conn.Scan(%s) error(%v)", item.Value, err)
  135. continue
  136. }
  137. rpMap[mm[item.Key]] = rp
  138. delete(mm, item.Key)
  139. }
  140. missed = make([]int64, 0, len(mm))
  141. for _, valIn := range mm {
  142. missed = append(missed, valIn)
  143. }
  144. return
  145. }
  146. // AddReplyCache add reply into memcache.
  147. func (d *Dao) AddReplyCache(c context.Context, rps ...*model.Reply) (err error) {
  148. conn := d.mc.Get(c)
  149. defer conn.Close()
  150. for _, rp := range rps {
  151. item := &memcache.Item{
  152. Key: keyReply(rp.ID),
  153. Object: rp,
  154. Expiration: d.mcExpire,
  155. Flags: memcache.FlagJSON,
  156. }
  157. if err = conn.Set(item); err != nil {
  158. return
  159. }
  160. }
  161. return
  162. }
  163. // DelReplyCache delete reply from memcache.
  164. func (d *Dao) DelReplyCache(c context.Context, rpID int64) (err error) {
  165. conn := d.mc.Get(c)
  166. if err = conn.Delete(keyReply(rpID)); err != nil {
  167. if err == memcache.ErrNotFound {
  168. err = nil
  169. }
  170. }
  171. conn.Close()
  172. return
  173. }
  174. // DelConfigCache delete reply config from memcache.
  175. func (d *Dao) DelConfigCache(c context.Context, oid int64, typ, category int32) (err error) {
  176. key := keyConfig(oid, typ, category)
  177. conn := d.mc.Get(c)
  178. if err = conn.Delete(key); err != nil {
  179. if err == memcache.ErrNotFound {
  180. err = nil
  181. }
  182. }
  183. conn.Close()
  184. return
  185. }
  186. // TopCache get a reply from memcache.
  187. func (d *Dao) TopCache(c context.Context, oid int64, attr uint32) (rp *model.Reply, err error) {
  188. var key string
  189. if attr == model.SubAttrTopAdmin {
  190. key = keyAdminTop(oid, attr)
  191. } else if attr == model.SubAttrTopUpper {
  192. key = keyUpperTop(oid, attr)
  193. }
  194. conn := d.mc.Get(c)
  195. defer conn.Close()
  196. item, err := conn.Get(key)
  197. if err != nil {
  198. if err == memcache.ErrNotFound {
  199. err = nil
  200. }
  201. return
  202. }
  203. rp = new(model.Reply)
  204. if err = conn.Scan(item, rp); err != nil {
  205. rp = nil
  206. }
  207. return
  208. }
  209. // DelTopCache delete topreply from memcache.
  210. func (d *Dao) DelTopCache(c context.Context, oid int64, attr uint32) (err error) {
  211. var key string
  212. if attr == model.SubAttrTopAdmin {
  213. key = keyAdminTop(oid, attr)
  214. } else if attr == model.SubAttrTopUpper {
  215. key = keyUpperTop(oid, attr)
  216. }
  217. conn := d.mc.Get(c)
  218. if err = conn.Delete(key); err != nil {
  219. if err == memcache.ErrNotFound {
  220. err = nil
  221. } else {
  222. log.Error("conn.Delete(%s) error(%v)", key, err)
  223. }
  224. }
  225. conn.Close()
  226. return
  227. }
  228. // AddTopCache add top reply into memcache.
  229. func (d *Dao) AddTopCache(c context.Context, rp *model.Reply) (err error) {
  230. var key string
  231. if rp.AttrVal(model.AttrTopAdmin) == model.AttrYes {
  232. key = keyAdminTop(rp.Oid, model.AttrTopAdmin)
  233. } else if rp.AttrVal(model.AttrTopUpper) == model.AttrYes {
  234. key = keyUpperTop(rp.Oid, model.AttrTopUpper)
  235. } else {
  236. return
  237. }
  238. conn := d.mc.Get(c)
  239. defer conn.Close()
  240. item := &memcache.Item{Key: key, Object: rp, Expiration: d.mcExpire, Flags: memcache.FlagJSON}
  241. if err = conn.Set(item); err != nil {
  242. log.Error("conn.Set(%s,%v) error(%v)", key, rp, err)
  243. }
  244. return
  245. }