github.com/TykTechnologies/tyk/storage
No package summary is available.
Package
Files: 7. Third party imports: 2. Imports from organisation: 8. Tests: 0. Benchmarks: 0.
Constants
const (
HashSha256 = crypto.HashSha256
HashMurmur32 = crypto.HashMurmur32
HashMurmur64 = crypto.HashMurmur64
HashMurmur128 = crypto.HashMurmur128
)
const (
// DefaultConn is the default connection type. Not analytics and Not cache.
DefaultConn = "default"
// CacheConn is the cache connection type
CacheConn = "cache"
// AnalyticsConn is the analytics connection type
AnalyticsConn = "analytics"
)
const (
resourceOauthClient = "OauthClient"
resourceCertificate = "Certificate"
resourceApiKey = "ApiKey"
resourceKey = "Key"
)
Vars
ErrKeyNotFound is a standard error for when a key is not found in the storage engine
var ErrKeyNotFound = errors.New("key not found")
var ErrMDCBConnectionLost = errors.New("mdcb connection is lost")
var (
HashStr = crypto.HashStr
HashKey = crypto.HashKey
)
var (
GenerateToken = crypto.GenerateToken
TokenHashAlgo = crypto.TokenHashAlgo
TokenID = crypto.TokenID
TokenOrg = crypto.TokenOrg
)
var (
// ErrRedisIsDown is returned when we can't communicate with redis
ErrRedisIsDown = errors.New("storage: Redis is either down or was not configured")
// ErrStorageConn is returned when we can't get a connection from the ConnectionHandler
ErrStorageConn = fmt.Errorf("Error trying to get singleton instance: %w", ErrRedisIsDown)
)
var log = logger.Get()
Types
AnalyticsHandler
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type AnalyticsHandler interface {
Connect() bool
AppendToSetPipelined(string, [][]byte)
GetAndDeleteSet(string) []interface{}
SetExp(string, int64) error // Set key expiration
GetExp(string) (int64, error) // Returns expiry of a key
}
ConnectionHandler
ConnectionHandler is a wrapper around the storage connection. It allows to dynamically enable/disable talking with storage and mantain a connection map to different storage types.
| Field name | Field type | Comment |
|---|---|---|
| connections |
|
No comment on field. |
| connectionsMu |
|
No comment on field. |
| storageUp |
|
No comment on field. |
| disableStorage |
|
No comment on field. |
| ctx |
|
No comment on field. |
| reconnect |
|
No comment on field. |
type ConnectionHandler struct {
connections map[string]model.Connector
connectionsMu *sync.RWMutex
storageUp atomic.Value
disableStorage atomic.Value
ctx context.Context
reconnect chan struct{}
}
DummyStorage
DummyStorage is a simple in-memory storage structure used for testing or demonstration purposes. It simulates a storage system.
| Field name | Field type | Comment |
|---|---|---|
| Data |
|
No comment on field. |
| IndexList |
|
No comment on field. |
type DummyStorage struct {
Data map[string]string
IndexList map[string][]string
}
Handler
Handler is a standard interface to a storage backend, used by AuthorisationManager to read and write key values to the backend
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type Handler interface {
GetKey(string) (string, error) // Returned string is expected to be a JSON object (user.SessionState)
GetMultiKey([]string) ([]string, error)
GetRawKey(string) (string, error)
SetKey(string, string, int64) error // Second input string is expected to be a JSON object (user.SessionState)
SetRawKey(string, string, int64) error
SetExp(string, int64) error // Set key expiration
GetExp(string) (int64, error) // Returns expiry of a key
GetKeys(string) []string
DeleteKey(string) bool
DeleteAllKeys() bool
DeleteRawKey(string) bool
DeleteRawKeys([]string) bool
Connect() bool
GetKeysAndValues() map[string]string
GetKeysAndValuesWithFilter(string) map[string]string
DeleteKeys([]string) bool
Decrement(string)
IncrememntWithExpire(string, int64) int64
SetRollingWindow(key string, per int64, val string, pipeline bool) (int, []interface{})
GetRollingWindow(key string, per int64, pipeline bool) (int, []interface{})
GetSet(string) (map[string]string, error)
AddToSet(string, string)
GetAndDeleteSet(string) []interface{}
RemoveFromSet(string, string)
DeleteScanMatch(string) bool
GetKeyPrefix() string
AddToSortedSet(string, string, float64)
GetSortedSetRange(string, string, string) ([]string, []float64, error)
RemoveSortedSetRange(string, string, string) error
GetListRange(string, int64, int64) ([]string, error)
RemoveFromList(string, string) error
AppendToSet(string, string)
Exists(string) (bool, error)
}
MdcbStorage
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| local |
|
No comment on field. |
| rpc |
|
No comment on field. |
| logger |
|
No comment on field. |
| OnRPCCertPull |
|
No comment on field. |
type MdcbStorage struct {
local Handler
rpc Handler
logger *logrus.Entry
OnRPCCertPull func(key string, val string) error
}
RedisCluster
RedisCluster is a storage manager that uses the redis database.
| Field name | Field type | Comment |
|---|---|---|
| KeyPrefix |
|
No comment on field. |
| HashKeys |
|
No comment on field. |
| IsCache |
|
No comment on field. |
| IsAnalytics |
|
No comment on field. |
| ConnectionHandler |
|
No comment on field. |
| RedisController |
|
RedisController must remain for compatibility with goplugins |
| storageMu |
|
No comment on field. |
| kvStorage |
|
No comment on field. |
| flusherStorage |
|
No comment on field. |
| queueStorage |
|
No comment on field. |
| listStorage |
|
No comment on field. |
| setStorage |
|
No comment on field. |
| sortedSetStorage |
|
No comment on field. |
type RedisCluster struct {
KeyPrefix string
HashKeys bool
IsCache bool
IsAnalytics bool
ConnectionHandler *ConnectionHandler
// RedisController must remain for compatibility with goplugins
RedisController *RedisController
storageMu sync.Mutex
kvStorage model.KeyValue
flusherStorage model.Flusher
queueStorage model.Queue
listStorage model.List
setStorage model.Set
sortedSetStorage model.SortedSet
}
RedisController
RedisController acts as a shim to provide backward compatibility for Go plugins users. It facilitates connecting to Redis using Tyk's storage package in a way that doesn't break existing implementations. changes here are sensible
| Field name | Field type | Comment |
|---|---|---|
| connection |
|
No comment on field. |
type RedisController struct {
connection *ConnectionHandler
}
Functions
func NewConnectionHandler
NewConnectionHandler creates a new connection handler not connected
func NewConnectionHandler(ctx context.Context) *ConnectionHandler {
return &ConnectionHandler{
ctx: ctx,
reconnect: make(chan struct{}, 1),
connections: make(map[string]model.Connector),
connectionsMu: &sync.RWMutex{},
}
}
Cognitive complexity: 3, Cyclomatic complexity: 1
func NewConnector
NewConnector creates a new storage connection.
func NewConnector(connType string, conf config.Config) (model.Connector, error) {
cfg := conf.Storage
if connType == CacheConn && conf.EnableSeperateCacheStore {
cfg = conf.CacheStorage
} else if connType == AnalyticsConn && conf.EnableAnalytics && conf.EnableSeperateAnalyticsStore {
cfg = conf.AnalyticsStorage
}
log.Debug("Creating new " + connType + " Storage connection")
// poolSize applies per cluster node and not for the whole cluster.
poolSize := 500
if cfg.MaxActive > 0 {
poolSize = cfg.MaxActive
}
timeout := 5
if cfg.Timeout > 0 {
timeout = cfg.Timeout
}
opts := []model.Option{}
optsR := model.RedisOptions{
Username: cfg.Username,
Password: cfg.Password,
Host: cfg.Host,
Port: cfg.Port,
Timeout: timeout,
Hosts: cfg.Hosts,
Addrs: cfg.Addrs,
MasterName: cfg.MasterName,
SentinelPassword: cfg.SentinelPassword,
Database: cfg.Database,
MaxActive: poolSize,
EnableCluster: cfg.EnableCluster,
}
opts = append(opts, model.WithRedisConfig(&optsR))
if cfg.UseSSL {
tls := model.TLS{
Enable: cfg.UseSSL,
InsecureSkipVerify: cfg.SSLInsecureSkipVerify,
CAFile: cfg.CAFile,
CertFile: cfg.CertFile,
KeyFile: cfg.KeyFile,
MinVersion: cfg.TLSMinVersion,
MaxVersion: cfg.TLSMaxVersion,
}
opts = append(opts, model.WithTLS(&tls))
}
return connector.NewConnector(model.RedisV9Type, opts...)
}
Cognitive complexity: 13, Cyclomatic complexity: 9
func NewDummyStorage
NewDummyStorage creates and returns a new instance of DummyStorage.
func NewDummyStorage() *DummyStorage {
return &DummyStorage{
Data: make(map[string]string),
IndexList: make(map[string][]string),
}
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func NewMdcbStorage
func NewMdcbStorage(local, rpc Handler, log *logrus.Entry, OnRPCCertPull func(key string, val string) error) *MdcbStorage {
return &MdcbStorage{
local: local,
rpc: rpc,
logger: log,
OnRPCCertPull: OnRPCCertPull,
}
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func NewRedisController
NewRedisController initializes a new RedisController. This method ensures Go plugins can connect to Redis leveraging Tyk's internal storage mechanisms with minimal changes to their code.
func NewRedisController(ctx context.Context) *RedisController {
return &RedisController{
connection: NewConnectionHandler(ctx),
}
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func (*ConnectionHandler) Connect
Connect starts a go routine that periodically tries to connect to storage.
onConnect will be called when we have established a successful storage reconnection
func (rc *ConnectionHandler) Connect(ctx context.Context, onConnect func(), conf *config.Config) {
err := rc.initConnection(*conf)
if err != nil {
log.WithError(err).Error("Could not initialize connection to Redis cluster")
return
}
// First time connecting to the clusters. We need this for the first connection (and avoid waiting 1second for the rc.statusCheck loop).
for connTyp, connection := range rc.connections {
if connection == nil {
log.Warn("connection" + connTyp + " is nil")
}
err := backoff.Retry(func() error { return connection.Ping(ctx) }, getExponentialBackoff())
if err != nil {
log.WithError(err).Errorf("Could not connect to Redis cluster after many attempts. Host(s): %v", getRedisAddrs(conf.Storage))
}
}
rc.storageUp.Store(true)
go rc.recoverLoop(ctx, onConnect)
// We need the ticker to constantly checking the connection status of Redis. If Redis gets down and up again, we should be able to recover.
go rc.statusCheck(ctx)
}
Cognitive complexity: 10, Cyclomatic complexity: 5
func (*ConnectionHandler) Connected
Connected returns true if we are connected to redis
func (rc *ConnectionHandler) Connected() bool {
v := rc.storageUp.Load()
if v != nil {
return v.(bool)
}
return false
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*ConnectionHandler) DisableStorage
DisableStorage allows to dynamically enable/disable talking with storage
func (rc *ConnectionHandler) DisableStorage(setStorageDown bool) {
if setStorageDown {
// we make sure x set that redis is down
rc.disableStorage.Store(true)
rc.storageUp.Store(false)
return
}
rc.disableStorage.Store(false)
rc.storageUp.Store(false)
ctx, cancel := context.WithTimeout(rc.ctx, 5*time.Second)
defer cancel()
if !rc.WaitConnect(ctx) {
panic("Can't reconnect to redis after disable")
}
rc.reconnect <- struct{}{}
}
Cognitive complexity: 6, Cyclomatic complexity: 3
func (*ConnectionHandler) Disconnect
Disconnect closes the connection to the storage
func (rc *ConnectionHandler) Disconnect() error {
for _, v := range rc.connections {
if v != nil {
if err := v.Disconnect(context.Background()); err != nil {
return err
}
}
}
return nil
}
Cognitive complexity: 7, Cyclomatic complexity: 4
func (*ConnectionHandler) WaitConnect
WaitConnect waits until we are connected to the storage
func (rc *ConnectionHandler) WaitConnect(ctx context.Context) bool {
for {
select {
case <-ctx.Done():
return false
default:
if rc.Connected() {
return true
}
time.Sleep(10 * time.Millisecond)
}
}
}
Cognitive complexity: 6, Cyclomatic complexity: 4
func (*DummyStorage) AddToSet
AddToSet adds a value to a set associated with a key in DummyStorage; implementation pending.
func (s *DummyStorage) AddToSet(string, string) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) AddToSortedSet
AddToSortedSet inserts a value with a score into a sorted set in DummyStorage; implementation pending.
func (s *DummyStorage) AddToSortedSet(string, string, float64) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) AppendToSet
AppendToSet adds a new value to the end of a list associated with a key in DummyStorage.
func (s *DummyStorage) AppendToSet(keyName string, value string) {
s.IndexList[keyName] = append(s.IndexList[keyName], value)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) Connect
Connect establishes a connection to the storage backend; not currently implemented.
func (s *DummyStorage) Connect() bool {
return true
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) Decrement
Decrement reduces the value of a specified key in DummyStorage; implementation pending.
func (s *DummyStorage) Decrement(string) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) DeleteAllKeys
DeleteAllKeys removes all keys and their associated data from the DummyStorage. This method is intended to provide a way to clear the entire storage, which can be particularly useful in testing scenarios to ensure a clean state before tests.
func (s *DummyStorage) DeleteAllKeys() bool {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) DeleteKey
DeleteKey removes a specified key from DummyStorage, returning true if successful.
func (s *DummyStorage) DeleteKey(key string) bool {
if _, ok := s.Data[key]; !ok {
return false
}
delete(s.Data, key)
return true
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*DummyStorage) DeleteKeys
DeleteKeys removes a list of keys from DummyStorage, returning a success status; not yet implemented.
func (s *DummyStorage) DeleteKeys([]string) bool {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) DeleteRawKey
DeleteRawKey removes a specified key from DummyStorage, returning success status; not yet implemented.
func (s *DummyStorage) DeleteRawKey(string) bool {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) DeleteRawKeys
DeleteRawKeys removes a set of raw keys from DummyStorage, returning success status; not yet implemented.
func (s *DummyStorage) DeleteRawKeys([]string) bool { panic("implement me") }
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) DeleteScanMatch
DeleteScanMatch deletes keys matching a pattern from DummyStorage, returning true if successful.
func (s *DummyStorage) DeleteScanMatch(pattern string) bool {
if pattern == "*" {
s.Data = make(map[string]string)
return true
}
return false
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*DummyStorage) Exists
Exists checks if a key exists in either the IndexList or Data in DummyStorage; returns true if found.
func (s *DummyStorage) Exists(keyName string) (bool, error) {
_, existIndex := s.IndexList[keyName]
_, existRaw := s.Data[keyName]
return existIndex || existRaw, nil
}
Cognitive complexity: 0, Cyclomatic complexity: 2
func (*DummyStorage) GetAndDeleteSet
GetAndDeleteSet retrieves and then deletes a set associated with a key in DummyStorage; not implemented.
func (s *DummyStorage) GetAndDeleteSet(string) []interface{} {
panic("implement me")
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func (*DummyStorage) GetExp
GetExp retrieves the expiration time of a specific key from the DummyStorage. This method accepts a string parameter representing the key and returns an int64 which is the expiration time associated with that key, along with an error.
func (s *DummyStorage) GetExp(string) (int64, error) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) GetKey
GetKey retrieves the value for a given key from DummyStorage, or an error if not found.
func (s *DummyStorage) GetKey(key string) (string, error) {
if value, ok := s.Data[key]; ok {
return value, nil
}
return "", errors.New("Not found")
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*DummyStorage) GetKeyPrefix
GetKeyPrefix returns the prefix used for keys in DummyStorage; not yet implemented.
func (s *DummyStorage) GetKeyPrefix() string {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) GetKeys
GetKeys retrieves all keys matching a specified pattern from DummyStorage; currently supports only '*'.
func (s *DummyStorage) GetKeys(pattern string) (keys []string) {
if pattern != "*" {
return nil
}
for k := range s.Data {
keys = append(keys, k)
}
return keys
}
Cognitive complexity: 5, Cyclomatic complexity: 3
func (*DummyStorage) GetKeysAndValues
GetKeysAndValues retrieves all key-value pairs from DummyStorage; currently not implemented.
func (s *DummyStorage) GetKeysAndValues() map[string]string {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) GetKeysAndValuesWithFilter
GetKeysAndValuesWithFilter fetches key-value pairs matching a filter from DummyStorage; not implemented.
func (s *DummyStorage) GetKeysAndValuesWithFilter(string) map[string]string {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) GetListRange
GetListRange retrieves a range of list elements from DummyStorage for a specified key; returns an error if not found.
func (s *DummyStorage) GetListRange(keyName string, _, _ int64) ([]string, error) {
for key := range s.IndexList {
if key == keyName {
return s.IndexList[key], nil
}
}
return []string{}, nil
}
Cognitive complexity: 6, Cyclomatic complexity: 3
func (*DummyStorage) GetMultiKey
GetMultiKey retrieves multiple values from the DummyStorage based on a slice of keys. It returns a slice of strings containing the values corresponding to each provided key, and an error if the operation cannot be completed.
func (s *DummyStorage) GetMultiKey(keys []string) ([]string, error) {
var values []string
for _, key := range keys {
value, ok := s.Data[key]
if !ok {
return nil, fmt.Errorf("key not found: %s", key)
}
values = append(values, value)
}
return values, nil
}
Cognitive complexity: 5, Cyclomatic complexity: 3
func (*DummyStorage) GetRawKey
GetRawKey retrieves the value associated with a given key from the DummyStorage. The method accepts a single string as the key and returns the corresponding string value. An error is also returned to indicate whether the retrieval was successful. Currently, this method is not implemented and will cause a panic if invoked.
func (s *DummyStorage) GetRawKey(key string) (string, error) {
value, ok := s.Data[key]
if !ok {
return "", fmt.Errorf("key not found: %s", key)
}
return value, nil
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*DummyStorage) GetRollingWindow
GetRollingWindow retrieves data for a specified rolling window; currently not implemented.
func (s *DummyStorage) GetRollingWindow(string, int64, bool) (int, []interface{}) {
panic("implement me")
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func (*DummyStorage) GetSet
GetSet retrieves a set of values associated with a key in DummyStorage; not yet implemented.
func (s *DummyStorage) GetSet(string) (map[string]string, error) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) GetSortedSetRange
GetSortedSetRange retrieves a range of values and scores from a sorted set in DummyStorage; not implemented.
func (s *DummyStorage) GetSortedSetRange(string, string, string) ([]string, []float64, error) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) IncrememntWithExpire
IncrememntWithExpire increments the value of a key and sets an expiry; not yet implemented.
func (s *DummyStorage) IncrememntWithExpire(string, int64) int64 {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) RemoveFromList
RemoveFromList eliminates a specific value from a list within DummyStorage; always returns nil.
func (s *DummyStorage) RemoveFromList(keyName, value string) error {
for key, keyList := range s.IndexList {
if key == keyName {
new := keyList[:]
newL := 0
for _, e := range new {
if e == value {
continue
}
new[newL] = e
newL++
}
new = new[:newL]
s.IndexList[key] = new
}
}
return nil
}
Cognitive complexity: 10, Cyclomatic complexity: 5
func (*DummyStorage) RemoveFromSet
RemoveFromSet deletes a specific value from a set in DummyStorage; currently not implemented.
func (s *DummyStorage) RemoveFromSet(string, string) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) RemoveSortedSetRange
RemoveSortedSetRange deletes a range of values from a sorted set in DummyStorage; yet to be implemented.
func (s *DummyStorage) RemoveSortedSetRange(string, string, string) error {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) SetExp
SetExp updates the expiration time of a specific key in the DummyStorage. This method accepts two parameters: a string representing the key, and an int64 indicating the new expiration time.
func (s *DummyStorage) SetExp(string, int64) error {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) SetKey
SetKey assigns a value to a key in DummyStorage with an expiration time; returns nil for success.
func (s *DummyStorage) SetKey(key, value string, _ int64) error {
s.Data[key] = value
return nil
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) SetRawKey
SetRawKey stores a value with a specified key in the DummyStorage. It takes three parameters: the key and value as strings, and an expiry time as int64. The expiry time could be used to simulate time-sensitive data storage or caching behavior. Currently, this method is not implemented and will trigger a panic if it is called. TODO: Proper implementation is needed for this method to handle data storage, or manage
func (s *DummyStorage) SetRawKey(string, string, int64) error {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*DummyStorage) SetRollingWindow
SetRollingWindow sets a rolling window for a key with specified parameters; implementation pending.
func (s *DummyStorage) SetRollingWindow(string, int64, string, bool) (int, []interface{}) {
panic("implement me")
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func (*RedisCluster) AddToSet
func (r *RedisCluster) AddToSet(keyName, value string) {
log.Debug("Pushing to raw key set: ", keyName)
log.Debug("Pushing to fixed key set: ", r.fixKey(keyName))
storage, err := r.set()
if err != nil {
log.Error(err)
return
}
err = storage.AddMember(context.Background(), r.fixKey(keyName), value)
if err != nil {
log.Error("Error trying to append to set: ", err)
}
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) AddToSortedSet
AddToSortedSet adds value with given score to sorted set identified by keyName
func (r *RedisCluster) AddToSortedSet(keyName, value string, score float64) {
fixedKey := r.fixKey(keyName)
logEntry := logrus.Fields{
"keyName": keyName,
"fixedKey": fixedKey,
}
log.WithFields(logEntry).Debug("Pushing raw key to sorted set")
storage, err := r.sortedSet()
if err != nil {
log.Error(err)
return
}
_, err = storage.AddScoredMember(context.Background(), fixedKey, value, score)
if err != nil {
log.WithFields(logEntry).WithError(err).Error("ZADD command failed")
}
}
Cognitive complexity: 5, Cyclomatic complexity: 3
func (*RedisCluster) AppendToSet
func (r *RedisCluster) AppendToSet(keyName, value string) {
fixedKey := r.fixKey(keyName)
log.WithField("keyName", keyName).Debug("Pushing to raw key list")
log.WithField("fixedKey", fixedKey).Debug("Appending to fixed key list")
storage, err := r.list()
if err != nil {
log.Error(err)
return
}
err = storage.Append(context.Background(), false, fixedKey, []byte(value))
if err != nil {
log.WithError(err).Error("Error trying to append to set keys")
}
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) AppendToSetPipelined
func (r *RedisCluster) AppendToSetPipelined(key string, values [][]byte) {
if len(values) == 0 {
return
}
fixedKey := r.fixKey(key)
storage, err := r.list()
if err != nil {
log.Error(err)
return
}
err = storage.Append(context.Background(), true, fixedKey, values...)
if err != nil {
log.WithError(err).Error("Error trying to append to set keys")
}
}
Cognitive complexity: 6, Cyclomatic complexity: 4
func (*RedisCluster) Client
Client will return a redis v8 RedisClient. This function allows implementation using the old storage clients.
func (r *RedisCluster) Client() (redis.UniversalClient, error) {
if err := r.up(); err != nil {
return nil, err
}
conn := r.getConnectionHandler().getConnection(r.IsCache, r.IsAnalytics)
if conn == nil {
return nil, ErrStorageConn
}
var client redis.UniversalClient
if ok := conn.As(&client); !ok {
return nil, errors.New("error converting connection to redis client")
}
return client, nil
}
Cognitive complexity: 6, Cyclomatic complexity: 4
func (*RedisCluster) Connect
Connect will establish a connection this is always true because we are dynamically using redis
func (r *RedisCluster) Connect() bool {
return r.getConnectionHandler().Connected()
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*RedisCluster) ControllerInitiated
func (r *RedisCluster) ControllerInitiated() bool {
return r.getConnectionHandler() != nil
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*RedisCluster) Decrement
Decrement will decrement a key in redis
func (r *RedisCluster) Decrement(keyName string) {
keyName = r.fixKey(keyName)
// log.Debug("Decrementing key: ", keyName)
storage, err := r.kv()
if err != nil {
log.Error(err)
return
}
_, err = storage.Decrement(context.Background(), keyName)
if err != nil {
log.Error("Error trying to decrement value:", err)
}
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) DeleteAllKeys
DeleteAllKeys will remove all keys from the database.
func (r *RedisCluster) DeleteAllKeys() bool {
storage, err := r.flusher()
if err != nil {
log.Error(err)
return false
}
err = storage.FlushAll(context.Background())
if err != nil {
log.WithError(err).Error("Error trying to delete keys")
return false
}
return true
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) DeleteKey
DeleteKey will remove a key from the database
func (r *RedisCluster) DeleteKey(keyName string) bool {
storage, err := r.kv()
if err != nil {
log.Error(err)
return false
}
exist, err := storage.Exists(context.Background(), r.fixKey(keyName))
if err != nil || !exist {
return false
}
err = storage.Delete(context.Background(), r.fixKey(keyName))
if err != nil {
log.WithError(err).Error("Error trying to delete key")
return false
}
return true
}
Cognitive complexity: 6, Cyclomatic complexity: 5
func (*RedisCluster) DeleteKeys
DeleteKeys will remove a group of keys in bulk
func (r *RedisCluster) DeleteKeys(keys []string) bool {
storage, err := r.kv()
if err != nil {
log.Error(err)
return false
}
for i, v := range keys {
keys[i] = r.fixKey(v)
}
deleted, err := storage.DeleteKeys(context.Background(), keys)
if err != nil {
log.WithError(err).Error("Error trying to delete keys ")
return false
}
return deleted > 0
}
Cognitive complexity: 7, Cyclomatic complexity: 4
func (*RedisCluster) DeleteRawKey
DeleteKey will remove a key from the database without prefixing, assumes user knows what they are doing
func (r *RedisCluster) DeleteRawKey(keyName string) bool {
storage, err := r.kv()
if err != nil {
log.Error(err)
return false
}
err = storage.Delete(context.Background(), keyName)
if err != nil {
log.WithError(err).Error("Error trying to delete raw key")
return false
}
return true
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) DeleteRawKeys
func (r *RedisCluster) DeleteRawKeys(keys []string) bool {
storage, err := r.kv()
if err != nil {
log.Error(err)
return false
}
deleted, err := storage.DeleteKeys(context.Background(), keys)
if err != nil {
log.WithError(err).Error("Error trying to delete keys ")
return false
}
return deleted > 0
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) DeleteScanMatch
DeleteKeys will remove a group of keys in bulk
func (r *RedisCluster) DeleteScanMatch(pattern string) bool {
storage, err := r.kv()
if err != nil {
log.Error(err)
return false
}
log.Debug("Deleting: ", pattern)
_, err = storage.DeleteScanMatch(context.Background(), pattern)
if err != nil {
log.WithError(err).Error("Error trying to delete key pattern ", pattern)
return false
}
return true
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) Exists
Exists check if keyName exists
func (r *RedisCluster) Exists(keyName string) (bool, error) {
fixedKey := r.fixKey(keyName)
log.WithField("keyName", fixedKey).Debug("Checking if exists")
storage, err := r.kv()
if err != nil {
log.Error(err)
return false, err
}
exists, err := storage.Exists(context.Background(), fixedKey)
if err != nil {
log.Error("Error trying to check if key exists: ", err)
return false, err
}
return exists, nil
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) GetAndDeleteSet
func (r *RedisCluster) GetAndDeleteSet(keyName string) []interface{} {
storage, err := r.list()
if err != nil {
log.Error(err)
return nil
}
log.Debug("Getting raw key set: ", keyName)
log.Debug("keyName is: ", keyName)
fixedKey := r.fixKey(keyName)
log.Debug("Fixed keyname is: ", fixedKey)
values, err := storage.Pop(context.Background(), fixedKey, -1)
if err != nil {
log.Error("Multi command failed: ", err)
return nil
}
if len(values) == 0 {
return []interface{}{}
}
result := make([]interface{}, len(values))
for i, v := range values {
result[i] = v
}
return result
}
Cognitive complexity: 13, Cyclomatic complexity: 5
func (*RedisCluster) GetExp
func (r *RedisCluster) GetExp(keyName string) (int64, error) {
return r.GetKeyTTL(keyName)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*RedisCluster) GetKey
GetKey will retrieve a key from the database
func (r *RedisCluster) GetKey(keyName string) (string, error) {
storage, err := r.kv()
if err != nil {
log.Error(err)
return "", err
}
value, err := storage.Get(context.Background(), r.fixKey(keyName))
if err != nil {
if !errors.Is(err, redis.Nil) {
log.Debug("Error trying to get value:", err)
}
return "", ErrKeyNotFound
}
return value, nil
}
Cognitive complexity: 6, Cyclomatic complexity: 4
func (*RedisCluster) GetKeyPrefix
GetPrefix returns storage key prefix
func (r *RedisCluster) GetKeyPrefix() string {
return r.KeyPrefix
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*RedisCluster) GetKeyTTL
func (r *RedisCluster) GetKeyTTL(keyName string) (ttl int64, err error) {
storage, err := r.kv()
if err != nil {
log.Error(err)
return 0, err
}
return storage.TTL(context.Background(), r.fixKey(keyName))
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*RedisCluster) GetKeys
GetKeys will return all keys according to the filter (filter is a prefix - e.g. tyk.keys.*)
func (r *RedisCluster) GetKeys(filter string) []string {
filterHash := ""
if filter != "" {
filterHash = r.hashKey(filter)
}
searchStr := r.KeyPrefix + filterHash + "*"
log.Debug("[STORE] Getting list by: ", searchStr)
sessions, err := r.ScanKeys(searchStr)
if err != nil {
log.Error("Error while fetching keys:", err)
return nil
}
for i, v := range sessions {
sessions[i] = r.cleanKey(v)
}
return sessions
}
Cognitive complexity: 7, Cyclomatic complexity: 4
func (*RedisCluster) GetKeysAndValues
GetKeysAndValues will return all keys and their values - not to be used lightly
func (r *RedisCluster) GetKeysAndValues() map[string]string {
return r.GetKeysAndValuesWithFilter("")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*RedisCluster) GetKeysAndValuesWithFilter
GetKeysAndValuesWithFilter will return all keys and their values with a filter
func (r *RedisCluster) GetKeysAndValuesWithFilter(filter string) map[string]string {
storage, err := r.kv()
if err != nil {
log.Error(err)
return nil
}
if filter != "" && !strings.Contains(filter, r.KeyPrefix) {
filter = r.KeyPrefix + filter
}
keysAndValues, err := storage.GetKeysAndValuesWithFilter(context.Background(), filter)
if err != nil {
log.Error("Error trying to get client keys: ", err)
return nil
}
m := make(map[string]string)
for key, value := range keysAndValues {
m[r.cleanKey(key)] = fmt.Sprint(value)
}
return m
}
Cognitive complexity: 9, Cyclomatic complexity: 6
func (*RedisCluster) GetListRange
GetListRange gets range of elements of list identified by keyName
func (r *RedisCluster) GetListRange(keyName string, from, to int64) ([]string, error) {
fixedKey := r.fixKey(keyName)
logEntry := logrus.Fields{
"keyName": keyName,
"fixedKey": fixedKey,
"from": from,
"to": to,
}
log.WithFields(logEntry).Debug("Getting list range")
storage, err := r.list()
if err != nil {
log.Error(err)
return []string{}, err
}
elements, err := storage.Range(context.Background(), fixedKey, from, to)
if err != nil {
log.WithFields(logEntry).WithError(err).Error("LRANGE command failed")
return nil, err
}
return elements, nil
}
Cognitive complexity: 6, Cyclomatic complexity: 3
func (*RedisCluster) GetMultiKey
GetMultiKey gets multiple keys from the database
func (r *RedisCluster) GetMultiKey(keys []string) ([]string, error) {
storage, err := r.kv()
if err != nil {
log.Error(err)
return nil, err
}
keyNames := make([]string, len(keys))
copy(keyNames, keys)
for index, val := range keyNames {
keyNames[index] = r.fixKey(val)
}
values, err := storage.GetMulti(context.Background(), keyNames)
if err != nil {
log.WithError(err).Debug("Error trying to get value")
return nil, ErrKeyNotFound
}
result := make([]string, 0)
for _, val := range values {
strVal := fmt.Sprint(val)
if strVal == "<nil>" {
strVal = ""
}
result = append(result, strVal)
}
for _, val := range result {
if val != "" {
return result, nil
}
}
return nil, ErrKeyNotFound
}
Cognitive complexity: 17, Cyclomatic complexity: 8
func (*RedisCluster) GetRawKey
func (r *RedisCluster) GetRawKey(keyName string) (string, error) {
storage, err := r.kv()
if err != nil {
log.Error(err)
return "", err
}
value, err := storage.Get(context.Background(), keyName)
if err != nil {
if !errors.Is(err, redis.Nil) {
log.Debug("Error trying to get value:", err)
}
return "", ErrKeyNotFound
}
return value, nil
}
Cognitive complexity: 6, Cyclomatic complexity: 4
func (*RedisCluster) GetRollingWindow
func (r *RedisCluster) GetRollingWindow(keyName string, per int64, pipeline bool) (int, []interface{}) {
now := time.Now()
onePeriodAgo := now.Add(time.Duration(-1*per) * time.Second)
singleton, err := r.Client()
if err != nil {
log.Error(err)
return 0, nil
}
ctx := context.Background()
var zrange *redis.StringSliceCmd
pipeFn := func(pipe redis.Pipeliner) error {
pipe.ZRemRangeByScore(ctx, keyName, "-inf", strconv.Itoa(int(onePeriodAgo.UnixNano())))
zrange = pipe.ZRange(ctx, keyName, 0, -1)
return nil
}
if pipeline {
_, err = singleton.Pipelined(ctx, pipeFn)
} else {
_, err = singleton.TxPipelined(ctx, pipeFn)
}
if err != nil {
log.Error("Multi command failed: ", err)
return 0, nil
}
values := zrange.Val()
// Check actual value
if values == nil {
return 0, nil
}
intVal := len(values)
result := make([]interface{}, intVal)
for i, v := range values {
result[i] = v
}
log.Debug("Returned: ", intVal)
return intVal, result
}
Cognitive complexity: 16, Cyclomatic complexity: 6
func (*RedisCluster) GetSet
func (r *RedisCluster) GetSet(keyName string) (map[string]string, error) {
log.Debug("Getting from key set: ", keyName)
log.Debug("Getting from fixed key set: ", r.fixKey(keyName))
storage, err := r.set()
if err != nil {
log.Error(err)
return nil, err
}
members, err := storage.Members(context.Background(), r.fixKey(keyName))
if err != nil {
log.Error("Error trying to get key set:", err)
return nil, err
}
result := make(map[string]string)
for i, value := range members {
result[strconv.Itoa(i)] = value
}
return result, nil
}
Cognitive complexity: 7, Cyclomatic complexity: 4
func (*RedisCluster) GetSortedSetRange
GetSortedSetRange gets range of elements of sorted set identified by keyName
func (r *RedisCluster) GetSortedSetRange(keyName, scoreFrom, scoreTo string) ([]string, []float64, error) {
fixedKey := r.fixKey(keyName)
logEntry := logrus.Fields{
"keyName": keyName,
"fixedKey": fixedKey,
"scoreFrom": scoreFrom,
"scoreTo": scoreTo,
}
log.WithFields(logEntry).Debug("Getting sorted set range")
storage, err := r.sortedSet()
if err != nil {
log.Error(err)
return nil, nil, err
}
values, scores, err := storage.GetMembersByScoreRange(context.Background(), fixedKey, scoreFrom, scoreTo)
if err != nil {
log.WithFields(logEntry).WithError(err).Error("ZRANGEBYSCORE command failed")
return nil, nil, err
}
if len(values) == 0 {
return nil, nil, nil
}
elements := make([]string, len(values))
for i, v := range values {
elements[i] = fmt.Sprint(v)
}
return elements, scores, nil
}
Cognitive complexity: 10, Cyclomatic complexity: 5
func (*RedisCluster) IncrememntWithExpire
IncrementWithExpire will increment a key in redis
func (r *RedisCluster) IncrememntWithExpire(keyName string, expire int64) int64 {
storage, err := r.kv()
if err != nil {
log.Error(err)
return 0
}
// This function uses a raw key, so we shouldn't call fixKey
fixedKey := keyName
val, err := storage.Increment(context.Background(), fixedKey)
if err != nil {
log.Error("Error trying to increment value:", err)
} else {
log.Debug("Incremented key: ", fixedKey, ", val is: ", val)
}
if val == 1 && expire > 0 {
log.Debug("--> Setting Expire")
err = storage.Expire(context.Background(), fixedKey, time.Duration(expire)*time.Second)
if err != nil {
log.Error("Error trying to set expire on key:", err)
}
}
return val
}
Cognitive complexity: 10, Cyclomatic complexity: 6
func (*RedisCluster) IsMemberOfSet
func (r *RedisCluster) IsMemberOfSet(keyName, value string) bool {
storage, err := r.set()
if err != nil {
log.Error(err)
return false
}
val, err := storage.IsMember(context.Background(), r.fixKey(keyName), value)
if err != nil {
log.Error("Error trying to check set member: ", err)
return false
}
log.Debug("SISMEMBER", keyName, value, val, err)
return val
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) Lock
Lock implements a distributed lock in a cluster.
func (r *RedisCluster) Lock(key string, timeout time.Duration) (bool, error) {
storage, err := r.kv()
if err != nil {
log.Error(err)
return false, err
}
set, err := storage.SetIfNotExist(context.Background(), key, "1", timeout)
if err != nil {
log.WithError(err).Error("Error trying to set value")
return false, err
}
return set, nil
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) Publish
func (r *RedisCluster) Publish(channel, message string) error {
storage, err := r.queue()
if err != nil {
log.Error(err)
return err
}
_, err = storage.Publish(context.Background(), channel, message)
if err != nil {
log.Error("Error trying to publish message: ", err)
return err
}
return nil
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) RemoveFromList
RemoveFromList delete an value from a list idetinfied with the keyName
func (r *RedisCluster) RemoveFromList(keyName, value string) error {
fixedKey := r.fixKey(keyName)
logEntry := logrus.Fields{
"keyName": keyName,
"fixedKey": fixedKey,
"value": value,
}
log.WithFields(logEntry).Debug("Removing value from list")
storage, err := r.list()
if err != nil {
log.Error(err)
return err
}
_, err = storage.Remove(context.Background(), fixedKey, 0, value)
if err != nil {
log.WithFields(logEntry).WithError(err).Error("LREM command failed")
return err
}
return nil
}
Cognitive complexity: 5, Cyclomatic complexity: 3
func (*RedisCluster) RemoveFromSet
func (r *RedisCluster) RemoveFromSet(keyName, value string) {
log.Debug("Removing from raw key set: ", keyName)
log.Debug("Removing from fixed key set: ", r.fixKey(keyName))
storage, err := r.set()
if err != nil {
log.Error(err)
return
}
err = storage.RemoveMember(context.Background(), r.fixKey(keyName), value)
if err != nil {
log.Error("Error trying to remove keys: ", err)
}
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (*RedisCluster) RemoveSortedSetRange
RemoveSortedSetRange removes range of elements from sorted set identified by keyName
func (r *RedisCluster) RemoveSortedSetRange(keyName, scoreFrom, scoreTo string) error {
fixedKey := r.fixKey(keyName)
logEntry := logrus.Fields{
"keyName": keyName,
"fixedKey": fixedKey,
"scoreFrom": scoreFrom,
"scoreTo": scoreTo,
}
log.WithFields(logEntry).Debug("Removing sorted set range")
storage, err := r.sortedSet()
if err != nil {
log.Error(err)
return err
}
_, err = storage.RemoveMembersByScoreRange(context.Background(), fixedKey, scoreFrom, scoreTo)
if err != nil {
log.WithFields(logEntry).WithError(err).Error("ZREMRANGEBYSCORE command failed")
return err
}
return nil
}
Cognitive complexity: 5, Cyclomatic complexity: 3
func (*RedisCluster) ScanKeys
ScanKeys will return all keys according to the pattern.
func (r *RedisCluster) ScanKeys(pattern string) ([]string, error) {
storage, err := r.kv()
if err != nil {
log.Error(err)
return nil, err
}
return storage.Keys(context.Background(), pattern)
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*RedisCluster) SetExp
func (r *RedisCluster) SetExp(keyName string, timeout int64) error {
storage, err := r.kv()
if err != nil {
log.Error(err)
return err
}
return storage.Expire(context.Background(), r.fixKey(keyName), time.Duration(timeout)*time.Second)
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*RedisCluster) SetKey
SetKey will create (or update) a key value in the store
func (r *RedisCluster) SetKey(keyName, session string, timeout int64) error {
return r.SetRawKey(r.fixKey(keyName), session, timeout)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*RedisCluster) SetRawKey
func (r *RedisCluster) SetRawKey(keyName, session string, timeout int64) error {
storage, err := r.kv()
if err != nil {
log.Error(err)
return err
}
return storage.Set(context.Background(), keyName, session, time.Duration(timeout)*time.Second)
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*RedisCluster) SetRollingWindow
SetRollingWindow will append to a sorted set in redis and extract a timed window of values
func (r *RedisCluster) SetRollingWindow(keyName string, per int64, value_override string, pipeline bool) (int, []interface{}) {
log.Debug("Incrementing raw key: ", keyName)
log.Debug("keyName is: ", keyName)
now := time.Now()
log.Debug("Now is:", now)
onePeriodAgo := now.Add(time.Duration(-1*per) * time.Second)
log.Debug("Then is: ", onePeriodAgo)
singleton, err := r.Client()
if err != nil {
log.Error(err)
return 0, nil
}
ctx := context.Background()
var zrange *redis.StringSliceCmd
pipeFn := func(pipe redis.Pipeliner) error {
pipe.ZRemRangeByScore(ctx, keyName, "-inf", strconv.Itoa(int(onePeriodAgo.UnixNano())))
zrange = pipe.ZRange(ctx, keyName, 0, -1)
element := redis.Z{
Score: float64(now.UnixNano()),
}
if value_override != "-1" {
element.Member = value_override
} else {
element.Member = strconv.Itoa(int(now.UnixNano()))
}
pipe.ZAdd(ctx, keyName, element)
pipe.Expire(ctx, keyName, time.Duration(per)*time.Second)
return nil
}
if pipeline {
_, err = singleton.Pipelined(context.Background(), pipeFn)
} else {
_, err = singleton.TxPipelined(context.Background(), pipeFn)
}
if err != nil {
log.Error("Multi command failed: ", err)
return 0, nil
}
values := zrange.Val()
// Check actual value
if values == nil {
return 0, nil
}
intVal := len(values)
result := make([]interface{}, len(values))
for i, v := range values {
result[i] = v
}
log.Debug("Returned: ", intVal)
return intVal, result
}
Cognitive complexity: 21, Cyclomatic complexity: 7
func (*RedisCluster) StartPubSubHandler
StartPubSubHandler will listen for a signal and run the callback for every subscription and message event.
func (r *RedisCluster) StartPubSubHandler(ctx context.Context, channel string, callback func(interface{})) error {
storage, err := r.queue()
if err != nil {
log.Error(err)
return err
}
pubsub := storage.Subscribe(ctx, channel)
defer pubsub.Close()
for {
select {
case <-ctx.Done():
return nil
default:
if err := r.handleReceive(ctx, pubsub.Receive, callback); err != nil {
return err
}
}
}
}
Cognitive complexity: 9, Cyclomatic complexity: 5
func (*RedisController) ConnectToRedis
ConnectToRedis sets up the connection to Redis using specified configuration. It abstracts the connection logic, allowing Go plugins to seamlessly integrate without direct interaction with the underlying storage logic.
func (rc *RedisController) ConnectToRedis(ctx context.Context, onReconnect func(), conf *config.Config) {
rc.connection.Connect(ctx, onReconnect, conf)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*RedisController) Connected
Connected checks the current state of the Redis connection, offering a simple interface for Go plugins to verify connectivity without delving into the specifics of the storage layer.
func (rc *RedisController) Connected() bool {
return rc.connection.Connected()
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*RedisController) DisableRedis
DisableRedis toggles the Redis connection's active status, providing a mechanism to dynamically manage the connection state in response to runtime conditions or configurations.
func (rc *RedisController) DisableRedis(setRedisDown bool) {
rc.connection.DisableStorage(setRedisDown)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*RedisController) WaitConnect
WaitConnect blocks until a Redis connection is established, enabling Go plugins to wait for connectivity before proceeding with operations that require Redis access.
func (rc *RedisController) WaitConnect(ctx context.Context) bool {
return rc.connection.WaitConnect(ctx)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) AddToSet
func (m MdcbStorage) AddToSet(key string, value string) {
m.local.AddToSet(key, value)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) AddToSortedSet
func (m MdcbStorage) AddToSortedSet(string, string, float64) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) AppendToSet
func (m MdcbStorage) AppendToSet(key string, value string) {
m.local.AppendToSet(key, value)
m.rpc.AppendToSet(key, value)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) Connect
func (m MdcbStorage) Connect() bool {
return m.local.Connect() && m.rpc.Connect()
}
Cognitive complexity: 0, Cyclomatic complexity: 2
func (MdcbStorage) Decrement
func (m MdcbStorage) Decrement(string) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) DeleteAllKeys
func (m MdcbStorage) DeleteAllKeys() bool {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) DeleteKey
func (m MdcbStorage) DeleteKey(key string) bool {
deleteLocal := m.local.DeleteKey(key)
deleteRPC := m.rpc.DeleteKey(key)
return deleteLocal || deleteRPC
}
Cognitive complexity: 0, Cyclomatic complexity: 2
func (MdcbStorage) DeleteKeys
func (m MdcbStorage) DeleteKeys([]string) bool {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) DeleteRawKey
func (m MdcbStorage) DeleteRawKey(string) bool {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) DeleteRawKeys
func (m MdcbStorage) DeleteRawKeys([]string) bool { panic("implement me") }
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) DeleteScanMatch
func (m MdcbStorage) DeleteScanMatch(key string) bool {
deleteLocal := m.local.DeleteScanMatch(key)
deleteRPC := m.rpc.DeleteScanMatch(key)
return deleteLocal || deleteRPC
}
Cognitive complexity: 0, Cyclomatic complexity: 2
func (MdcbStorage) Exists
func (m MdcbStorage) Exists(key string) (bool, error) {
foundLocal, errLocal := m.local.Exists(key)
foundRpc, errRpc := m.rpc.Exists(key)
if errLocal != nil && errRpc != nil {
return false, errors.New("cannot find key in storages")
}
return foundLocal && foundRpc, nil
}
Cognitive complexity: 2, Cyclomatic complexity: 4
func (MdcbStorage) GetAndDeleteSet
func (m MdcbStorage) GetAndDeleteSet(string) []interface{} {
panic("implement me")
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func (MdcbStorage) GetExp
func (m MdcbStorage) GetExp(string) (int64, error) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) GetKey
func (m MdcbStorage) GetKey(key string) (string, error) {
if m.local != nil {
val, err := m.getFromLocal(key)
if err == nil {
return val, nil
}
m.logger.Debugf("Key not present locally, pulling from rpc layer: %v", err)
}
return m.getFromRPCAndCache(key)
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (MdcbStorage) GetKeyPrefix
func (m MdcbStorage) GetKeyPrefix() string {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) GetKeys
func (m MdcbStorage) GetKeys(key string) []string {
var val []string
if m.local != nil {
val = m.local.GetKeys(key)
if len(val) == 0 {
val = m.rpc.GetKeys(key)
}
} else {
val = m.rpc.GetKeys(key)
}
return val
}
Cognitive complexity: 6, Cyclomatic complexity: 3
func (MdcbStorage) GetKeysAndValues
func (m MdcbStorage) GetKeysAndValues() map[string]string {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) GetKeysAndValuesWithFilter
func (m MdcbStorage) GetKeysAndValuesWithFilter(key string) map[string]string {
return m.local.GetKeysAndValuesWithFilter(key)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) GetListRange
func (m MdcbStorage) GetListRange(key string, from int64, to int64) ([]string, error) {
var val []string
var err error
if m.local == nil {
return m.rpc.GetListRange(key, from, to)
}
val, err = m.local.GetListRange(key, from, to)
if err != nil {
val, err = m.rpc.GetListRange(key, from, to)
}
return val, err
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func (MdcbStorage) GetMultiKey
GetMultiKey gets multiple keys from the MDCB layer
func (m MdcbStorage) GetMultiKey(keyNames []string) ([]string, error) {
var err error
var value string
for _, key := range keyNames {
value, err = m.GetKey(key)
if err == nil {
return []string{value}, nil
}
}
return nil, err
}
Cognitive complexity: 6, Cyclomatic complexity: 3
func (MdcbStorage) GetRawKey
func (m MdcbStorage) GetRawKey(string) (string, error) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) GetRollingWindow
func (m MdcbStorage) GetRollingWindow(key string, per int64, pipeline bool) (int, []interface{}) {
panic("implement me")
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func (MdcbStorage) GetSet
func (m MdcbStorage) GetSet(key string) (map[string]string, error) {
val, err := m.local.GetSet(key)
if err != nil {
// try rpc
val, err = m.rpc.GetSet(key)
}
return val, err
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (MdcbStorage) GetSortedSetRange
func (m MdcbStorage) GetSortedSetRange(string, string, string) ([]string, []float64, error) {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) IncrememntWithExpire
func (m MdcbStorage) IncrememntWithExpire(string, int64) int64 {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) RemoveFromList
func (m MdcbStorage) RemoveFromList(key string, value string) error {
errLocal := m.local.RemoveFromList(key, value)
errRpc := m.rpc.RemoveFromList(key, value)
if errLocal != nil && errRpc != nil {
return errors.New("cannot delete key in storages")
}
return nil
}
Cognitive complexity: 2, Cyclomatic complexity: 3
func (MdcbStorage) RemoveFromSet
func (m MdcbStorage) RemoveFromSet(key string, value string) {
m.local.RemoveFromSet(key, value)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) RemoveSortedSetRange
func (m MdcbStorage) RemoveSortedSetRange(string, string, string) error {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) SetExp
func (m MdcbStorage) SetExp(string, int64) error {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) SetKey
func (m MdcbStorage) SetKey(key string, content string, TTL int64) error {
// only set the value locally as rpc writtes is not allowed
errLocal := m.local.SetKey(key, content, TTL)
if errLocal != nil {
return errors.New("cannot save key in local")
}
return nil
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (MdcbStorage) SetRawKey
func (m MdcbStorage) SetRawKey(string, string, int64) error {
panic("implement me")
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (MdcbStorage) SetRollingWindow
func (m MdcbStorage) SetRollingWindow(key string, per int64, val string, pipeline bool) (int, []interface{}) {
panic("implement me")
}
Cognitive complexity: 1, Cyclomatic complexity: 1
Private functions
func getExponentialBackoff
getExponentialBackoff returns a backoff.ExponentialBackOff with the following settings:
- Multiplier: 2
- MaxInterval: 10 seconds
- MaxElapsedTime: 0 (no limit)
getExponentialBackoff () *backoff.ExponentialBackOff
References: backoff.NewExponentialBackOff, time.Second.
func getRedisAddrs
getRedisAddrs (conf config.StorageOptionsConf) []string
func getResourceType
getResourceType (key string) string
References: strings.Contains, strings.HasPrefix.
func enabled
enabled () bool
func getConnection
getConnection (isCache,isAnalytics bool) model.Connector
func initConnection
initConnection initializes the connection singletons.
initConnection (conf config.Config) error
func isConnected
isConnected (ctx context.Context, connType string) bool
func recoverLoop
recoverLoop (ctx context.Context, onReconnect func())
func statusCheck
statusCheck will check the storage status each second. This method will be constantly modifying the redisUp control flag.
statusCheck (ctx context.Context)
References: time.NewTicker, time.Second.
func cleanKey
cleanKey (keyName string) string
References: strings.Replace.
func fixKey
fixKey (keyName string) string
func flusher
flusher () (model.Flusher, error)
References: tempflusher.NewFlusher.
func getConnectionHandler
getConnectionHandler () *ConnectionHandler
func handleMessage
handleMessage (msg interface{}, err error, callback func(interface{})) error
References: redis.ErrClosed, strings.Contains.
func handleReceive
handleReceive is split from pubsub inner loop to inject fake receive function for code coverage tests.
handleReceive (ctx context.Context, receiveFn func(context.Context) (model.Message, error), callback func(interface{})) error
func hashKey
hashKey (in string) string
func kv
kv () (model.KeyValue, error)
References: tempkv.NewKeyValue.
func list
list () (model.List, error)
References: templist.NewList.
func queue
queue () (model.Queue, error)
References: tempqueue.NewQueue.
func set
set () (model.Set, error)
References: tempset.NewSet.
func sortedSet
sortedSet () (model.SortedSet, error)
References: tempsortedset.NewSortedSet.
func up
up () error
func cacheCertificate
cacheCertificate saves locally resourceCertificate after pull from rpc
cacheCertificate (key,val string) error
func cacheOAuthClient
cacheOAuthClient saved oauth data in local storage after pull from rpc
cacheOAuthClient (key,val string) error
func getFromLocal
getFromLocal get a key from local storage
getFromLocal (key string) (string, error)
func getFromRPCAndCache
getFromRPCAndCache pulls a resource from rpc and stores it in local redis for caching
getFromRPCAndCache (key string) (string, error)
func processResourceByType
processResourceByType based on the type of key it will trigger the proper caching mechanism
processResourceByType (key,val string) error
Tests
Files: 6. Third party imports: 4. Imports from organisation: 2. Tests: 97. Benchmarks: 0.
Vars
var notFoundKeyErr = errors.New("key not found")
var rc *ConnectionHandler
Types
testSetup
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| Logger |
|
No comment on field. |
| Local |
|
No comment on field. |
| Remote |
|
No comment on field. |
| MdcbStorage |
|
No comment on field. |
| CleanUp |
|
No comment on field. |
type testSetup struct {
Logger *logrus.Entry
Local *mock.MockHandler
Remote *mock.MockHandler
MdcbStorage *MdcbStorage
CleanUp func()
}