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:
Jesús Espino
2019-09-12 18:52:45 +02:00
committed by GitHub
parent e58aeb90a8
commit 28cc7e7e36
18 changed files with 410 additions and 510 deletions

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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...)
}

View File

@@ -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...)
}

View File

@@ -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()

View File

@@ -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()

View File

@@ -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)
})
}

View 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()
}

View 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)
})
}

View 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()
}

View 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)
})
}

View File

@@ -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)
}

View File

@@ -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...)
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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))

View File

@@ -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) {