You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cache_redis.go 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package cache
  5. import (
  6. "fmt"
  7. "time"
  8. "code.gitea.io/gitea/modules/graceful"
  9. "code.gitea.io/gitea/modules/nosql"
  10. "gitea.com/go-chi/cache"
  11. "github.com/go-redis/redis/v8"
  12. "github.com/unknwon/com"
  13. )
  14. // RedisCacher represents a redis cache adapter implementation.
  15. type RedisCacher struct {
  16. c redis.UniversalClient
  17. prefix string
  18. hsetName string
  19. occupyMode bool
  20. }
  21. // Put puts value into cache with key and expire time.
  22. // If expired is 0, it lives forever.
  23. func (c *RedisCacher) Put(key string, val interface{}, expire int64) error {
  24. key = c.prefix + key
  25. if expire == 0 {
  26. if err := c.c.Set(graceful.GetManager().HammerContext(), key, com.ToStr(val), 0).Err(); err != nil {
  27. return err
  28. }
  29. } else {
  30. dur, err := time.ParseDuration(com.ToStr(expire) + "s")
  31. if err != nil {
  32. return err
  33. }
  34. if err = c.c.Set(graceful.GetManager().HammerContext(), key, com.ToStr(val), dur).Err(); err != nil {
  35. return err
  36. }
  37. }
  38. if c.occupyMode {
  39. return nil
  40. }
  41. return c.c.HSet(graceful.GetManager().HammerContext(), c.hsetName, key, "0").Err()
  42. }
  43. // Get gets cached value by given key.
  44. func (c *RedisCacher) Get(key string) interface{} {
  45. val, err := c.c.Get(graceful.GetManager().HammerContext(), c.prefix+key).Result()
  46. if err != nil {
  47. return nil
  48. }
  49. return val
  50. }
  51. // Delete deletes cached value by given key.
  52. func (c *RedisCacher) Delete(key string) error {
  53. key = c.prefix + key
  54. if err := c.c.Del(graceful.GetManager().HammerContext(), key).Err(); err != nil {
  55. return err
  56. }
  57. if c.occupyMode {
  58. return nil
  59. }
  60. return c.c.HDel(graceful.GetManager().HammerContext(), c.hsetName, key).Err()
  61. }
  62. // Incr increases cached int-type value by given key as a counter.
  63. func (c *RedisCacher) Incr(key string) error {
  64. if !c.IsExist(key) {
  65. return fmt.Errorf("key '%s' not exist", key)
  66. }
  67. return c.c.Incr(graceful.GetManager().HammerContext(), c.prefix+key).Err()
  68. }
  69. // Decr decreases cached int-type value by given key as a counter.
  70. func (c *RedisCacher) Decr(key string) error {
  71. if !c.IsExist(key) {
  72. return fmt.Errorf("key '%s' not exist", key)
  73. }
  74. return c.c.Decr(graceful.GetManager().HammerContext(), c.prefix+key).Err()
  75. }
  76. // IsExist returns true if cached value exists.
  77. func (c *RedisCacher) IsExist(key string) bool {
  78. if c.c.Exists(graceful.GetManager().HammerContext(), c.prefix+key).Val() == 1 {
  79. return true
  80. }
  81. if !c.occupyMode {
  82. c.c.HDel(graceful.GetManager().HammerContext(), c.hsetName, c.prefix+key)
  83. }
  84. return false
  85. }
  86. // Flush deletes all cached data.
  87. func (c *RedisCacher) Flush() error {
  88. if c.occupyMode {
  89. return c.c.FlushDB(graceful.GetManager().HammerContext()).Err()
  90. }
  91. keys, err := c.c.HKeys(graceful.GetManager().HammerContext(), c.hsetName).Result()
  92. if err != nil {
  93. return err
  94. }
  95. if err = c.c.Del(graceful.GetManager().HammerContext(), keys...).Err(); err != nil {
  96. return err
  97. }
  98. return c.c.Del(graceful.GetManager().HammerContext(), c.hsetName).Err()
  99. }
  100. // StartAndGC starts GC routine based on config string settings.
  101. // AdapterConfig: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180,hset_name=MacaronCache,prefix=cache:
  102. func (c *RedisCacher) StartAndGC(opts cache.Options) error {
  103. c.hsetName = "MacaronCache"
  104. c.occupyMode = opts.OccupyMode
  105. uri := nosql.ToRedisURI(opts.AdapterConfig)
  106. c.c = nosql.GetManager().GetRedisClient(uri.String())
  107. for k, v := range uri.Query() {
  108. switch k {
  109. case "hset_name":
  110. c.hsetName = v[0]
  111. case "prefix":
  112. c.prefix = v[0]
  113. }
  114. }
  115. return c.c.Ping(graceful.GetManager().HammerContext()).Err()
  116. }
  117. func init() {
  118. cache.Register("redis", &RedisCacher{})
  119. }