[FEAT] Only implement used API of Redis client
- Currently for the `nosql` module (which simply said provides a manager for redis clients) returns the [`redis.UniversalClient`](https://pkg.go.dev/github.com/redis/go-redis/v9#UniversalClient) interface. The interfaces exposes all available commands. - In generalm, dead code elimination should be able to take care of not generating the machine code for methods that aren't being used. However in this specific case, dead code elimination either is disabled or gives up on trying because of exhaustive call stack the client by `GetRedisClient` is used. - Help the Go compiler by explicitly specifying which methods we use. This reduces the binary size by ~400KB (397312 bytes). As Go no longer generate machine code for commands that aren't being used. - There's a **CAVEAT** with this, if a developer wants to use a new method that isn't specified, they will have to know about this hack (by following the definition of existing Redis methods) and add the method definition from the Redis library to the `RedisClient` interface.
This commit is contained in:
parent
1004ecd56b
commit
9df10c5ac5
|
@ -12,12 +12,11 @@ import (
|
||||||
"code.gitea.io/gitea/modules/nosql"
|
"code.gitea.io/gitea/modules/nosql"
|
||||||
|
|
||||||
"code.forgejo.org/go-chi/cache"
|
"code.forgejo.org/go-chi/cache"
|
||||||
"github.com/redis/go-redis/v9"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RedisCacher represents a redis cache adapter implementation.
|
// RedisCacher represents a redis cache adapter implementation.
|
||||||
type RedisCacher struct {
|
type RedisCacher struct {
|
||||||
c redis.UniversalClient
|
c nosql.RedisClient
|
||||||
prefix string
|
prefix string
|
||||||
hsetName string
|
hsetName string
|
||||||
occupyMode bool
|
occupyMode bool
|
||||||
|
|
|
@ -27,8 +27,46 @@ type Manager struct {
|
||||||
LevelDBConnections map[string]*levelDBHolder
|
LevelDBConnections map[string]*levelDBHolder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RedisClient is a subset of redis.UniversalClient, it exposes less methods
|
||||||
|
// to avoid generating machine code for unused methods. New method definitions
|
||||||
|
// should be copied from the definitions in the Redis library github.com/redis/go-redis.
|
||||||
|
type RedisClient interface {
|
||||||
|
// redis.GenericCmdable
|
||||||
|
Del(ctx context.Context, keys ...string) *redis.IntCmd
|
||||||
|
Exists(ctx context.Context, keys ...string) *redis.IntCmd
|
||||||
|
|
||||||
|
// redis.ListCmdable
|
||||||
|
RPush(ctx context.Context, key string, values ...any) *redis.IntCmd
|
||||||
|
LPop(ctx context.Context, key string) *redis.StringCmd
|
||||||
|
LLen(ctx context.Context, key string) *redis.IntCmd
|
||||||
|
|
||||||
|
// redis.StringCmdable
|
||||||
|
Decr(ctx context.Context, key string) *redis.IntCmd
|
||||||
|
Incr(ctx context.Context, key string) *redis.IntCmd
|
||||||
|
Set(ctx context.Context, key string, value any, expiration time.Duration) *redis.StatusCmd
|
||||||
|
Get(ctx context.Context, key string) *redis.StringCmd
|
||||||
|
|
||||||
|
// redis.HashCmdable
|
||||||
|
HSet(ctx context.Context, key string, values ...any) *redis.IntCmd
|
||||||
|
HDel(ctx context.Context, key string, fields ...string) *redis.IntCmd
|
||||||
|
HKeys(ctx context.Context, key string) *redis.StringSliceCmd
|
||||||
|
|
||||||
|
// redis.SetCmdable
|
||||||
|
SAdd(ctx context.Context, key string, members ...any) *redis.IntCmd
|
||||||
|
SRem(ctx context.Context, key string, members ...any) *redis.IntCmd
|
||||||
|
SIsMember(ctx context.Context, key string, member any) *redis.BoolCmd
|
||||||
|
|
||||||
|
// redis.Cmdable
|
||||||
|
DBSize(ctx context.Context) *redis.IntCmd
|
||||||
|
FlushDB(ctx context.Context) *redis.StatusCmd
|
||||||
|
Ping(ctx context.Context) *redis.StatusCmd
|
||||||
|
|
||||||
|
// redis.UniversalClient
|
||||||
|
Close() error
|
||||||
|
}
|
||||||
|
|
||||||
type redisClientHolder struct {
|
type redisClientHolder struct {
|
||||||
redis.UniversalClient
|
RedisClient
|
||||||
name []string
|
name []string
|
||||||
count int64
|
count int64
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,11 +39,11 @@ func (m *Manager) CloseRedisClient(connection string) error {
|
||||||
for _, name := range client.name {
|
for _, name := range client.name {
|
||||||
delete(m.RedisConnections, name)
|
delete(m.RedisConnections, name)
|
||||||
}
|
}
|
||||||
return client.UniversalClient.Close()
|
return client.RedisClient.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRedisClient gets a redis client for a particular connection
|
// GetRedisClient gets a redis client for a particular connection
|
||||||
func (m *Manager) GetRedisClient(connection string) (client redis.UniversalClient) {
|
func (m *Manager) GetRedisClient(connection string) (client RedisClient) {
|
||||||
// Because we want associate any goroutines created by this call to the main nosqldb context we need to
|
// Because we want associate any goroutines created by this call to the main nosqldb context we need to
|
||||||
// wrap this in a goroutine labelled with the nosqldb context
|
// wrap this in a goroutine labelled with the nosqldb context
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
@ -67,7 +67,7 @@ func (m *Manager) GetRedisClient(connection string) (client redis.UniversalClien
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) getRedisClient(connection string) redis.UniversalClient {
|
func (m *Manager) getRedisClient(connection string) RedisClient {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
client, ok := m.RedisConnections[connection]
|
client, ok := m.RedisConnections[connection]
|
||||||
|
@ -102,24 +102,24 @@ func (m *Manager) getRedisClient(connection string) redis.UniversalClient {
|
||||||
opts.TLSConfig = tlsConfig
|
opts.TLSConfig = tlsConfig
|
||||||
fallthrough
|
fallthrough
|
||||||
case "redis+sentinel":
|
case "redis+sentinel":
|
||||||
client.UniversalClient = redis.NewFailoverClient(opts.Failover())
|
client.RedisClient = redis.NewFailoverClient(opts.Failover())
|
||||||
case "redis+clusters":
|
case "redis+clusters":
|
||||||
fallthrough
|
fallthrough
|
||||||
case "rediss+cluster":
|
case "rediss+cluster":
|
||||||
opts.TLSConfig = tlsConfig
|
opts.TLSConfig = tlsConfig
|
||||||
fallthrough
|
fallthrough
|
||||||
case "redis+cluster":
|
case "redis+cluster":
|
||||||
client.UniversalClient = redis.NewClusterClient(opts.Cluster())
|
client.RedisClient = redis.NewClusterClient(opts.Cluster())
|
||||||
case "redis+socket":
|
case "redis+socket":
|
||||||
simpleOpts := opts.Simple()
|
simpleOpts := opts.Simple()
|
||||||
simpleOpts.Network = "unix"
|
simpleOpts.Network = "unix"
|
||||||
simpleOpts.Addr = path.Join(uri.Host, uri.Path)
|
simpleOpts.Addr = path.Join(uri.Host, uri.Path)
|
||||||
client.UniversalClient = redis.NewClient(simpleOpts)
|
client.RedisClient = redis.NewClient(simpleOpts)
|
||||||
case "rediss":
|
case "rediss":
|
||||||
opts.TLSConfig = tlsConfig
|
opts.TLSConfig = tlsConfig
|
||||||
fallthrough
|
fallthrough
|
||||||
case "redis":
|
case "redis":
|
||||||
client.UniversalClient = redis.NewClient(opts.Simple())
|
client.RedisClient = redis.NewClient(opts.Simple())
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type baseRedis struct {
|
type baseRedis struct {
|
||||||
client redis.UniversalClient
|
client nosql.RedisClient
|
||||||
isUnique bool
|
isUnique bool
|
||||||
cfg *BaseConfig
|
cfg *BaseConfig
|
||||||
prefix string
|
prefix string
|
||||||
|
@ -26,7 +26,7 @@ type baseRedis struct {
|
||||||
|
|
||||||
var _ baseQueue = (*baseRedis)(nil)
|
var _ baseQueue = (*baseRedis)(nil)
|
||||||
|
|
||||||
func newBaseRedisGeneric(cfg *BaseConfig, unique bool, client redis.UniversalClient) (baseQueue, error) {
|
func newBaseRedisGeneric(cfg *BaseConfig, unique bool, client nosql.RedisClient) (baseQueue, error) {
|
||||||
if client == nil {
|
if client == nil {
|
||||||
client = nosql.GetManager().GetRedisClient(cfg.ConnStr)
|
client = nosql.GetManager().GetRedisClient(cfg.ConnStr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,11 @@ import (
|
||||||
"code.gitea.io/gitea/modules/nosql"
|
"code.gitea.io/gitea/modules/nosql"
|
||||||
|
|
||||||
"code.forgejo.org/go-chi/session"
|
"code.forgejo.org/go-chi/session"
|
||||||
"github.com/redis/go-redis/v9"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RedisStore represents a redis session store implementation.
|
// RedisStore represents a redis session store implementation.
|
||||||
type RedisStore struct {
|
type RedisStore struct {
|
||||||
c redis.UniversalClient
|
c nosql.RedisClient
|
||||||
prefix, sid string
|
prefix, sid string
|
||||||
duration time.Duration
|
duration time.Duration
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
|
@ -39,7 +38,7 @@ type RedisStore struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRedisStore creates and returns a redis session store.
|
// NewRedisStore creates and returns a redis session store.
|
||||||
func NewRedisStore(c redis.UniversalClient, prefix, sid string, dur time.Duration, kv map[any]any) *RedisStore {
|
func NewRedisStore(c nosql.RedisClient, prefix, sid string, dur time.Duration, kv map[any]any) *RedisStore {
|
||||||
return &RedisStore{
|
return &RedisStore{
|
||||||
c: c,
|
c: c,
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
|
@ -106,7 +105,7 @@ func (s *RedisStore) Flush() error {
|
||||||
|
|
||||||
// RedisProvider represents a redis session provider implementation.
|
// RedisProvider represents a redis session provider implementation.
|
||||||
type RedisProvider struct {
|
type RedisProvider struct {
|
||||||
c redis.UniversalClient
|
c nosql.RedisClient
|
||||||
duration time.Duration
|
duration time.Duration
|
||||||
prefix string
|
prefix string
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue