redis.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // Copyright 2014 beego Author. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Package redis for cache provider
  15. //
  16. // depend on github.com/garyburd/redigo/redis
  17. //
  18. // go install github.com/garyburd/redigo/redis
  19. //
  20. // Usage:
  21. // import(
  22. // _ "github.com/astaxie/beego/cache/redis"
  23. // "github.com/astaxie/beego/cache"
  24. // )
  25. //
  26. // bm, err := cache.NewCache("redis", `{"conn":"127.0.0.1:11211"}`)
  27. //
  28. // more docs http://beego.me/docs/module/cache.md
  29. package redis
  30. import (
  31. "encoding/json"
  32. "errors"
  33. "strconv"
  34. "time"
  35. "github.com/garyburd/redigo/redis"
  36. "github.com/astaxie/beego/cache"
  37. )
  38. var (
  39. // DefaultKey the collection name of redis for cache adapter.
  40. DefaultKey = "beecacheRedis"
  41. )
  42. // Cache is Redis cache adapter.
  43. type Cache struct {
  44. p *redis.Pool // redis connection pool
  45. conninfo string
  46. dbNum int
  47. key string
  48. password string
  49. }
  50. // NewRedisCache create new redis cache with default collection name.
  51. func NewRedisCache() cache.Cache {
  52. return &Cache{key: DefaultKey}
  53. }
  54. // actually do the redis cmds
  55. func (rc *Cache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
  56. c := rc.p.Get()
  57. defer c.Close()
  58. return c.Do(commandName, args...)
  59. }
  60. // Get cache from redis.
  61. func (rc *Cache) Get(key string) interface{} {
  62. if v, err := rc.do("GET", key); err == nil {
  63. return v
  64. }
  65. return nil
  66. }
  67. // GetMulti get cache from redis.
  68. func (rc *Cache) GetMulti(keys []string) []interface{} {
  69. size := len(keys)
  70. var rv []interface{}
  71. c := rc.p.Get()
  72. defer c.Close()
  73. var err error
  74. for _, key := range keys {
  75. err = c.Send("GET", key)
  76. if err != nil {
  77. goto ERROR
  78. }
  79. }
  80. if err = c.Flush(); err != nil {
  81. goto ERROR
  82. }
  83. for i := 0; i < size; i++ {
  84. if v, err := c.Receive(); err == nil {
  85. rv = append(rv, v.([]byte))
  86. } else {
  87. rv = append(rv, err)
  88. }
  89. }
  90. return rv
  91. ERROR:
  92. rv = rv[0:0]
  93. for i := 0; i < size; i++ {
  94. rv = append(rv, nil)
  95. }
  96. return rv
  97. }
  98. // Put put cache to redis.
  99. func (rc *Cache) Put(key string, val interface{}, timeout time.Duration) error {
  100. var err error
  101. if _, err = rc.do("SETEX", key, int64(timeout/time.Second), val); err != nil {
  102. return err
  103. }
  104. if _, err = rc.do("HSET", rc.key, key, true); err != nil {
  105. return err
  106. }
  107. return err
  108. }
  109. // Delete delete cache in redis.
  110. func (rc *Cache) Delete(key string) error {
  111. var err error
  112. if _, err = rc.do("DEL", key); err != nil {
  113. return err
  114. }
  115. _, err = rc.do("HDEL", rc.key, key)
  116. return err
  117. }
  118. // IsExist check cache's existence in redis.
  119. func (rc *Cache) IsExist(key string) bool {
  120. v, err := redis.Bool(rc.do("EXISTS", key))
  121. if err != nil {
  122. return false
  123. }
  124. if v == false {
  125. if _, err = rc.do("HDEL", rc.key, key); err != nil {
  126. return false
  127. }
  128. }
  129. return v
  130. }
  131. // Incr increase counter in redis.
  132. func (rc *Cache) Incr(key string) error {
  133. _, err := redis.Bool(rc.do("INCRBY", key, 1))
  134. return err
  135. }
  136. // Decr decrease counter in redis.
  137. func (rc *Cache) Decr(key string) error {
  138. _, err := redis.Bool(rc.do("INCRBY", key, -1))
  139. return err
  140. }
  141. // ClearAll clean all cache in redis. delete this redis collection.
  142. func (rc *Cache) ClearAll() error {
  143. cachedKeys, err := redis.Strings(rc.do("HKEYS", rc.key))
  144. if err != nil {
  145. return err
  146. }
  147. for _, str := range cachedKeys {
  148. if _, err = rc.do("DEL", str); err != nil {
  149. return err
  150. }
  151. }
  152. _, err = rc.do("DEL", rc.key)
  153. return err
  154. }
  155. // StartAndGC start redis cache adapter.
  156. // config is like {"key":"collection key","conn":"connection info","dbNum":"0"}
  157. // the cache item in redis are stored forever,
  158. // so no gc operation.
  159. func (rc *Cache) StartAndGC(config string) error {
  160. var cf map[string]string
  161. json.Unmarshal([]byte(config), &cf)
  162. if _, ok := cf["key"]; !ok {
  163. cf["key"] = DefaultKey
  164. }
  165. if _, ok := cf["conn"]; !ok {
  166. return errors.New("config has no conn key")
  167. }
  168. if _, ok := cf["dbNum"]; !ok {
  169. cf["dbNum"] = "0"
  170. }
  171. if _, ok := cf["password"]; !ok {
  172. cf["password"] = ""
  173. }
  174. rc.key = cf["key"]
  175. rc.conninfo = cf["conn"]
  176. rc.dbNum, _ = strconv.Atoi(cf["dbNum"])
  177. rc.password = cf["password"]
  178. rc.connectInit()
  179. c := rc.p.Get()
  180. defer c.Close()
  181. return c.Err()
  182. }
  183. // connect to redis.
  184. func (rc *Cache) connectInit() {
  185. dialFunc := func() (c redis.Conn, err error) {
  186. c, err = redis.Dial("tcp", rc.conninfo)
  187. if err != nil {
  188. return nil, err
  189. }
  190. if rc.password != "" {
  191. if _, err := c.Do("AUTH", rc.password); err != nil {
  192. c.Close()
  193. return nil, err
  194. }
  195. }
  196. _, selecterr := c.Do("SELECT", rc.dbNum)
  197. if selecterr != nil {
  198. c.Close()
  199. return nil, selecterr
  200. }
  201. return
  202. }
  203. // initialize a new pool
  204. rc.p = &redis.Pool{
  205. MaxIdle: 3,
  206. IdleTimeout: 180 * time.Second,
  207. Dial: dialFunc,
  208. }
  209. }
  210. func init() {
  211. cache.Register("redis", NewRedisCache)
  212. }