loading up the forgejo repo on tangled to test page performance
at forgejo 4.2 kB view raw
1// Copyright 2020 The Gitea Authors. All rights reserved. 2// SPDX-License-Identifier: MIT 3 4package cache 5 6import ( 7 "fmt" 8 "strconv" 9 "time" 10 11 "forgejo.org/modules/graceful" 12 "forgejo.org/modules/nosql" 13 14 "code.forgejo.org/go-chi/cache" 15) 16 17// RedisCacher represents a redis cache adapter implementation. 18type RedisCacher struct { 19 c nosql.RedisClient 20 prefix string 21 hsetName string 22 occupyMode bool 23} 24 25// toStr convert string/int/int64 interface to string. it's only used by the RedisCacher.Put internally 26func toStr(v any) string { 27 if v == nil { 28 return "" 29 } 30 switch v := v.(type) { 31 case string: 32 return v 33 case []byte: 34 return string(v) 35 case int: 36 return strconv.FormatInt(int64(v), 10) 37 case int64: 38 return strconv.FormatInt(v, 10) 39 default: 40 return fmt.Sprint(v) // as what the old com.ToStr does in most cases 41 } 42} 43 44// Put puts value (string type) into cache with key and expire time. 45// If expired is 0, it lives forever. 46func (c *RedisCacher) Put(key string, val any, expire int64) error { 47 // this function is not well-designed, it only puts string values into cache 48 key = c.prefix + key 49 if expire == 0 { 50 if err := c.c.Set(graceful.GetManager().HammerContext(), key, toStr(val), 0).Err(); err != nil { 51 return err 52 } 53 } else { 54 dur := time.Duration(expire) * time.Second 55 if err := c.c.Set(graceful.GetManager().HammerContext(), key, toStr(val), dur).Err(); err != nil { 56 return err 57 } 58 } 59 60 if c.occupyMode { 61 return nil 62 } 63 return c.c.HSet(graceful.GetManager().HammerContext(), c.hsetName, key, "0").Err() 64} 65 66// Get gets cached value by given key. 67func (c *RedisCacher) Get(key string) any { 68 val, err := c.c.Get(graceful.GetManager().HammerContext(), c.prefix+key).Result() 69 if err != nil { 70 return nil 71 } 72 return val 73} 74 75// Delete deletes cached value by given key. 76func (c *RedisCacher) Delete(key string) error { 77 key = c.prefix + key 78 if err := c.c.Del(graceful.GetManager().HammerContext(), key).Err(); err != nil { 79 return err 80 } 81 82 if c.occupyMode { 83 return nil 84 } 85 return c.c.HDel(graceful.GetManager().HammerContext(), c.hsetName, key).Err() 86} 87 88// Incr increases cached int-type value by given key as a counter. 89func (c *RedisCacher) Incr(key string) error { 90 if !c.IsExist(key) { 91 return fmt.Errorf("key '%s' not exist", key) 92 } 93 return c.c.Incr(graceful.GetManager().HammerContext(), c.prefix+key).Err() 94} 95 96// Decr decreases cached int-type value by given key as a counter. 97func (c *RedisCacher) Decr(key string) error { 98 if !c.IsExist(key) { 99 return fmt.Errorf("key '%s' not exist", key) 100 } 101 return c.c.Decr(graceful.GetManager().HammerContext(), c.prefix+key).Err() 102} 103 104// IsExist returns true if cached value exists. 105func (c *RedisCacher) IsExist(key string) bool { 106 if c.c.Exists(graceful.GetManager().HammerContext(), c.prefix+key).Val() == 1 { 107 return true 108 } 109 110 if !c.occupyMode { 111 c.c.HDel(graceful.GetManager().HammerContext(), c.hsetName, c.prefix+key) 112 } 113 return false 114} 115 116// Flush deletes all cached data. 117func (c *RedisCacher) Flush() error { 118 if c.occupyMode { 119 return c.c.FlushDB(graceful.GetManager().HammerContext()).Err() 120 } 121 122 keys, err := c.c.HKeys(graceful.GetManager().HammerContext(), c.hsetName).Result() 123 if err != nil { 124 return err 125 } 126 if err = c.c.Del(graceful.GetManager().HammerContext(), keys...).Err(); err != nil { 127 return err 128 } 129 return c.c.Del(graceful.GetManager().HammerContext(), c.hsetName).Err() 130} 131 132// StartAndGC starts GC routine based on config string settings. 133// AdapterConfig: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180,hset_name=MacaronCache,prefix=cache: 134func (c *RedisCacher) StartAndGC(opts cache.Options) error { 135 c.hsetName = "MacaronCache" 136 c.occupyMode = opts.OccupyMode 137 138 uri := nosql.ToRedisURI(opts.AdapterConfig) 139 140 c.c = nosql.GetManager().GetRedisClient(uri.String()) 141 142 for k, v := range uri.Query() { 143 switch k { 144 case "hset_name": 145 c.hsetName = v[0] 146 case "prefix": 147 c.prefix = v[0] 148 } 149 } 150 151 return c.c.Ping(graceful.GetManager().HammerContext()).Err() 152} 153 154// Ping tests if the cache is alive. 155func (c *RedisCacher) Ping() error { 156 return c.c.Ping(graceful.GetManager().HammerContext()).Err() 157} 158 159func init() { 160 cache.Register("redis", &RedisCacher{}) 161}