mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
Migrating roles and schemes to new Cache Layer (#11936)
* Migrating roles and schemes to new Cache Layer * Adding missed license headers * Updating cache tests * Adding the cache layer to the testlib helper * Fixing cyclic dependency * fixing a bit of not-idiomatic error handling * Another small fix arrount idiomatic error handling
This commit is contained in:
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/mattermost/mattermost-server/einterfaces"
|
||||
"github.com/mattermost/mattermost-server/mlog"
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -22,8 +21,6 @@ type LayeredStoreDatabaseLayer interface {
|
||||
|
||||
type LayeredStore struct {
|
||||
TmpContext context.Context
|
||||
RoleStore RoleStore
|
||||
SchemeStore SchemeStore
|
||||
DatabaseLayer LayeredStoreDatabaseLayer
|
||||
LocalCacheLayer *LocalCacheSupplier
|
||||
RedisLayer *RedisSupplier
|
||||
@@ -37,9 +34,6 @@ func NewLayeredStore(db LayeredStoreDatabaseLayer, metrics einterfaces.MetricsIn
|
||||
LocalCacheLayer: NewLocalCacheSupplier(metrics, cluster),
|
||||
}
|
||||
|
||||
store.RoleStore = &LayeredRoleStore{store}
|
||||
store.SchemeStore = &LayeredSchemeStore{store}
|
||||
|
||||
// Setup the chain
|
||||
if ENABLE_EXPERIMENTAL_REDIS {
|
||||
mlog.Debug("Experimental redis enabled.")
|
||||
@@ -161,7 +155,7 @@ func (s *LayeredStore) Plugin() PluginStore {
|
||||
}
|
||||
|
||||
func (s *LayeredStore) Role() RoleStore {
|
||||
return s.RoleStore
|
||||
return s.DatabaseLayer.Role()
|
||||
}
|
||||
|
||||
func (s *LayeredStore) TermsOfService() TermsOfServiceStore {
|
||||
@@ -173,7 +167,7 @@ func (s *LayeredStore) UserTermsOfService() UserTermsOfServiceStore {
|
||||
}
|
||||
|
||||
func (s *LayeredStore) Scheme() SchemeStore {
|
||||
return s.SchemeStore
|
||||
return s.DatabaseLayer.Scheme()
|
||||
}
|
||||
|
||||
func (s *LayeredStore) Group() GroupStore {
|
||||
@@ -220,63 +214,3 @@ func (s *LayeredStore) TotalSearchDbConnections() int {
|
||||
func (s *LayeredStore) CheckIntegrity() <-chan IntegrityCheckResult {
|
||||
return s.DatabaseLayer.CheckIntegrity()
|
||||
}
|
||||
|
||||
type LayeredRoleStore struct {
|
||||
*LayeredStore
|
||||
}
|
||||
|
||||
func (s *LayeredRoleStore) Save(role *model.Role) (*model.Role, *model.AppError) {
|
||||
return s.LayerChainHead.RoleSave(s.TmpContext, role)
|
||||
}
|
||||
|
||||
func (s *LayeredRoleStore) Get(roleId string) (*model.Role, *model.AppError) {
|
||||
return s.LayerChainHead.RoleGet(s.TmpContext, roleId)
|
||||
}
|
||||
|
||||
func (s *LayeredRoleStore) GetAll() ([]*model.Role, *model.AppError) {
|
||||
return s.LayerChainHead.RoleGetAll(s.TmpContext)
|
||||
}
|
||||
|
||||
func (s *LayeredRoleStore) GetByName(name string) (*model.Role, *model.AppError) {
|
||||
return s.LayerChainHead.RoleGetByName(s.TmpContext, name)
|
||||
}
|
||||
|
||||
func (s *LayeredRoleStore) GetByNames(names []string) ([]*model.Role, *model.AppError) {
|
||||
return s.LayerChainHead.RoleGetByNames(s.TmpContext, names)
|
||||
}
|
||||
|
||||
func (s *LayeredRoleStore) Delete(roldId string) (*model.Role, *model.AppError) {
|
||||
return s.LayerChainHead.RoleDelete(s.TmpContext, roldId)
|
||||
}
|
||||
|
||||
func (s *LayeredRoleStore) PermanentDeleteAll() *model.AppError {
|
||||
return s.LayerChainHead.RolePermanentDeleteAll(s.TmpContext)
|
||||
}
|
||||
|
||||
type LayeredSchemeStore struct {
|
||||
*LayeredStore
|
||||
}
|
||||
|
||||
func (s *LayeredSchemeStore) Save(scheme *model.Scheme) (*model.Scheme, *model.AppError) {
|
||||
return s.LayerChainHead.SchemeSave(s.TmpContext, scheme)
|
||||
}
|
||||
|
||||
func (s *LayeredSchemeStore) Get(schemeId string) (*model.Scheme, *model.AppError) {
|
||||
return s.LayerChainHead.SchemeGet(s.TmpContext, schemeId)
|
||||
}
|
||||
|
||||
func (s *LayeredSchemeStore) GetByName(schemeName string) (*model.Scheme, *model.AppError) {
|
||||
return s.LayerChainHead.SchemeGetByName(s.TmpContext, schemeName)
|
||||
}
|
||||
|
||||
func (s *LayeredSchemeStore) Delete(schemeId string) (*model.Scheme, *model.AppError) {
|
||||
return s.LayerChainHead.SchemeDelete(s.TmpContext, schemeId)
|
||||
}
|
||||
|
||||
func (s *LayeredSchemeStore) GetAllPage(scope string, offset int, limit int) ([]*model.Scheme, *model.AppError) {
|
||||
return s.LayerChainHead.SchemeGetAllPage(s.TmpContext, scope, offset, limit)
|
||||
}
|
||||
|
||||
func (s *LayeredSchemeStore) PermanentDeleteAll() *model.AppError {
|
||||
return s.LayerChainHead.SchemePermanentDeleteAll(s.TmpContext)
|
||||
}
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
|
||||
package store
|
||||
|
||||
import "github.com/mattermost/mattermost-server/model"
|
||||
import "context"
|
||||
|
||||
type LayeredStoreSupplierResult struct {
|
||||
StoreResult
|
||||
}
|
||||
@@ -20,21 +17,4 @@ type LayeredStoreSupplier interface {
|
||||
//
|
||||
SetChainNext(LayeredStoreSupplier)
|
||||
Next() LayeredStoreSupplier
|
||||
|
||||
// Roles
|
||||
RoleSave(ctx context.Context, role *model.Role, hints ...LayeredStoreHint) (*model.Role, *model.AppError)
|
||||
RoleGet(ctx context.Context, roleId string, hints ...LayeredStoreHint) (*model.Role, *model.AppError)
|
||||
RoleGetAll(ctx context.Context, hints ...LayeredStoreHint) ([]*model.Role, *model.AppError)
|
||||
RoleGetByName(ctx context.Context, name string, hints ...LayeredStoreHint) (*model.Role, *model.AppError)
|
||||
RoleGetByNames(ctx context.Context, names []string, hints ...LayeredStoreHint) ([]*model.Role, *model.AppError)
|
||||
RoleDelete(ctx context.Context, roldId string, hints ...LayeredStoreHint) (*model.Role, *model.AppError)
|
||||
RolePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *model.AppError
|
||||
|
||||
// Schemes
|
||||
SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError)
|
||||
SchemeGet(ctx context.Context, schemeId string, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError)
|
||||
SchemeGetByName(ctx context.Context, schemeName string, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError)
|
||||
SchemeDelete(ctx context.Context, schemeId string, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError)
|
||||
SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) ([]*model.Scheme, *model.AppError)
|
||||
SchemePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *model.AppError
|
||||
}
|
||||
|
||||
@@ -8,28 +8,16 @@ import (
|
||||
|
||||
"github.com/mattermost/mattermost-server/einterfaces"
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
ROLE_CACHE_SIZE = 20000
|
||||
ROLE_CACHE_SEC = 30 * 60
|
||||
|
||||
SCHEME_CACHE_SIZE = 20000
|
||||
SCHEME_CACHE_SEC = 30 * 60
|
||||
|
||||
GROUP_CACHE_SIZE = 20000
|
||||
GROUP_CACHE_SEC = 30 * 60
|
||||
|
||||
CLEAR_CACHE_MESSAGE_DATA = ""
|
||||
)
|
||||
|
||||
type LocalCacheSupplier struct {
|
||||
next LayeredStoreSupplier
|
||||
roleCache *utils.Cache
|
||||
schemeCache *utils.Cache
|
||||
metrics einterfaces.MetricsInterface
|
||||
cluster einterfaces.ClusterInterface
|
||||
next LayeredStoreSupplier
|
||||
metrics einterfaces.MetricsInterface
|
||||
cluster einterfaces.ClusterInterface
|
||||
}
|
||||
|
||||
// Caching Interface
|
||||
@@ -46,14 +34,8 @@ type ObjectCache interface {
|
||||
|
||||
func NewLocalCacheSupplier(metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface) *LocalCacheSupplier {
|
||||
supplier := &LocalCacheSupplier{
|
||||
roleCache: utils.NewLruWithParams(ROLE_CACHE_SIZE, "Role", ROLE_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES),
|
||||
schemeCache: utils.NewLruWithParams(SCHEME_CACHE_SIZE, "Scheme", SCHEME_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES),
|
||||
metrics: metrics,
|
||||
cluster: cluster,
|
||||
}
|
||||
|
||||
if cluster != nil {
|
||||
cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES, supplier.handleClusterInvalidateRole)
|
||||
metrics: metrics,
|
||||
cluster: cluster,
|
||||
}
|
||||
|
||||
return supplier
|
||||
@@ -122,6 +104,4 @@ func (s *LocalCacheSupplier) doClearCacheCluster(cache ObjectCache) {
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) Invalidate() {
|
||||
s.doClearCacheCluster(s.roleCache)
|
||||
s.doClearCacheCluster(s.schemeCache)
|
||||
}
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
)
|
||||
|
||||
func (s *LocalCacheSupplier) handleClusterInvalidateRole(msg *model.ClusterMessage) {
|
||||
if msg.Data == CLEAR_CACHE_MESSAGE_DATA {
|
||||
s.roleCache.Purge()
|
||||
} else {
|
||||
s.roleCache.Remove(msg.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) RoleSave(ctx context.Context, role *model.Role, hints ...LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
if len(role.Name) != 0 {
|
||||
defer s.doInvalidateCacheCluster(s.roleCache, role.Name)
|
||||
}
|
||||
return s.Next().RoleSave(ctx, role, hints...)
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) RoleGet(ctx context.Context, roleId string, hints ...LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
// Roles are cached by name, as that is most commonly how they are looked up.
|
||||
// This means that no caching is supported on roles being looked up by ID.
|
||||
return s.Next().RoleGet(ctx, roleId, hints...)
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) RoleGetAll(ctx context.Context, hints ...LayeredStoreHint) ([]*model.Role, *model.AppError) {
|
||||
// Roles are cached by name, as that is most commonly how they are looked up.
|
||||
// This means that no caching is supported on roles being listed.
|
||||
return s.Next().RoleGetAll(ctx, hints...)
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) RoleGetByName(ctx context.Context, name string, hints ...LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
if result := s.doStandardReadCache(ctx, s.roleCache, name, hints...); result != nil {
|
||||
return result.Data.(*model.Role), nil
|
||||
}
|
||||
|
||||
role, err := s.Next().RoleGetByName(ctx, name, hints...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := NewSupplierResult()
|
||||
result.Data = role
|
||||
s.doStandardAddToCache(ctx, s.roleCache, name, result, hints...)
|
||||
|
||||
return role, nil
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) RoleGetByNames(ctx context.Context, roleNames []string, hints ...LayeredStoreHint) ([]*model.Role, *model.AppError) {
|
||||
var foundRoles []*model.Role
|
||||
var rolesToQuery []string
|
||||
|
||||
for _, roleName := range roleNames {
|
||||
if result := s.doStandardReadCache(ctx, s.roleCache, roleName, hints...); result != nil {
|
||||
foundRoles = append(foundRoles, result.Data.(*model.Role))
|
||||
} else {
|
||||
rolesToQuery = append(rolesToQuery, roleName)
|
||||
}
|
||||
}
|
||||
|
||||
rolesFound, err := s.Next().RoleGetByNames(ctx, rolesToQuery, hints...)
|
||||
|
||||
for _, role := range rolesFound {
|
||||
res := NewSupplierResult()
|
||||
res.Data = role
|
||||
s.doStandardAddToCache(ctx, s.roleCache, role.Name, res, hints...)
|
||||
}
|
||||
foundRoles = append(foundRoles, rolesFound...)
|
||||
|
||||
return foundRoles, err
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) RoleDelete(ctx context.Context, roleId string, hints ...LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
role, err := s.Next().RoleDelete(ctx, roleId, hints...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.doInvalidateCacheCluster(s.roleCache, role.Name)
|
||||
|
||||
return role, nil
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) RolePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *model.AppError {
|
||||
defer s.roleCache.Purge()
|
||||
defer s.doClearCacheCluster(s.roleCache)
|
||||
|
||||
return s.Next().RolePermanentDeleteAll(ctx, hints...)
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
)
|
||||
|
||||
func (s *LocalCacheSupplier) handleClusterInvalidateScheme(msg *model.ClusterMessage) {
|
||||
if msg.Data == CLEAR_CACHE_MESSAGE_DATA {
|
||||
s.schemeCache.Purge()
|
||||
} else {
|
||||
s.schemeCache.Remove(msg.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
if len(scheme.Id) != 0 {
|
||||
defer s.doInvalidateCacheCluster(s.schemeCache, scheme.Id)
|
||||
}
|
||||
return s.Next().SchemeSave(ctx, scheme, hints...)
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) SchemeGet(ctx context.Context, schemeId string, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
if result := s.doStandardReadCache(ctx, s.schemeCache, schemeId, hints...); result != nil {
|
||||
return result.Data.(*model.Scheme), nil
|
||||
}
|
||||
|
||||
scheme, err := s.Next().SchemeGet(ctx, schemeId, hints...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := NewSupplierResult()
|
||||
result.Data = scheme
|
||||
s.doStandardAddToCache(ctx, s.schemeCache, schemeId, result, hints...)
|
||||
|
||||
return scheme, nil
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) SchemeGetByName(ctx context.Context, schemeName string, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
return s.Next().SchemeGetByName(ctx, schemeName, hints...)
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) SchemeDelete(ctx context.Context, schemeId string, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
defer s.doInvalidateCacheCluster(s.schemeCache, schemeId)
|
||||
defer s.doClearCacheCluster(s.roleCache)
|
||||
|
||||
return s.Next().SchemeDelete(ctx, schemeId, hints...)
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) ([]*model.Scheme, *model.AppError) {
|
||||
return s.Next().SchemeGetAllPage(ctx, scope, offset, limit, hints...)
|
||||
}
|
||||
|
||||
func (s *LocalCacheSupplier) SchemePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *model.AppError {
|
||||
defer s.doClearCacheCluster(s.schemeCache)
|
||||
defer s.doClearCacheCluster(s.roleCache)
|
||||
|
||||
return s.Next().SchemePermanentDeleteAll(ctx, hints...)
|
||||
}
|
||||
@@ -14,6 +14,12 @@ const (
|
||||
REACTION_CACHE_SIZE = 20000
|
||||
REACTION_CACHE_SEC = 30 * 60
|
||||
|
||||
ROLE_CACHE_SIZE = 20000
|
||||
ROLE_CACHE_SEC = 30 * 60
|
||||
|
||||
SCHEME_CACHE_SIZE = 20000
|
||||
SCHEME_CACHE_SEC = 30 * 60
|
||||
|
||||
CLEAR_CACHE_MESSAGE_DATA = ""
|
||||
)
|
||||
|
||||
@@ -23,6 +29,10 @@ type LocalCacheStore struct {
|
||||
cluster einterfaces.ClusterInterface
|
||||
reaction LocalCacheReactionStore
|
||||
reactionCache *utils.Cache
|
||||
role LocalCacheRoleStore
|
||||
roleCache *utils.Cache
|
||||
scheme LocalCacheSchemeStore
|
||||
schemeCache *utils.Cache
|
||||
}
|
||||
|
||||
func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface) LocalCacheStore {
|
||||
@@ -33,9 +43,15 @@ func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterf
|
||||
}
|
||||
localCacheStore.reactionCache = utils.NewLruWithParams(REACTION_CACHE_SIZE, "Reaction", REACTION_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_REACTIONS)
|
||||
localCacheStore.reaction = LocalCacheReactionStore{ReactionStore: baseStore.Reaction(), rootStore: &localCacheStore}
|
||||
localCacheStore.roleCache = utils.NewLruWithParams(ROLE_CACHE_SIZE, "Role", ROLE_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES)
|
||||
localCacheStore.role = LocalCacheRoleStore{RoleStore: baseStore.Role(), rootStore: &localCacheStore}
|
||||
localCacheStore.schemeCache = utils.NewLruWithParams(SCHEME_CACHE_SIZE, "Scheme", SCHEME_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES)
|
||||
localCacheStore.scheme = LocalCacheSchemeStore{SchemeStore: baseStore.Scheme(), rootStore: &localCacheStore}
|
||||
|
||||
if cluster != nil {
|
||||
cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_REACTIONS, localCacheStore.reaction.handleClusterInvalidateReaction)
|
||||
cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES, localCacheStore.role.handleClusterInvalidateRole)
|
||||
cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES, localCacheStore.scheme.handleClusterInvalidateScheme)
|
||||
}
|
||||
return localCacheStore
|
||||
}
|
||||
@@ -44,6 +60,14 @@ func (s LocalCacheStore) Reaction() store.ReactionStore {
|
||||
return s.reaction
|
||||
}
|
||||
|
||||
func (s LocalCacheStore) Role() store.RoleStore {
|
||||
return s.role
|
||||
}
|
||||
|
||||
func (s LocalCacheStore) Scheme() store.SchemeStore {
|
||||
return s.scheme
|
||||
}
|
||||
|
||||
func (s LocalCacheStore) DropAllTables() {
|
||||
s.Invalidate()
|
||||
s.Store.DropAllTables()
|
||||
|
||||
@@ -6,11 +6,44 @@ package localcachelayer
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/store/storetest/mocks"
|
||||
"github.com/mattermost/mattermost-server/testlib"
|
||||
)
|
||||
|
||||
var mainHelper *testlib.MainHelper
|
||||
|
||||
func getMockStore() *mocks.Store {
|
||||
mockStore := mocks.Store{}
|
||||
|
||||
fakeReaction := model.Reaction{PostId: "123"}
|
||||
mockReactionsStore := mocks.ReactionStore{}
|
||||
mockReactionsStore.On("Save", &fakeReaction).Return(&model.Reaction{}, nil)
|
||||
mockReactionsStore.On("Delete", &fakeReaction).Return(&model.Reaction{}, nil)
|
||||
mockReactionsStore.On("GetForPost", "123", false).Return([]*model.Reaction{&fakeReaction}, nil)
|
||||
mockReactionsStore.On("GetForPost", "123", true).Return([]*model.Reaction{&fakeReaction}, nil)
|
||||
mockStore.On("Reaction").Return(&mockReactionsStore)
|
||||
|
||||
fakeRole := model.Role{Id: "123", Name: "role-name"}
|
||||
mockRolesStore := mocks.RoleStore{}
|
||||
mockRolesStore.On("Save", &fakeRole).Return(&model.Role{}, nil)
|
||||
mockRolesStore.On("Delete", "123").Return(&fakeRole, nil)
|
||||
mockRolesStore.On("GetByName", "role-name").Return(&fakeRole, nil)
|
||||
mockRolesStore.On("GetByNames", []string{"role-name"}).Return([]*model.Role{&fakeRole}, nil)
|
||||
mockRolesStore.On("PermanentDeleteAll").Return(nil)
|
||||
mockStore.On("Role").Return(&mockRolesStore)
|
||||
|
||||
fakeScheme := model.Scheme{Id: "123", Name: "scheme-name"}
|
||||
mockSchemesStore := mocks.SchemeStore{}
|
||||
mockSchemesStore.On("Save", &fakeScheme).Return(&model.Scheme{}, nil)
|
||||
mockSchemesStore.On("Delete", "123").Return(&model.Scheme{}, nil)
|
||||
mockSchemesStore.On("Get", "123").Return(&fakeScheme, nil)
|
||||
mockSchemesStore.On("PermanentDeleteAll").Return(nil)
|
||||
mockStore.On("Scheme").Return(&mockSchemesStore)
|
||||
|
||||
return &mockStore
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
mainHelper = testlib.NewMainHelperWithOptions(nil)
|
||||
defer mainHelper.Close()
|
||||
|
||||
@@ -21,72 +21,48 @@ func TestReactionStoreCache(t *testing.T) {
|
||||
fakeReaction := model.Reaction{PostId: "123"}
|
||||
|
||||
t.Run("first call not cached, second cached and returning same data", func(t *testing.T) {
|
||||
mockStore := mocks.Store{}
|
||||
mockReactionsStore := mocks.ReactionStore{}
|
||||
mockReactionsStore.On("Save", &fakeReaction).Return(&model.Reaction{}, nil)
|
||||
mockReactionsStore.On("Delete", &fakeReaction).Return(&model.Reaction{}, nil)
|
||||
mockReactionsStore.On("GetForPost", "123", false).Return([]*model.Reaction{&fakeReaction}, nil)
|
||||
mockReactionsStore.On("GetForPost", "123", true).Return([]*model.Reaction{&fakeReaction}, nil)
|
||||
mockStore.On("Reaction").Return(&mockReactionsStore)
|
||||
cachedStore := NewLocalCacheLayer(&mockStore, nil, nil)
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
reaction, err := cachedStore.Reaction().GetForPost("123", true)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, reaction, []*model.Reaction{&fakeReaction})
|
||||
mockReactionsStore.AssertNumberOfCalls(t, "GetForPost", 1)
|
||||
mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, reaction, []*model.Reaction{&fakeReaction})
|
||||
cachedStore.Reaction().GetForPost("123", true)
|
||||
mockReactionsStore.AssertNumberOfCalls(t, "GetForPost", 1)
|
||||
mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 1)
|
||||
})
|
||||
|
||||
t.Run("first call not cached, second force no cached", func(t *testing.T) {
|
||||
mockStore := mocks.Store{}
|
||||
mockReactionsStore := mocks.ReactionStore{}
|
||||
mockReactionsStore.On("Save", &fakeReaction).Return(&model.Reaction{}, nil)
|
||||
mockReactionsStore.On("Delete", &fakeReaction).Return(&model.Reaction{}, nil)
|
||||
mockReactionsStore.On("GetForPost", "123", false).Return([]*model.Reaction{&fakeReaction}, nil)
|
||||
mockReactionsStore.On("GetForPost", "123", true).Return([]*model.Reaction{&fakeReaction}, nil)
|
||||
mockStore.On("Reaction").Return(&mockReactionsStore)
|
||||
cachedStore := NewLocalCacheLayer(&mockStore, nil, nil)
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
cachedStore.Reaction().GetForPost("123", true)
|
||||
mockReactionsStore.AssertNumberOfCalls(t, "GetForPost", 1)
|
||||
mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 1)
|
||||
cachedStore.Reaction().GetForPost("123", false)
|
||||
mockReactionsStore.AssertNumberOfCalls(t, "GetForPost", 2)
|
||||
mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 2)
|
||||
})
|
||||
|
||||
t.Run("first call not cached, save, and then not cached again", func(t *testing.T) {
|
||||
mockStore := mocks.Store{}
|
||||
mockReactionsStore := mocks.ReactionStore{}
|
||||
mockReactionsStore.On("Save", &fakeReaction).Return(&model.Reaction{}, nil)
|
||||
mockReactionsStore.On("Delete", &fakeReaction).Return(&model.Reaction{}, nil)
|
||||
mockReactionsStore.On("GetForPost", "123", false).Return([]*model.Reaction{&fakeReaction}, nil)
|
||||
mockReactionsStore.On("GetForPost", "123", true).Return([]*model.Reaction{&fakeReaction}, nil)
|
||||
mockStore.On("Reaction").Return(&mockReactionsStore)
|
||||
cachedStore := NewLocalCacheLayer(&mockStore, nil, nil)
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
cachedStore.Reaction().GetForPost("123", true)
|
||||
mockReactionsStore.AssertNumberOfCalls(t, "GetForPost", 1)
|
||||
mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 1)
|
||||
cachedStore.Reaction().Save(&fakeReaction)
|
||||
cachedStore.Reaction().GetForPost("123", true)
|
||||
mockReactionsStore.AssertNumberOfCalls(t, "GetForPost", 2)
|
||||
mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 2)
|
||||
})
|
||||
|
||||
t.Run("first call not cached, delete, and then not cached again", func(t *testing.T) {
|
||||
mockStore := mocks.Store{}
|
||||
mockReactionsStore := mocks.ReactionStore{}
|
||||
mockReactionsStore.On("Save", &fakeReaction).Return(&model.Reaction{}, nil)
|
||||
mockReactionsStore.On("Delete", &fakeReaction).Return(&model.Reaction{}, nil)
|
||||
mockReactionsStore.On("GetForPost", "123", false).Return([]*model.Reaction{&fakeReaction}, nil)
|
||||
mockReactionsStore.On("GetForPost", "123", true).Return([]*model.Reaction{&fakeReaction}, nil)
|
||||
mockStore.On("Reaction").Return(&mockReactionsStore)
|
||||
cachedStore := NewLocalCacheLayer(&mockStore, nil, nil)
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
cachedStore.Reaction().GetForPost("123", true)
|
||||
mockReactionsStore.AssertNumberOfCalls(t, "GetForPost", 1)
|
||||
mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 1)
|
||||
cachedStore.Reaction().Delete(&fakeReaction)
|
||||
cachedStore.Reaction().GetForPost("123", true)
|
||||
mockReactionsStore.AssertNumberOfCalls(t, "GetForPost", 2)
|
||||
mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 2)
|
||||
})
|
||||
}
|
||||
|
||||
80
store/localcachelayer/role_layer.go
Normal file
80
store/localcachelayer/role_layer.go
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package localcachelayer
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/store"
|
||||
)
|
||||
|
||||
type LocalCacheRoleStore struct {
|
||||
store.RoleStore
|
||||
rootStore *LocalCacheStore
|
||||
}
|
||||
|
||||
func (s *LocalCacheRoleStore) handleClusterInvalidateRole(msg *model.ClusterMessage) {
|
||||
if msg.Data == CLEAR_CACHE_MESSAGE_DATA {
|
||||
s.rootStore.roleCache.Purge()
|
||||
} else {
|
||||
s.rootStore.roleCache.Remove(msg.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func (s LocalCacheRoleStore) Save(role *model.Role) (*model.Role, *model.AppError) {
|
||||
if len(role.Name) != 0 {
|
||||
defer s.rootStore.doInvalidateCacheCluster(s.rootStore.roleCache, role.Name)
|
||||
}
|
||||
return s.RoleStore.Save(role)
|
||||
}
|
||||
|
||||
func (s LocalCacheRoleStore) GetByName(name string) (*model.Role, *model.AppError) {
|
||||
if role := s.rootStore.doStandardReadCache(s.rootStore.roleCache, name); role != nil {
|
||||
return role.(*model.Role), nil
|
||||
}
|
||||
|
||||
role, err := s.RoleStore.GetByName(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.rootStore.doStandardAddToCache(s.rootStore.roleCache, name, role)
|
||||
return role, nil
|
||||
}
|
||||
|
||||
func (s LocalCacheRoleStore) GetByNames(names []string) ([]*model.Role, *model.AppError) {
|
||||
var foundRoles []*model.Role
|
||||
var rolesToQuery []string
|
||||
|
||||
for _, roleName := range names {
|
||||
if role := s.rootStore.doStandardReadCache(s.rootStore.roleCache, roleName); role != nil {
|
||||
foundRoles = append(foundRoles, role.(*model.Role))
|
||||
} else {
|
||||
rolesToQuery = append(rolesToQuery, roleName)
|
||||
}
|
||||
}
|
||||
|
||||
roles, _ := s.RoleStore.GetByNames(rolesToQuery)
|
||||
|
||||
if roles != nil {
|
||||
for _, role := range roles {
|
||||
s.rootStore.doStandardAddToCache(s.rootStore.roleCache, role.Name, role)
|
||||
}
|
||||
}
|
||||
return append(foundRoles, roles...), nil
|
||||
}
|
||||
|
||||
func (s LocalCacheRoleStore) Delete(roleId string) (*model.Role, *model.AppError) {
|
||||
role, err := s.RoleStore.Delete(roleId)
|
||||
|
||||
if err == nil {
|
||||
s.rootStore.doInvalidateCacheCluster(s.rootStore.roleCache, role.Name)
|
||||
}
|
||||
return role, err
|
||||
}
|
||||
|
||||
func (s LocalCacheRoleStore) PermanentDeleteAll() *model.AppError {
|
||||
defer s.rootStore.roleCache.Purge()
|
||||
defer s.rootStore.doClearCacheCluster(s.rootStore.roleCache)
|
||||
|
||||
return s.RoleStore.PermanentDeleteAll()
|
||||
}
|
||||
69
store/localcachelayer/role_layer_test.go
Normal file
69
store/localcachelayer/role_layer_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package localcachelayer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/store/storetest"
|
||||
"github.com/mattermost/mattermost-server/store/storetest/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRoleStore(t *testing.T) {
|
||||
StoreTest(t, storetest.TestRoleStore)
|
||||
}
|
||||
|
||||
func TestRoleStoreCache(t *testing.T) {
|
||||
fakeRole := model.Role{Id: "123", Name: "role-name"}
|
||||
|
||||
t.Run("first call not cached, second cached and returning same data", func(t *testing.T) {
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
role, err := cachedStore.Role().GetByName("role-name")
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, role, &fakeRole)
|
||||
mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, role, &fakeRole)
|
||||
cachedStore.Role().GetByName("role-name")
|
||||
mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 1)
|
||||
})
|
||||
|
||||
t.Run("first call not cached, save, and then not cached again", func(t *testing.T) {
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
cachedStore.Role().GetByName("role-name")
|
||||
mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 1)
|
||||
cachedStore.Role().Save(&fakeRole)
|
||||
cachedStore.Role().GetByName("role-name")
|
||||
mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 2)
|
||||
})
|
||||
|
||||
t.Run("first call not cached, delete, and then not cached again", func(t *testing.T) {
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
cachedStore.Role().GetByName("role-name")
|
||||
mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 1)
|
||||
cachedStore.Role().Delete("123")
|
||||
cachedStore.Role().GetByName("role-name")
|
||||
mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 2)
|
||||
})
|
||||
|
||||
t.Run("first call not cached, permanent delete all, and then not cached again", func(t *testing.T) {
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
cachedStore.Role().GetByName("role-name")
|
||||
mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 1)
|
||||
cachedStore.Role().PermanentDeleteAll()
|
||||
cachedStore.Role().GetByName("role-name")
|
||||
mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 2)
|
||||
})
|
||||
}
|
||||
58
store/localcachelayer/scheme_layer.go
Normal file
58
store/localcachelayer/scheme_layer.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package localcachelayer
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/store"
|
||||
)
|
||||
|
||||
type LocalCacheSchemeStore struct {
|
||||
store.SchemeStore
|
||||
rootStore *LocalCacheStore
|
||||
}
|
||||
|
||||
func (s *LocalCacheSchemeStore) handleClusterInvalidateScheme(msg *model.ClusterMessage) {
|
||||
if msg.Data == CLEAR_CACHE_MESSAGE_DATA {
|
||||
s.rootStore.schemeCache.Purge()
|
||||
} else {
|
||||
s.rootStore.schemeCache.Remove(msg.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func (s LocalCacheSchemeStore) Save(scheme *model.Scheme) (*model.Scheme, *model.AppError) {
|
||||
if len(scheme.Id) != 0 {
|
||||
defer s.rootStore.doInvalidateCacheCluster(s.rootStore.schemeCache, scheme.Id)
|
||||
}
|
||||
return s.SchemeStore.Save(scheme)
|
||||
}
|
||||
|
||||
func (s LocalCacheSchemeStore) Get(schemeId string) (*model.Scheme, *model.AppError) {
|
||||
if scheme := s.rootStore.doStandardReadCache(s.rootStore.schemeCache, schemeId); scheme != nil {
|
||||
return scheme.(*model.Scheme), nil
|
||||
}
|
||||
|
||||
scheme, err := s.SchemeStore.Get(schemeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.rootStore.doStandardAddToCache(s.rootStore.schemeCache, schemeId, scheme)
|
||||
|
||||
return scheme, nil
|
||||
}
|
||||
|
||||
func (s LocalCacheSchemeStore) Delete(schemeId string) (*model.Scheme, *model.AppError) {
|
||||
defer s.rootStore.doInvalidateCacheCluster(s.rootStore.schemeCache, schemeId)
|
||||
defer s.rootStore.doClearCacheCluster(s.rootStore.roleCache)
|
||||
|
||||
return s.SchemeStore.Delete(schemeId)
|
||||
}
|
||||
|
||||
func (s LocalCacheSchemeStore) PermanentDeleteAll() *model.AppError {
|
||||
defer s.rootStore.doClearCacheCluster(s.rootStore.schemeCache)
|
||||
defer s.rootStore.doClearCacheCluster(s.rootStore.roleCache)
|
||||
|
||||
return s.SchemeStore.PermanentDeleteAll()
|
||||
}
|
||||
69
store/localcachelayer/scheme_layer_test.go
Normal file
69
store/localcachelayer/scheme_layer_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package localcachelayer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/store/storetest"
|
||||
"github.com/mattermost/mattermost-server/store/storetest/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSchemeStore(t *testing.T) {
|
||||
StoreTest(t, storetest.TestSchemeStore)
|
||||
}
|
||||
|
||||
func TestSchemeStoreCache(t *testing.T) {
|
||||
fakeScheme := model.Scheme{Id: "123", Name: "scheme-name"}
|
||||
|
||||
t.Run("first call not cached, second cached and returning same data", func(t *testing.T) {
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
scheme, err := cachedStore.Scheme().Get("123")
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, scheme, &fakeScheme)
|
||||
mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, scheme, &fakeScheme)
|
||||
cachedStore.Scheme().Get("123")
|
||||
mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 1)
|
||||
})
|
||||
|
||||
t.Run("first call not cached, save, and then not cached again", func(t *testing.T) {
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
cachedStore.Scheme().Get("123")
|
||||
mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 1)
|
||||
cachedStore.Scheme().Save(&fakeScheme)
|
||||
cachedStore.Scheme().Get("123")
|
||||
mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 2)
|
||||
})
|
||||
|
||||
t.Run("first call not cached, delete, and then not cached again", func(t *testing.T) {
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
cachedStore.Scheme().Get("123")
|
||||
mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 1)
|
||||
cachedStore.Scheme().Delete("123")
|
||||
cachedStore.Scheme().Get("123")
|
||||
mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 2)
|
||||
})
|
||||
|
||||
t.Run("first call not cached, permanent delete all, and then not cached again", func(t *testing.T) {
|
||||
mockStore := getMockStore()
|
||||
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
|
||||
|
||||
cachedStore.Scheme().Get("123")
|
||||
mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 1)
|
||||
cachedStore.Scheme().PermanentDeleteAll()
|
||||
cachedStore.Scheme().Get("123")
|
||||
mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 2)
|
||||
})
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/mattermost/mattermost-server/mlog"
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
)
|
||||
|
||||
func (s *RedisSupplier) RoleSave(ctx context.Context, role *model.Role, hints ...LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
key := buildRedisKeyForRoleName(role.Name)
|
||||
|
||||
defer func() {
|
||||
if err := s.client.Del(key).Err(); err != nil {
|
||||
mlog.Error("Redis failed to remove key " + key + " Error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
return s.Next().RoleSave(ctx, role, hints...)
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) RoleGet(ctx context.Context, roleId string, hints ...LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
// Roles are cached by name, as that is most commonly how they are looked up.
|
||||
// This means that no caching is supported on roles being looked up by ID.
|
||||
return s.Next().RoleGet(ctx, roleId, hints...)
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) RoleGetAll(ctx context.Context, hints ...LayeredStoreHint) ([]*model.Role, *model.AppError) {
|
||||
// Roles are cached by name, as that is most commonly how they are looked up.
|
||||
// This means that no caching is supported on roles being listed.
|
||||
return s.Next().RoleGetAll(ctx, hints...)
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) RoleGetByName(ctx context.Context, name string, hints ...LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
key := buildRedisKeyForRoleName(name)
|
||||
|
||||
var role *model.Role
|
||||
found, err := s.load(key, &role)
|
||||
if err != nil {
|
||||
mlog.Error("Redis encountered an error on read: " + err.Error())
|
||||
} else if found {
|
||||
return role, nil
|
||||
}
|
||||
|
||||
role, appErr := s.Next().RoleGetByName(ctx, name, hints...)
|
||||
|
||||
if appErr == nil {
|
||||
if err := s.save(key, role, REDIS_EXPIRY_TIME); err != nil {
|
||||
mlog.Error("Redis encountered and error on write: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return role, appErr
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) RoleGetByNames(ctx context.Context, roleNames []string, hints ...LayeredStoreHint) ([]*model.Role, *model.AppError) {
|
||||
var foundRoles []*model.Role
|
||||
var rolesToQuery []string
|
||||
|
||||
for _, roleName := range roleNames {
|
||||
var role *model.Role
|
||||
found, err := s.load(buildRedisKeyForRoleName(roleName), &role)
|
||||
if err == nil && found {
|
||||
foundRoles = append(foundRoles, role)
|
||||
} else {
|
||||
rolesToQuery = append(rolesToQuery, roleName)
|
||||
if err != nil {
|
||||
mlog.Error("Redis encountered an error on read: " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rolesFound, appErr := s.Next().RoleGetByNames(ctx, rolesToQuery, hints...)
|
||||
|
||||
if appErr == nil {
|
||||
for _, role := range rolesFound {
|
||||
if err := s.save(buildRedisKeyForRoleName(role.Name), role, REDIS_EXPIRY_TIME); err != nil {
|
||||
mlog.Error("Redis encountered and error on write: " + err.Error())
|
||||
}
|
||||
}
|
||||
foundRoles = append(foundRoles, rolesFound...)
|
||||
}
|
||||
|
||||
return foundRoles, appErr
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) RoleDelete(ctx context.Context, roleId string, hints ...LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
role, appErr := s.Next().RoleGet(ctx, roleId, hints...)
|
||||
|
||||
if appErr == nil {
|
||||
defer func() {
|
||||
key := buildRedisKeyForRoleName(role.Name)
|
||||
|
||||
if err := s.client.Del(key).Err(); err != nil {
|
||||
mlog.Error("Redis failed to remove key " + key + " Error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return s.Next().RoleDelete(ctx, roleId, hints...)
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) RolePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *model.AppError {
|
||||
defer func() {
|
||||
if keys, err := s.client.Keys("roles:*").Result(); err != nil {
|
||||
mlog.Error("Redis encountered an error on read: " + err.Error())
|
||||
} else {
|
||||
if err := s.client.Del(keys...).Err(); err != nil {
|
||||
mlog.Error("Redis encountered an error on delete: " + err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return s.Next().RolePermanentDeleteAll(ctx, hints...)
|
||||
}
|
||||
|
||||
func buildRedisKeyForRoleName(roleName string) string {
|
||||
return fmt.Sprintf("roles:%s", roleName)
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
)
|
||||
|
||||
func (s *RedisSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
// TODO: Redis caching.
|
||||
return s.Next().SchemeSave(ctx, scheme, hints...)
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) SchemeGet(ctx context.Context, schemeId string, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
// TODO: Redis caching.
|
||||
return s.Next().SchemeGet(ctx, schemeId, hints...)
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) SchemeGetByName(ctx context.Context, schemeName string, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
// TODO: Redis caching.
|
||||
return s.Next().SchemeGetByName(ctx, schemeName, hints...)
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) SchemeDelete(ctx context.Context, schemeId string, hints ...LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
// TODO: Redis caching.
|
||||
return s.Next().SchemeDelete(ctx, schemeId, hints...)
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) ([]*model.Scheme, *model.AppError) {
|
||||
// TODO: Redis caching.
|
||||
return s.Next().SchemeGetAllPage(ctx, scope, offset, limit, hints...)
|
||||
}
|
||||
|
||||
func (s *RedisSupplier) SchemePermanentDeleteAll(ctx context.Context, hints ...LayeredStoreHint) *model.AppError {
|
||||
// TODO: Redis caching.
|
||||
return s.Next().SchemePermanentDeleteAll(ctx, hints...)
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -15,6 +14,10 @@ import (
|
||||
"github.com/mattermost/mattermost-server/store"
|
||||
)
|
||||
|
||||
type SqlRoleStore struct {
|
||||
SqlStore
|
||||
}
|
||||
|
||||
type Role struct {
|
||||
Id string
|
||||
Name string
|
||||
@@ -68,7 +71,9 @@ func (role Role) ToModel() *model.Role {
|
||||
}
|
||||
}
|
||||
|
||||
func initSqlSupplierRoles(sqlStore SqlStore) {
|
||||
func NewSqlRoleStore(sqlStore SqlStore) store.RoleStore {
|
||||
s := &SqlRoleStore{sqlStore}
|
||||
|
||||
for _, db := range sqlStore.GetAllConns() {
|
||||
table := db.AddTableWithName(Role{}, "Roles").SetKeys(false, "Id")
|
||||
table.ColMap("Id").SetMaxSize(26)
|
||||
@@ -77,9 +82,13 @@ func initSqlSupplierRoles(sqlStore SqlStore) {
|
||||
table.ColMap("Description").SetMaxSize(1024)
|
||||
table.ColMap("Permissions").SetMaxSize(4096)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) RoleSave(ctx context.Context, role *model.Role, hints ...store.LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
func (s SqlRoleStore) CreateIndexesIfNotExists() {
|
||||
}
|
||||
|
||||
func (s *SqlRoleStore) Save(role *model.Role) (*model.Role, *model.AppError) {
|
||||
// Check the role is valid before proceeding.
|
||||
if !role.IsValidWithoutId() {
|
||||
return nil, model.NewAppError("SqlRoleStore.Save", "store.sql_role.save.invalid_role.app_error", nil, "", http.StatusBadRequest)
|
||||
@@ -91,7 +100,7 @@ func (s *SqlSupplier) RoleSave(ctx context.Context, role *model.Role, hints ...s
|
||||
return nil, model.NewAppError("SqlRoleStore.RoleSave", "store.sql_role.save.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
defer finalizeTransaction(transaction)
|
||||
createdRole, appErr := s.createRole(ctx, role, transaction, hints...)
|
||||
createdRole, appErr := s.createRole(role, transaction)
|
||||
if appErr != nil {
|
||||
transaction.Rollback()
|
||||
return nil, appErr
|
||||
@@ -112,7 +121,7 @@ func (s *SqlSupplier) RoleSave(ctx context.Context, role *model.Role, hints ...s
|
||||
return dbRole.ToModel(), nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) createRole(ctx context.Context, role *model.Role, transaction *gorp.Transaction, hints ...store.LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
func (s *SqlRoleStore) createRole(role *model.Role, transaction *gorp.Transaction) (*model.Role, *model.AppError) {
|
||||
// Check the role is valid before proceeding.
|
||||
if !role.IsValidWithoutId() {
|
||||
return nil, model.NewAppError("SqlRoleStore.Save", "store.sql_role.save.invalid_role.app_error", nil, "", http.StatusBadRequest)
|
||||
@@ -131,7 +140,7 @@ func (s *SqlSupplier) createRole(ctx context.Context, role *model.Role, transact
|
||||
return dbRole.ToModel(), nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) RoleGet(ctx context.Context, roleId string, hints ...store.LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
func (s *SqlRoleStore) Get(roleId string) (*model.Role, *model.AppError) {
|
||||
var dbRole Role
|
||||
|
||||
if err := s.GetReplica().SelectOne(&dbRole, "SELECT * from Roles WHERE Id = :Id", map[string]interface{}{"Id": roleId}); err != nil {
|
||||
@@ -144,7 +153,7 @@ func (s *SqlSupplier) RoleGet(ctx context.Context, roleId string, hints ...store
|
||||
return dbRole.ToModel(), nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) RoleGetAll(ctx context.Context, hints ...store.LayeredStoreHint) ([]*model.Role, *model.AppError) {
|
||||
func (s *SqlRoleStore) GetAll() ([]*model.Role, *model.AppError) {
|
||||
var dbRoles []Role
|
||||
|
||||
if _, err := s.GetReplica().Select(&dbRoles, "SELECT * from Roles", map[string]interface{}{}); err != nil {
|
||||
@@ -161,7 +170,7 @@ func (s *SqlSupplier) RoleGetAll(ctx context.Context, hints ...store.LayeredStor
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) RoleGetByName(ctx context.Context, name string, hints ...store.LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
func (s *SqlRoleStore) GetByName(name string) (*model.Role, *model.AppError) {
|
||||
var dbRole Role
|
||||
|
||||
if err := s.GetReplica().SelectOne(&dbRole, "SELECT * from Roles WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil {
|
||||
@@ -174,7 +183,7 @@ func (s *SqlSupplier) RoleGetByName(ctx context.Context, name string, hints ...s
|
||||
return dbRole.ToModel(), nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) RoleGetByNames(ctx context.Context, names []string, hints ...store.LayeredStoreHint) ([]*model.Role, *model.AppError) {
|
||||
func (s *SqlRoleStore) GetByNames(names []string) ([]*model.Role, *model.AppError) {
|
||||
var dbRoles []*Role
|
||||
|
||||
if len(names) == 0 {
|
||||
@@ -202,7 +211,7 @@ func (s *SqlSupplier) RoleGetByNames(ctx context.Context, names []string, hints
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) RoleDelete(ctx context.Context, roleId string, hints ...store.LayeredStoreHint) (*model.Role, *model.AppError) {
|
||||
func (s *SqlRoleStore) Delete(roleId string) (*model.Role, *model.AppError) {
|
||||
// Get the role.
|
||||
var role *Role
|
||||
if err := s.GetReplica().SelectOne(&role, "SELECT * from Roles WHERE Id = :Id", map[string]interface{}{"Id": roleId}); err != nil {
|
||||
@@ -224,7 +233,7 @@ func (s *SqlSupplier) RoleDelete(ctx context.Context, roleId string, hints ...st
|
||||
return role.ToModel(), nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) RolePermanentDeleteAll(ctx context.Context, hints ...store.LayeredStoreHint) *model.AppError {
|
||||
func (s *SqlRoleStore) PermanentDeleteAll() *model.AppError {
|
||||
if _, err := s.GetMaster().Exec("DELETE FROM Roles"); err != nil {
|
||||
return model.NewAppError("SqlRoleStore.PermanentDeleteAll", "store.sql_role.permanent_delete_all.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -16,7 +15,13 @@ import (
|
||||
"github.com/mattermost/mattermost-server/store"
|
||||
)
|
||||
|
||||
func initSqlSupplierSchemes(sqlStore SqlStore) {
|
||||
type SqlSchemeStore struct {
|
||||
SqlStore
|
||||
}
|
||||
|
||||
func NewSqlSchemeStore(sqlStore SqlStore) store.SchemeStore {
|
||||
s := &SqlSchemeStore{sqlStore}
|
||||
|
||||
for _, db := range sqlStore.GetAllConns() {
|
||||
table := db.AddTableWithName(model.Scheme{}, "Schemes").SetKeys(false, "Id")
|
||||
table.ColMap("Id").SetMaxSize(26)
|
||||
@@ -31,9 +36,14 @@ func initSqlSupplierSchemes(sqlStore SqlStore) {
|
||||
table.ColMap("DefaultChannelUserRole").SetMaxSize(64)
|
||||
table.ColMap("DefaultChannelGuestRole").SetMaxSize(64)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
func (s SqlSchemeStore) CreateIndexesIfNotExists() {
|
||||
}
|
||||
|
||||
func (s *SqlSchemeStore) Save(scheme *model.Scheme) (*model.Scheme, *model.AppError) {
|
||||
if len(scheme.Id) == 0 {
|
||||
transaction, err := s.GetMaster().Begin()
|
||||
if err != nil {
|
||||
@@ -41,7 +51,7 @@ func (s *SqlSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hint
|
||||
}
|
||||
defer finalizeTransaction(transaction)
|
||||
|
||||
newScheme, appErr := s.createScheme(ctx, scheme, transaction, hints...)
|
||||
newScheme, appErr := s.createScheme(scheme, transaction)
|
||||
if appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
@@ -68,11 +78,11 @@ func (s *SqlSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hint
|
||||
return scheme, nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) createScheme(ctx context.Context, scheme *model.Scheme, transaction *gorp.Transaction, hints ...store.LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
func (s *SqlSchemeStore) createScheme(scheme *model.Scheme, transaction *gorp.Transaction) (*model.Scheme, *model.AppError) {
|
||||
// Fetch the default system scheme roles to populate default permissions.
|
||||
defaultRoleNames := []string{model.TEAM_ADMIN_ROLE_ID, model.TEAM_USER_ROLE_ID, model.TEAM_GUEST_ROLE_ID, model.CHANNEL_ADMIN_ROLE_ID, model.CHANNEL_USER_ROLE_ID, model.CHANNEL_GUEST_ROLE_ID}
|
||||
defaultRoles := make(map[string]*model.Role)
|
||||
roles, err := s.RoleGetByNames(ctx, defaultRoleNames)
|
||||
roles, err := s.SqlStore.Role().GetByNames(defaultRoleNames)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -108,7 +118,7 @@ func (s *SqlSupplier) createScheme(ctx context.Context, scheme *model.Scheme, tr
|
||||
SchemeManaged: true,
|
||||
}
|
||||
|
||||
savedRole, err := s.createRole(ctx, teamAdminRole, transaction)
|
||||
savedRole, err := s.SqlStore.Role().(*SqlRoleStore).createRole(teamAdminRole, transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -122,7 +132,7 @@ func (s *SqlSupplier) createScheme(ctx context.Context, scheme *model.Scheme, tr
|
||||
SchemeManaged: true,
|
||||
}
|
||||
|
||||
savedRole, err = s.createRole(ctx, teamUserRole, transaction)
|
||||
savedRole, err = s.SqlStore.Role().(*SqlRoleStore).createRole(teamUserRole, transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -136,7 +146,7 @@ func (s *SqlSupplier) createScheme(ctx context.Context, scheme *model.Scheme, tr
|
||||
SchemeManaged: true,
|
||||
}
|
||||
|
||||
savedRole, err = s.createRole(ctx, teamGuestRole, transaction)
|
||||
savedRole, err = s.SqlStore.Role().(*SqlRoleStore).createRole(teamGuestRole, transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -151,7 +161,7 @@ func (s *SqlSupplier) createScheme(ctx context.Context, scheme *model.Scheme, tr
|
||||
SchemeManaged: true,
|
||||
}
|
||||
|
||||
savedRole, err := s.createRole(ctx, channelAdminRole, transaction)
|
||||
savedRole, err := s.SqlStore.Role().(*SqlRoleStore).createRole(channelAdminRole, transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -165,7 +175,7 @@ func (s *SqlSupplier) createScheme(ctx context.Context, scheme *model.Scheme, tr
|
||||
SchemeManaged: true,
|
||||
}
|
||||
|
||||
savedRole, err = s.createRole(ctx, channelUserRole, transaction)
|
||||
savedRole, err = s.SqlStore.Role().(*SqlRoleStore).createRole(channelUserRole, transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -179,7 +189,7 @@ func (s *SqlSupplier) createScheme(ctx context.Context, scheme *model.Scheme, tr
|
||||
SchemeManaged: true,
|
||||
}
|
||||
|
||||
savedRole, err = s.createRole(ctx, channelGuestRole, transaction)
|
||||
savedRole, err = s.SqlStore.Role().(*SqlRoleStore).createRole(channelGuestRole, transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -205,7 +215,7 @@ func (s *SqlSupplier) createScheme(ctx context.Context, scheme *model.Scheme, tr
|
||||
return scheme, nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) SchemeGet(ctx context.Context, schemeId string, hints ...store.LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
func (s *SqlSchemeStore) Get(schemeId string) (*model.Scheme, *model.AppError) {
|
||||
var scheme model.Scheme
|
||||
if err := s.GetReplica().SelectOne(&scheme, "SELECT * from Schemes WHERE Id = :Id", map[string]interface{}{"Id": schemeId}); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
@@ -217,7 +227,7 @@ func (s *SqlSupplier) SchemeGet(ctx context.Context, schemeId string, hints ...s
|
||||
return &scheme, nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) SchemeGetByName(ctx context.Context, schemeName string, hints ...store.LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
func (s *SqlSchemeStore) GetByName(schemeName string) (*model.Scheme, *model.AppError) {
|
||||
var scheme model.Scheme
|
||||
|
||||
if err := s.GetReplica().SelectOne(&scheme, "SELECT * from Schemes WHERE Name = :Name", map[string]interface{}{"Name": schemeName}); err != nil {
|
||||
@@ -230,7 +240,7 @@ func (s *SqlSupplier) SchemeGetByName(ctx context.Context, schemeName string, hi
|
||||
return &scheme, nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) SchemeDelete(ctx context.Context, schemeId string, hints ...store.LayeredStoreHint) (*model.Scheme, *model.AppError) {
|
||||
func (s *SqlSchemeStore) Delete(schemeId string) (*model.Scheme, *model.AppError) {
|
||||
// Get the scheme
|
||||
var scheme model.Scheme
|
||||
if err := s.GetReplica().SelectOne(&scheme, "SELECT * from Schemes WHERE Id = :Id", map[string]interface{}{"Id": schemeId}); err != nil {
|
||||
@@ -290,7 +300,7 @@ func (s *SqlSupplier) SchemeDelete(ctx context.Context, schemeId string, hints .
|
||||
return &scheme, nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...store.LayeredStoreHint) ([]*model.Scheme, *model.AppError) {
|
||||
func (s *SqlSchemeStore) GetAllPage(scope string, offset int, limit int) ([]*model.Scheme, *model.AppError) {
|
||||
var schemes []*model.Scheme
|
||||
|
||||
scopeClause := ""
|
||||
@@ -305,7 +315,7 @@ func (s *SqlSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset
|
||||
return schemes, nil
|
||||
}
|
||||
|
||||
func (s *SqlSupplier) SchemePermanentDeleteAll(ctx context.Context, hints ...store.LayeredStoreHint) *model.AppError {
|
||||
func (s *SqlSchemeStore) PermanentDeleteAll() *model.AppError {
|
||||
if _, err := s.GetMaster().Exec("DELETE from Schemes"); err != nil {
|
||||
return model.NewAppError("SqlSchemeStore.PermanentDeleteAll", "store.sql_scheme.permanent_delete_all.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
@@ -152,11 +152,10 @@ func NewSqlSupplier(settings model.SqlSettings, metrics einterfaces.MetricsInter
|
||||
supplier.oldStores.UserTermsOfService = NewSqlUserTermsOfServiceStore(supplier)
|
||||
supplier.oldStores.linkMetadata = NewSqlLinkMetadataStore(supplier)
|
||||
supplier.oldStores.reaction = NewSqlReactionStore(supplier)
|
||||
supplier.oldStores.role = NewSqlRoleStore(supplier)
|
||||
supplier.oldStores.scheme = NewSqlSchemeStore(supplier)
|
||||
supplier.oldStores.group = NewSqlGroupStore(supplier)
|
||||
|
||||
initSqlSupplierRoles(supplier)
|
||||
initSqlSupplierSchemes(supplier)
|
||||
|
||||
err := supplier.GetMaster().CreateTablesIfNotExists()
|
||||
if err != nil {
|
||||
mlog.Critical("Error creating database tables.", mlog.Err(err))
|
||||
|
||||
@@ -48,9 +48,11 @@ func (c *FakeClusterInterface) ConfigChanged(previousConfig *model.Config, newCo
|
||||
}
|
||||
|
||||
func (c *FakeClusterInterface) SendClearRoleCacheMessage() {
|
||||
c.clusterMessageHandler(&model.ClusterMessage{
|
||||
Event: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES,
|
||||
})
|
||||
if c.clusterMessageHandler != nil {
|
||||
c.clusterMessageHandler(&model.ClusterMessage{
|
||||
Event: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (c *FakeClusterInterface) GetPluginStatuses() (model.PluginStatuses, *model.AppError) {
|
||||
|
||||
Reference in New Issue
Block a user