Skip to content

Commit 7f8e319

Browse files
zeripathtechknowlogicklafriks
authored
Allow common redis and leveldb connections (#12385)
* Allow common redis and leveldb connections Prevents multiple reopening of redis and leveldb connections to the same place by sharing connections. Further allows for more configurable redis connection type using the redisURI and a leveldbURI scheme. Signed-off-by: Andrew Thornton <art27@cantab.net> * add unit-test Signed-off-by: Andrew Thornton <art27@cantab.net> * as per @lunny Signed-off-by: Andrew Thornton <art27@cantab.net> * add test Signed-off-by: Andrew Thornton <art27@cantab.net> * Update modules/cache/cache_redis.go * Update modules/queue/queue_disk.go * Update modules/cache/cache_redis.go * Update modules/cache/cache_redis.go * Update modules/queue/unique_queue_disk.go * Update modules/queue/queue_disk.go * Update modules/queue/unique_queue_disk.go * Update modules/session/redis.go Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: Lauris BH <lauris@nix.lv>
1 parent f404bdd commit 7f8e319

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+4876
-3087
lines changed

custom/conf/app.example.ini

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,10 @@ LENGTH = 20
467467
BATCH_LENGTH = 20
468468
; Connection string for redis queues this will store the redis connection string.
469469
CONN_STR = "addrs=127.0.0.1:6379 db=0"
470-
; Provide the suffix of the default redis queue name - specific queues can be overriden within in their [queue.name] sections.
470+
; Provides the suffix of the default redis/disk queue name - specific queues can be overriden within in their [queue.name] sections.
471471
QUEUE_NAME = "_queue"
472+
; Provides the suffix of the default redis/disk unique queue set name - specific queues can be overriden within in their [queue.name] sections.
473+
SET_NAME = "_unique"
472474
; If the queue cannot be created at startup - level queues may need a timeout at startup - wrap the queue:
473475
WRAP_IF_NECESSARY = true
474476
; Attempt to create the wrapped queue at max

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -308,15 +308,13 @@ relation to port exhaustion.
308308
## Queue (`queue` and `queue.*`)
309309

310310
- `TYPE`: **persistable-channel**: General queue type, currently support: `persistable-channel`, `channel`, `level`, `redis`, `dummy`
311-
- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for inidividual queues can be set in `queue.name` sections but will default to `DATADIR/`**`name`**.
311+
- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for individual queues can be set in `queue.name` sections but will default to `DATADIR/`**`name`**.
312312
- `LENGTH`: **20**: Maximal queue size before channel queues block
313313
- `BATCH_LENGTH`: **20**: Batch data before passing to the handler
314-
- `CONN_STR`: **addrs=127.0.0.1:6379 db=0**: Connection string for the redis queue type.
315-
- `QUEUE_NAME`: **_queue**: The suffix for default redis queue name. Individual queues will default to **`name`**`QUEUE_NAME` but can be overriden in the specific `queue.name` section.
316-
- `SET_NAME`: **_unique**: The suffix that will added to the default redis
317-
set name for unique queues. Individual queues will default to
318-
**`name`**`QUEUE_NAME`_`SET_NAME`_ but can be overridden in the specific
319-
`queue.name` section.
314+
- `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. Options can be set using query params. Similarly LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**
315+
- `QUEUE_NAME`: **_queue**: The suffix for default redis and disk queue name. Individual queues will default to **`name`**`QUEUE_NAME` but can be overriden in the specific `queue.name` section.
316+
- `SET_NAME`: **_unique**: The suffix that will be added to the default redis and disk queue `set` name for unique queues. Individual queues will default to
317+
**`name`**`QUEUE_NAME`_`SET_NAME`_ but can be overridden in the specific `queue.name` section.
320318
- `WRAP_IF_NECESSARY`: **true**: Will wrap queues with a timeoutable queue if the selected queue is not ready to be created - (Only relevant for the level queue.)
321319
- `MAX_ATTEMPTS`: **10**: Maximum number of attempts to create the wrapped queue
322320
- `TIMEOUT`: **GRACEFUL_HAMMER_TIME + 30s**: Timeout the creation of the wrapped queue if it takes longer than this to create.
@@ -459,7 +457,7 @@ set name for unique queues. Individual queues will default to
459457
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, or `memcache`.
460458
- `INTERVAL`: **60**: Garbage Collection interval (sec), for memory cache only.
461459
- `HOST`: **\<empty\>**: Connection string for `redis` and `memcache`.
462-
- Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180`
460+
- Redis: `redis://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
463461
- Memcache: `127.0.0.1:9090;127.0.0.1:9091`
464462
- `ITEM_TTL`: **16h**: Time to keep items in cache if not used, Setting it to 0 disables caching.
465463

@@ -708,7 +706,7 @@ Task queue configuration has been moved to `queue.task`. However, the below conf
708706

709707
- `QUEUE_TYPE`: **channel**: Task queue type, could be `channel` or `redis`.
710708
- `QUEUE_LENGTH`: **1000**: Task queue length, available only when `QUEUE_TYPE` is `channel`.
711-
- `QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If redis needs a password, use `addrs=127.0.0.1:6379 password=123 db=0`.
709+
- `QUEUE_CONN_STR`: **redis://127.0.0.1:6379/0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If redis needs a password, use `redis://123@127.0.0.1:6379/0`.
712710

713711
## Migrations (`migrations`)
714712

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ require (
3838
github.com/go-enry/go-enry/v2 v2.5.2
3939
github.com/go-git/go-billy/v5 v5.0.0
4040
github.com/go-git/go-git/v5 v5.1.0
41-
github.com/go-redis/redis v6.15.2+incompatible
41+
github.com/go-redis/redis/v7 v7.4.0
4242
github.com/go-sql-driver/mysql v1.5.0
4343
github.com/go-swagger/go-swagger v0.25.0
4444
github.com/go-testfixtures/testfixtures/v3 v3.4.0
@@ -88,6 +88,7 @@ require (
8888
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect
8989
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
9090
github.com/stretchr/testify v1.6.1
91+
github.com/syndtr/goleveldb v1.0.0
9192
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect
9293
github.com/tinylib/msgp v1.1.2 // indirect
9394
github.com/tstranex/u2f v1.0.0

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ github.com/go-openapi/validate v0.19.10 h1:tG3SZ5DC5KF4cyt7nqLVcQXGj5A7mpaYkAcNP
342342
github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8=
343343
github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
344344
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
345+
github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4=
346+
github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
345347
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
346348
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
347349
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
@@ -730,9 +732,13 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
730732
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
731733
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
732734
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
735+
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
736+
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
733737
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
734738
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
735739
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
740+
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
741+
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
736742
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
737743
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
738744
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@@ -1014,6 +1020,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
10141020
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
10151021
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
10161022
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
1023+
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
10171024
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
10181025
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
10191026
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=

modules/cache/cache.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
mc "gitea.com/macaron/cache"
1414

1515
_ "gitea.com/macaron/cache/memcache" // memcache plugin for cache
16-
_ "gitea.com/macaron/cache/redis"
1716
)
1817

1918
var (

vendor/gitea.com/macaron/cache/redis/redis.go renamed to modules/cache/cache_redis.go

Lines changed: 15 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,23 @@
1-
// Copyright 2013 Beego Authors
2-
// Copyright 2014 The Macaron Authors
3-
//
4-
// Licensed under the Apache License, Version 2.0 (the "License"): you may
5-
// not use this file except in compliance with the License. You may obtain
6-
// a copy of the License at
7-
//
8-
// http://www.apache.org/licenses/LICENSE-2.0
9-
//
10-
// Unless required by applicable law or agreed to in writing, software
11-
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12-
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13-
// License for the specific language governing permissions and limitations
14-
// under the License.
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.
154

165
package cache
176

187
import (
198
"fmt"
20-
"strings"
219
"time"
2210

23-
"github.com/go-redis/redis"
24-
"github.com/unknwon/com"
25-
"gopkg.in/ini.v1"
11+
"code.gitea.io/gitea/modules/nosql"
2612

2713
"gitea.com/macaron/cache"
14+
"github.com/go-redis/redis/v7"
15+
"github.com/unknwon/com"
2816
)
2917

3018
// RedisCacher represents a redis cache adapter implementation.
3119
type RedisCacher struct {
32-
c *redis.Client
20+
c redis.UniversalClient
3321
prefix string
3422
hsetName string
3523
occupyMode bool
@@ -112,7 +100,7 @@ func (c *RedisCacher) IsExist(key string) bool {
112100
// Flush deletes all cached data.
113101
func (c *RedisCacher) Flush() error {
114102
if c.occupyMode {
115-
return c.c.FlushDb().Err()
103+
return c.c.FlushDB().Err()
116104
}
117105

118106
keys, err := c.c.HKeys(c.hsetName).Result()
@@ -131,46 +119,20 @@ func (c *RedisCacher) StartAndGC(opts cache.Options) error {
131119
c.hsetName = "MacaronCache"
132120
c.occupyMode = opts.OccupyMode
133121

134-
cfg, err := ini.Load([]byte(strings.Replace(opts.AdapterConfig, ",", "\n", -1)))
135-
if err != nil {
136-
return err
137-
}
122+
uri := nosql.ToRedisURI(opts.AdapterConfig)
138123

139-
opt := &redis.Options{
140-
Network: "tcp",
141-
}
142-
for k, v := range cfg.Section("").KeysHash() {
124+
c.c = nosql.GetManager().GetRedisClient(uri.String())
125+
126+
for k, v := range uri.Query() {
143127
switch k {
144-
case "network":
145-
opt.Network = v
146-
case "addr":
147-
opt.Addr = v
148-
case "password":
149-
opt.Password = v
150-
case "db":
151-
opt.DB = com.StrTo(v).MustInt()
152-
case "pool_size":
153-
opt.PoolSize = com.StrTo(v).MustInt()
154-
case "idle_timeout":
155-
opt.IdleTimeout, err = time.ParseDuration(v + "s")
156-
if err != nil {
157-
return fmt.Errorf("error parsing idle timeout: %v", err)
158-
}
159128
case "hset_name":
160-
c.hsetName = v
129+
c.hsetName = v[0]
161130
case "prefix":
162-
c.prefix = v
163-
default:
164-
return fmt.Errorf("session/redis: unsupported option '%s'", k)
131+
c.prefix = v[0]
165132
}
166133
}
167134

168-
c.c = redis.NewClient(opt)
169-
if err = c.c.Ping().Err(); err != nil {
170-
return err
171-
}
172-
173-
return nil
135+
return c.c.Ping().Err()
174136
}
175137

176138
func init() {

modules/nosql/leveldb.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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+
5+
package nosql
6+
7+
import "net/url"
8+
9+
// ToLevelDBURI converts old style connections to a LevelDBURI
10+
//
11+
// A LevelDBURI matches the pattern:
12+
//
13+
// leveldb://path[?[option=value]*]
14+
//
15+
// We have previously just provided the path but this prevent other options
16+
func ToLevelDBURI(connection string) *url.URL {
17+
uri, err := url.Parse(connection)
18+
if err == nil && uri.Scheme == "leveldb" {
19+
return uri
20+
}
21+
uri, _ = url.Parse("leveldb://common")
22+
uri.Host = ""
23+
uri.Path = connection
24+
return uri
25+
}

modules/nosql/manager.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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+
5+
package nosql
6+
7+
import (
8+
"strconv"
9+
"sync"
10+
"time"
11+
12+
"github.com/go-redis/redis/v7"
13+
"github.com/syndtr/goleveldb/leveldb"
14+
)
15+
16+
var manager *Manager
17+
18+
// Manager is the nosql connection manager
19+
type Manager struct {
20+
mutex sync.Mutex
21+
22+
RedisConnections map[string]*redisClientHolder
23+
LevelDBConnections map[string]*levelDBHolder
24+
}
25+
26+
type redisClientHolder struct {
27+
redis.UniversalClient
28+
name []string
29+
count int64
30+
}
31+
32+
func (r *redisClientHolder) Close() error {
33+
return manager.CloseRedisClient(r.name[0])
34+
}
35+
36+
type levelDBHolder struct {
37+
name []string
38+
count int64
39+
db *leveldb.DB
40+
}
41+
42+
func init() {
43+
_ = GetManager()
44+
}
45+
46+
// GetManager returns a Manager and initializes one as singleton is there's none yet
47+
func GetManager() *Manager {
48+
if manager == nil {
49+
manager = &Manager{
50+
RedisConnections: make(map[string]*redisClientHolder),
51+
LevelDBConnections: make(map[string]*levelDBHolder),
52+
}
53+
}
54+
return manager
55+
}
56+
57+
func valToTimeDuration(vs []string) (result time.Duration) {
58+
var err error
59+
for _, v := range vs {
60+
result, err = time.ParseDuration(v)
61+
if err != nil {
62+
var val int
63+
val, err = strconv.Atoi(v)
64+
result = time.Duration(val)
65+
}
66+
if err == nil {
67+
return
68+
}
69+
}
70+
return
71+
}

0 commit comments

Comments
 (0)