memcache.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. package dao
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "go-common/app/service/main/relation/model"
  7. gmc "go-common/library/cache/memcache"
  8. "go-common/library/log"
  9. )
  10. const (
  11. _prefixFollowing = "pb_a_" // key of following
  12. _prefixFollower = "pb_f_" // key of follower
  13. _prefixTagCount = "rs_tmtc_%d" // key of relation tag by mid & tag's count
  14. _prefixTags = "tags_" // user tag info.
  15. _prefixGlobalHotRec = "gh_rec" // global hot rec
  16. _prefixStat = "c_" // key of stat
  17. _prefixFollowerNotify = "f_notify_"
  18. _emptyExpire = 20 * 24 * 3600
  19. _recExpire = 5 * 24 * 3600
  20. )
  21. func statKey(mid int64) string {
  22. return _prefixStat + strconv.FormatInt(mid, 10)
  23. }
  24. func tagsKey(mid int64) string {
  25. return _prefixTags + strconv.FormatInt(mid, 10)
  26. }
  27. func followingKey(mid int64) string {
  28. return _prefixFollowing + strconv.FormatInt(mid, 10)
  29. }
  30. func followerKey(mid int64) string {
  31. return _prefixFollower + strconv.FormatInt(mid, 10)
  32. }
  33. func tagCountKey(mid int64) string {
  34. return fmt.Sprintf(_prefixTagCount, mid)
  35. }
  36. func globalHotKey() string {
  37. return _prefixGlobalHotRec
  38. }
  39. func followerNotifySetting(mid int64) string {
  40. return _prefixFollowerNotify + strconv.FormatInt(mid, 10)
  41. }
  42. // pingMC ping memcache.
  43. func (d *Dao) pingMC(c context.Context) (err error) {
  44. conn := d.mc.Get(c)
  45. if err = conn.Set(&gmc.Item{Key: "ping", Value: []byte{1}, Expiration: d.mcExpire}); err != nil {
  46. log.Error("conn.Store(set, ping, 1) error(%v)", err)
  47. }
  48. conn.Close()
  49. return
  50. }
  51. // SetFollowingCache set following cache.
  52. func (d *Dao) SetFollowingCache(c context.Context, mid int64, followings []*model.Following) (err error) {
  53. return d.setFollowingCache(c, followingKey(mid), followings)
  54. }
  55. // FollowingCache get following cache.
  56. func (d *Dao) FollowingCache(c context.Context, mid int64) (followings []*model.Following, err error) {
  57. return d.followingCache(c, followingKey(mid))
  58. }
  59. // DelFollowingCache delete following cache.
  60. func (d *Dao) DelFollowingCache(c context.Context, mid int64) (err error) {
  61. return d.delFollowingCache(c, followingKey(mid))
  62. }
  63. // SetFollowerCache set follower cache.
  64. func (d *Dao) SetFollowerCache(c context.Context, mid int64, followers []*model.Following) (err error) {
  65. return d.setFollowingCache(c, followerKey(mid), followers)
  66. }
  67. // FollowerCache get follower cache.
  68. func (d *Dao) FollowerCache(c context.Context, mid int64) (followers []*model.Following, err error) {
  69. return d.followingCache(c, followerKey(mid))
  70. }
  71. // DelFollowerCache delete follower cache.
  72. func (d *Dao) DelFollowerCache(c context.Context, mid int64) (err error) {
  73. return d.delFollowingCache(c, followerKey(mid))
  74. }
  75. // setFollowingCache set following cache.
  76. func (d *Dao) setFollowingCache(c context.Context, key string, followings []*model.Following) (err error) {
  77. expire := d.followerExpire
  78. if len(followings) == 0 {
  79. expire = _emptyExpire
  80. }
  81. item := &gmc.Item{Key: key, Object: &model.FollowingList{FollowingList: followings}, Expiration: expire, Flags: gmc.FlagProtobuf}
  82. conn := d.mc.Get(c)
  83. if err = conn.Set(item); err != nil {
  84. log.Error("setFollowingCache err(%v)", err)
  85. }
  86. conn.Close()
  87. return
  88. }
  89. // followingCache get following cache.
  90. func (d *Dao) followingCache(c context.Context, key string) (followings []*model.Following, err error) {
  91. conn := d.mc.Get(c)
  92. defer conn.Close()
  93. item, err := conn.Get(key)
  94. if err != nil {
  95. if err == gmc.ErrNotFound {
  96. err = nil
  97. return
  98. }
  99. log.Error("d.followingCache err(%v)", err)
  100. return
  101. }
  102. followingList := &model.FollowingList{}
  103. if err = conn.Scan(item, followingList); err != nil {
  104. log.Error("d.followinfCache err(%v)", err)
  105. }
  106. followings = followingList.FollowingList
  107. if followings == nil {
  108. followings = []*model.Following{}
  109. }
  110. return
  111. }
  112. // delFollowingCache delete following cache.
  113. func (d *Dao) delFollowingCache(c context.Context, key string) (err error) {
  114. conn := d.mc.Get(c)
  115. if err = conn.Delete(key); err != nil {
  116. if err == gmc.ErrNotFound {
  117. err = nil
  118. } else {
  119. log.Error("conn.Delete(%s) error(%v)", key, err)
  120. }
  121. }
  122. conn.Close()
  123. return
  124. }
  125. // TagCountCache tag count cache
  126. func (d *Dao) TagCountCache(c context.Context, mid int64) (tagCount []*model.TagCount, err error) {
  127. conn := d.mc.Get(c)
  128. defer conn.Close()
  129. res, err := conn.Get(tagCountKey(mid))
  130. if err != nil {
  131. if err == gmc.ErrNotFound {
  132. err = nil
  133. return
  134. }
  135. log.Error("mc.Get error(%v)", err)
  136. return
  137. }
  138. tc := &model.TagCountList{}
  139. if err = conn.Scan(res, tc); err != nil {
  140. log.Error("conn.Scan error(%v)", err)
  141. }
  142. tagCount = tc.TagCountList
  143. return
  144. }
  145. // SetTagCountCache set tag count cache
  146. func (d *Dao) SetTagCountCache(c context.Context, mid int64, tagCount []*model.TagCount) (err error) {
  147. item := &gmc.Item{Key: tagCountKey(mid), Object: &model.TagCountList{TagCountList: tagCount}, Expiration: d.mcExpire, Flags: gmc.FlagProtobuf}
  148. conn := d.mc.Get(c)
  149. if err = conn.Set(item); err != nil {
  150. log.Error("setTagMidFidCache(%s) error(%v)", tagCountKey(mid), err)
  151. }
  152. conn.Close()
  153. return
  154. }
  155. // DelTagCountCache del tag count cache
  156. func (d *Dao) DelTagCountCache(c context.Context, mid int64) (err error) {
  157. conn := d.mc.Get(c)
  158. if err = conn.Delete(tagCountKey(mid)); err != nil {
  159. if err == gmc.ErrNotFound {
  160. err = nil
  161. } else {
  162. log.Error("conn.Delete(%s) error(%v)", tagCountKey(mid), err)
  163. }
  164. }
  165. conn.Close()
  166. return
  167. }
  168. // SetTagsCache set user tags cache.
  169. func (d *Dao) SetTagsCache(c context.Context, mid int64, tags *model.Tags) (err error) {
  170. conn := d.mc.Get(c)
  171. defer conn.Close()
  172. item := &gmc.Item{Key: tagsKey(mid), Object: tags, Expiration: d.mcExpire, Flags: gmc.FlagProtobuf}
  173. if err = conn.Set(item); err != nil {
  174. log.Error("SetTagsCache err %v", err)
  175. }
  176. return
  177. }
  178. // TagsCache get user tags.
  179. func (d *Dao) TagsCache(c context.Context, mid int64) (tags map[int64]*model.Tag, err error) {
  180. conn := d.mc.Get(c)
  181. defer conn.Close()
  182. res, err := conn.Get(tagsKey(mid))
  183. if err != nil {
  184. if err == gmc.ErrNotFound {
  185. err = nil
  186. return
  187. }
  188. return
  189. }
  190. tag := new(model.Tags)
  191. if err = conn.Scan(res, tag); err != nil {
  192. return
  193. }
  194. tags = tag.Tags
  195. return
  196. }
  197. // DelTagsCache del user tags cache.
  198. func (d *Dao) DelTagsCache(c context.Context, mid int64) (err error) {
  199. conn := d.mc.Get(c)
  200. if err = conn.Delete(tagsKey(mid)); err != nil {
  201. if err == gmc.ErrNotFound {
  202. err = nil
  203. } else {
  204. log.Error("conn.Delete(%s) error(%v)", tagCountKey(mid), err)
  205. }
  206. }
  207. conn.Close()
  208. return
  209. }
  210. // SetGlobalHotRecCache set global hot recommend cache.
  211. func (d *Dao) SetGlobalHotRecCache(c context.Context, fids []int64) (err error) {
  212. conn := d.mc.Get(c)
  213. defer conn.Close()
  214. item := &gmc.Item{Key: globalHotKey(), Object: &model.GlobalRec{Fids: fids}, Expiration: _recExpire, Flags: gmc.FlagProtobuf}
  215. if err = conn.Set(item); err != nil {
  216. log.Error("SetGlobalHotRecCache err %v", err)
  217. }
  218. return
  219. }
  220. // GlobalHotRecCache get global hot recommend.
  221. func (d *Dao) GlobalHotRecCache(c context.Context) (fs []int64, err error) {
  222. conn := d.mc.Get(c)
  223. defer conn.Close()
  224. res, err := conn.Get(globalHotKey())
  225. if err != nil {
  226. if err == gmc.ErrNotFound {
  227. err = nil
  228. }
  229. return
  230. }
  231. gh := new(model.GlobalRec)
  232. if err = conn.Scan(res, gh); err != nil {
  233. return
  234. }
  235. fs = gh.Fids
  236. return
  237. }
  238. // SetStatCache set stat cache.
  239. func (d *Dao) SetStatCache(c context.Context, mid int64, st *model.Stat) error {
  240. conn := d.mc.Get(c)
  241. defer conn.Close()
  242. item := &gmc.Item{
  243. Key: statKey(mid),
  244. Object: st,
  245. Expiration: d.mcExpire,
  246. Flags: gmc.FlagProtobuf,
  247. }
  248. if err := conn.Set(item); err != nil {
  249. log.Error("Failed to set stat cache: mid: %d stat: %+v: %+v", mid, st, err)
  250. return err
  251. }
  252. return nil
  253. }
  254. // statCache get stat cache.
  255. func (d *Dao) statCache(c context.Context, mid int64) (*model.Stat, error) {
  256. conn := d.mc.Get(c)
  257. defer conn.Close()
  258. item, err := conn.Get(statKey(mid))
  259. if err != nil {
  260. if err == gmc.ErrNotFound {
  261. return nil, nil
  262. }
  263. return nil, err
  264. }
  265. stat := &model.Stat{}
  266. if err := conn.Scan(item, stat); err != nil {
  267. log.Error("Failed to get stat cache: mid: %d: %+v", mid, err)
  268. return nil, err
  269. }
  270. return stat, nil
  271. }
  272. // statsCache get multi stat cache.
  273. func (d *Dao) statsCache(c context.Context, mids []int64) (map[int64]*model.Stat, []int64, error) {
  274. conn := d.mc.Get(c)
  275. defer conn.Close()
  276. keys := make([]string, 0, len(mids))
  277. for _, mid := range mids {
  278. keys = append(keys, statKey(mid))
  279. }
  280. items, err := conn.GetMulti(keys)
  281. if err != nil {
  282. log.Error("Failed to get multi stat: keys: %+v: %+v", keys, err)
  283. return nil, nil, err
  284. }
  285. stats := make(map[int64]*model.Stat, len(mids))
  286. for _, item := range items {
  287. stat := &model.Stat{}
  288. if err := conn.Scan(item, stat); err != nil {
  289. log.Error("Failed to scan item: key: %s item: %+v: %+v", item.Key, item, err)
  290. continue
  291. }
  292. stats[stat.Mid] = stat
  293. }
  294. missed := make([]int64, 0, len(mids))
  295. for _, mid := range mids {
  296. if _, ok := stats[mid]; !ok {
  297. missed = append(missed, mid)
  298. }
  299. }
  300. return stats, missed, nil
  301. }
  302. // DelStatCache delete stat cache.
  303. func (d *Dao) DelStatCache(c context.Context, mid int64) error {
  304. conn := d.mc.Get(c)
  305. defer conn.Close()
  306. if err := conn.Delete(statKey(mid)); err != nil {
  307. if err == gmc.ErrNotFound {
  308. return nil
  309. }
  310. log.Error("Failed to delete stat cache: mid: %d: %+v", mid, err)
  311. return err
  312. }
  313. return nil
  314. }
  315. // GetFollowerNotifyCache get data from mc
  316. func (d *Dao) GetFollowerNotifyCache(c context.Context, mid int64) (res *model.FollowerNotifySetting, err error) {
  317. conn := d.mc.Get(c)
  318. defer conn.Close()
  319. key := followerNotifySetting(mid)
  320. reply, err := conn.Get(key)
  321. if err != nil {
  322. if err == gmc.ErrNotFound {
  323. err = nil
  324. return
  325. }
  326. log.Errorv(c, log.KV("GetFollowerNotifyCache", fmt.Sprintf("%+v", err)), log.KV("key", key))
  327. return
  328. }
  329. res = &model.FollowerNotifySetting{}
  330. err = conn.Scan(reply, res)
  331. if err != nil {
  332. log.Errorv(c, log.KV("GetFollowerNotifyCache", fmt.Sprintf("%+v", err)), log.KV("key", key))
  333. return
  334. }
  335. return
  336. }
  337. // SetFollowerNotifyCache Set data to mc
  338. func (d *Dao) SetFollowerNotifyCache(c context.Context, mid int64, val *model.FollowerNotifySetting) (err error) {
  339. conn := d.mc.Get(c)
  340. defer conn.Close()
  341. key := followerNotifySetting(mid)
  342. item := &gmc.Item{
  343. Key: key,
  344. Object: val,
  345. Expiration: 86400,
  346. Flags: gmc.FlagJSON,
  347. }
  348. if err = conn.Set(item); err != nil {
  349. log.Errorv(c, log.KV("SetFollowerNotifyCache", fmt.Sprintf("%+v", err)), log.KV("key", key))
  350. return
  351. }
  352. return
  353. }
  354. // DelFollowerNotifyCache Del data from mc
  355. func (d *Dao) DelFollowerNotifyCache(c context.Context, mid int64) (err error) {
  356. conn := d.mc.Get(c)
  357. defer conn.Close()
  358. key := followerNotifySetting(mid)
  359. if err = conn.Delete(key); err != nil {
  360. if err == gmc.ErrNotFound {
  361. err = nil
  362. return
  363. }
  364. log.Errorv(c, log.KV("DelFollowerNotifyCache", fmt.Sprintf("%+v", err)), log.KV("key", key))
  365. return
  366. }
  367. return
  368. }