Adding caching to get channel member (#5518)

Этот коммит содержится в:
Christopher Speller
2017-02-24 09:15:36 -05:00
коммит произвёл Corey Hulen
родитель 7fc5dc236a
Коммит ba028ed74b
8 изменённых файлов: 67 добавлений и 13 удалений

Просмотреть файл

@@ -194,13 +194,15 @@ func UpdateUserToNonTeamAdmin(user *model.User, team *model.Team) {
func MakeUserChannelAdmin(user *model.User, channel *model.Channel) { func MakeUserChannelAdmin(user *model.User, channel *model.Channel) {
utils.DisableDebugLogForTest() utils.DisableDebugLogForTest()
if cmr := <-app.Srv.Store.Channel().GetMember(channel.Id, user.Id); cmr.Err == nil { if cmr := <-app.Srv.Store.Channel().GetMember(channel.Id, user.Id, true); cmr.Err == nil {
cm := cmr.Data.(*model.ChannelMember) cm := cmr.Data.(*model.ChannelMember)
cm.Roles = "channel_admin channel_user" cm.Roles = "channel_admin channel_user"
if sr := <-app.Srv.Store.Channel().UpdateMember(cm); sr.Err != nil { if sr := <-app.Srv.Store.Channel().UpdateMember(cm); sr.Err != nil {
utils.EnableDebugLogForTest() utils.EnableDebugLogForTest()
panic(sr.Err) panic(sr.Err)
} }
app.InvalidateCacheForChannelMember(cm.ChannelId, cm.UserId)
} else { } else {
utils.EnableDebugLogForTest() utils.EnableDebugLogForTest()
panic(cmr.Err) panic(cmr.Err)
@@ -212,13 +214,15 @@ func MakeUserChannelAdmin(user *model.User, channel *model.Channel) {
func MakeUserChannelUser(user *model.User, channel *model.Channel) { func MakeUserChannelUser(user *model.User, channel *model.Channel) {
utils.DisableDebugLogForTest() utils.DisableDebugLogForTest()
if cmr := <-app.Srv.Store.Channel().GetMember(channel.Id, user.Id); cmr.Err == nil { if cmr := <-app.Srv.Store.Channel().GetMember(channel.Id, user.Id, true); cmr.Err == nil {
cm := cmr.Data.(*model.ChannelMember) cm := cmr.Data.(*model.ChannelMember)
cm.Roles = "channel_user" cm.Roles = "channel_user"
if sr := <-app.Srv.Store.Channel().UpdateMember(cm); sr.Err != nil { if sr := <-app.Srv.Store.Channel().UpdateMember(cm); sr.Err != nil {
utils.EnableDebugLogForTest() utils.EnableDebugLogForTest()
panic(sr.Err) panic(sr.Err)
} }
app.InvalidateCacheForChannelMember(cm.ChannelId, cm.UserId)
} else { } else {
utils.EnableDebugLogForTest() utils.EnableDebugLogForTest()
panic(cmr.Err) panic(cmr.Err)

Просмотреть файл

@@ -175,7 +175,7 @@ func WaitForChannelMembership(channelId string, userId string) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
result := <-Srv.Store.Channel().GetMember(channelId, userId) result := <-Srv.Store.Channel().GetMember(channelId, userId, true)
// If the membership was found then return // If the membership was found then return
if result.Err == nil { if result.Err == nil {
@@ -214,6 +214,7 @@ func UpdateChannelMemberRoles(channelId string, userId string, newRoles string)
return nil, result.Err return nil, result.Err
} }
InvalidateCacheForChannelMember(channelId, userId)
InvalidateCacheForUser(userId) InvalidateCacheForUser(userId)
return member, nil return member, nil
} }
@@ -245,6 +246,7 @@ func UpdateChannelMemberNotifyProps(data map[string]string, channelId string, us
if result := <-Srv.Store.Channel().UpdateMember(member); result.Err != nil { if result := <-Srv.Store.Channel().UpdateMember(member); result.Err != nil {
return nil, result.Err return nil, result.Err
} else { } else {
InvalidateCacheForChannelMember(channelId, userId)
InvalidateCacheForUser(userId) InvalidateCacheForUser(userId)
InvalidateCacheForChannelMembersNotifyProps(channelId) InvalidateCacheForChannelMembersNotifyProps(channelId)
return member, nil return member, nil
@@ -333,7 +335,7 @@ func addUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelM
} }
tmchan := Srv.Store.Team().GetMember(channel.TeamId, user.Id) tmchan := Srv.Store.Team().GetMember(channel.TeamId, user.Id)
cmchan := Srv.Store.Channel().GetMember(channel.Id, user.Id) cmchan := Srv.Store.Channel().GetMember(channel.Id, user.Id, true)
if result := <-tmchan; result.Err != nil { if result := <-tmchan; result.Err != nil {
return nil, result.Err return nil, result.Err
@@ -588,7 +590,7 @@ func GetChannelsUserNotIn(teamId string, userId string, offset int, limit int) (
} }
func GetChannelMember(channelId string, userId string) (*model.ChannelMember, *model.AppError) { func GetChannelMember(channelId string, userId string) (*model.ChannelMember, *model.AppError) {
if result := <-Srv.Store.Channel().GetMember(channelId, userId); result.Err != nil { if result := <-Srv.Store.Channel().GetMember(channelId, userId, true); result.Err != nil {
return nil, result.Err return nil, result.Err
} else { } else {
return result.Data.(*model.ChannelMember), nil return result.Data.(*model.ChannelMember), nil
@@ -637,7 +639,7 @@ func GetChannelCounts(teamId string, userId string) (*model.ChannelCounts, *mode
func JoinChannel(channel *model.Channel, userId string) *model.AppError { func JoinChannel(channel *model.Channel, userId string) *model.AppError {
userChan := Srv.Store.User().Get(userId) userChan := Srv.Store.User().Get(userId)
memberChan := Srv.Store.Channel().GetMember(channel.Id, userId) memberChan := Srv.Store.Channel().GetMember(channel.Id, userId, true)
if uresult := <-userChan; uresult.Err != nil { if uresult := <-userChan; uresult.Err != nil {
return uresult.Err return uresult.Err
@@ -790,6 +792,7 @@ func removeUserFromChannel(userIdToRemove string, removerUserId string, channel
} }
InvalidateCacheForUser(userIdToRemove) InvalidateCacheForUser(userIdToRemove)
InvalidateCacheForChannelMember(channel.Id, userIdToRemove)
InvalidateCacheForChannelMembers(channel.Id) InvalidateCacheForChannelMembers(channel.Id)
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_USER_REMOVED, "", channel.Id, "", nil) message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_USER_REMOVED, "", channel.Id, "", nil)

Просмотреть файл

@@ -424,6 +424,7 @@ func LeaveTeam(team *model.Team, user *model.User) *model.AppError {
for _, channel := range *channelList { for _, channel := range *channelList {
if channel.Type != model.CHANNEL_DIRECT { if channel.Type != model.CHANNEL_DIRECT {
InvalidateCacheForChannelMembers(channel.Id) InvalidateCacheForChannelMembers(channel.Id)
InvalidateCacheForChannelMember(channel.Id, user.Id)
if result := <-Srv.Store.Channel().RemoveMember(channel.Id, user.Id); result.Err != nil { if result := <-Srv.Store.Channel().RemoveMember(channel.Id, user.Id); result.Err != nil {
return result.Err return result.Err
} }

Просмотреть файл

@@ -170,6 +170,18 @@ func InvalidateCacheForUser(userId string) {
} }
} }
func InvalidateCacheForChannelMember(channelId string, userId string) {
InvalidateCacheForChannelMemberSkipClusterSend(channelId, userId)
if einterfaces.GetClusterInterface() != nil {
einterfaces.GetClusterInterface().InvalidateCacheForChannelMember(channelId, userId)
}
}
func InvalidateCacheForChannelMemberSkipClusterSend(channelId string, userId string) {
Srv.Store.Channel().InvalidateMember(channelId, userId)
}
func InvalidateCacheForUserSkipClusterSend(userId string) { func InvalidateCacheForUserSkipClusterSend(userId string) {
Srv.Store.Channel().InvalidateAllChannelMembersForUser(userId) Srv.Store.Channel().InvalidateAllChannelMembersForUser(userId)
Srv.Store.User().InvalidateProfilesInChannelCacheByUser(userId) Srv.Store.User().InvalidateProfilesInChannelCacheByUser(userId)

Просмотреть файл

@@ -20,6 +20,7 @@ type ClusterInterface interface {
InvalidateCacheForChannelMembersNotifyProps(channelId string) InvalidateCacheForChannelMembersNotifyProps(channelId string)
InvalidateCacheForChannelPosts(channelId string) InvalidateCacheForChannelPosts(channelId string)
InvalidateCacheForWebhook(webhookId string) InvalidateCacheForWebhook(webhookId string)
InvalidateCacheForChannelMember(channelId string, userId string)
Publish(event *model.WebSocketEvent) Publish(event *model.WebSocketEvent)
UpdateStatus(status *model.Status) UpdateStatus(status *model.Status)
GetLogs() ([]string, *model.AppError) GetLogs() ([]string, *model.AppError)

Просмотреть файл

@@ -28,6 +28,9 @@ const (
ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE = model.SESSION_CACHE_SIZE ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE = model.SESSION_CACHE_SIZE
ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC = 1800 // 30 mins ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC = 1800 // 30 mins
CHANNEL_MEMBER_CACHE_SIZE = model.SESSION_CACHE_SIZE
CHANNEL_MEMBER_CACHE_SEC = 900 // 15 mins
CHANNEL_MEMBERS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE CHANNEL_MEMBERS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
CHANNEL_MEMBERS_COUNTS_CACHE_SEC = 1800 // 30 mins CHANNEL_MEMBERS_COUNTS_CACHE_SEC = 1800 // 30 mins
@@ -43,6 +46,7 @@ var allChannelMembersForUserCache = utils.NewLru(ALL_CHANNEL_MEMBERS_FOR_USER_CA
var allChannelMembersNotifyPropsForChannelCache = utils.NewLru(ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE) var allChannelMembersNotifyPropsForChannelCache = utils.NewLru(ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE)
var channelCache = utils.NewLru(model.CHANNEL_CACHE_SIZE) var channelCache = utils.NewLru(model.CHANNEL_CACHE_SIZE)
var channelByNameCache = utils.NewLru(model.CHANNEL_CACHE_SIZE) var channelByNameCache = utils.NewLru(model.CHANNEL_CACHE_SIZE)
var channelMemberCache = utils.NewLru(CHANNEL_MEMBER_CACHE_SIZE)
func ClearChannelCaches() { func ClearChannelCaches() {
channelMemberCountsCache.Purge() channelMemberCountsCache.Purge()
@@ -50,6 +54,7 @@ func ClearChannelCaches() {
allChannelMembersNotifyPropsForChannelCache.Purge() allChannelMembersNotifyPropsForChannelCache.Purge()
channelCache.Purge() channelCache.Purge()
channelByNameCache.Purge() channelByNameCache.Purge()
channelMemberCache.Purge()
} }
func NewSqlChannelStore(sqlStore *SqlStore) ChannelStore { func NewSqlChannelStore(sqlStore *SqlStore) ChannelStore {
@@ -776,11 +781,36 @@ func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) StoreCh
return storeChannel return storeChannel
} }
func (s SqlChannelStore) GetMember(channelId string, userId string) StoreChannel { func (s SqlChannelStore) InvalidateMember(channelId string, userId string) {
channelMemberCache.Remove(channelId + userId)
}
func (s SqlChannelStore) GetMember(channelId string, userId string, allowFromCache bool) StoreChannel {
storeChannel := make(StoreChannel, 1) storeChannel := make(StoreChannel, 1)
go func() { go func() {
result := StoreResult{} result := StoreResult{}
metrics := einterfaces.GetMetricsInterface()
if allowFromCache {
if cacheItem, ok := channelMemberCache.Get(channelId + userId); ok {
if metrics != nil {
metrics.IncrementMemCacheHitCounter("Channel Member")
}
result.Data = cacheItem.(*model.ChannelMember)
storeChannel <- result
close(storeChannel)
return
} else {
if metrics != nil {
metrics.IncrementMemCacheMissCounter("Channel Member")
}
}
} else {
if metrics != nil {
metrics.IncrementMemCacheMissCounter("Channel Member")
}
}
var member model.ChannelMember var member model.ChannelMember
@@ -792,6 +822,8 @@ func (s SqlChannelStore) GetMember(channelId string, userId string) StoreChannel
} }
} else { } else {
result.Data = &member result.Data = &member
channelMemberCache.AddWithExpiresInSecs(channelId+userId, &member, CHANNEL_MEMBER_CACHE_SEC)
} }
storeChannel <- result storeChannel <- result

Просмотреть файл

@@ -497,7 +497,7 @@ func TestChannelMemberStore(t *testing.T) {
t.Fatal("Member update time incorrect on delete") t.Fatal("Member update time incorrect on delete")
} }
member := (<-store.Channel().GetMember(o1.ChannelId, o1.UserId)).Data.(*model.ChannelMember) member := (<-store.Channel().GetMember(o1.ChannelId, o1.UserId, false)).Data.(*model.ChannelMember)
if member.ChannelId != o1.ChannelId { if member.ChannelId != o1.ChannelId {
t.Fatal("should have go member") t.Fatal("should have go member")
} }
@@ -968,15 +968,15 @@ func TestGetMember(t *testing.T) {
} }
Must(store.Channel().SaveMember(m2)) Must(store.Channel().SaveMember(m2))
if result := <-store.Channel().GetMember(model.NewId(), userId); result.Err == nil { if result := <-store.Channel().GetMember(model.NewId(), userId, false); result.Err == nil {
t.Fatal("should've failed to get member for non-existant channel") t.Fatal("should've failed to get member for non-existant channel")
} }
if result := <-store.Channel().GetMember(c1.Id, model.NewId()); result.Err == nil { if result := <-store.Channel().GetMember(c1.Id, model.NewId(), false); result.Err == nil {
t.Fatal("should've failed to get member for non-existant user") t.Fatal("should've failed to get member for non-existant user")
} }
if result := <-store.Channel().GetMember(c1.Id, userId); result.Err != nil { if result := <-store.Channel().GetMember(c1.Id, userId, false); result.Err != nil {
t.Fatal("shouldn't have errored when getting member", result.Err) t.Fatal("shouldn't have errored when getting member", result.Err)
} else if member := result.Data.(*model.ChannelMember); member.ChannelId != c1.Id { } else if member := result.Data.(*model.ChannelMember); member.ChannelId != c1.Id {
t.Fatal("should've gotten member of channel 1") t.Fatal("should've gotten member of channel 1")
@@ -984,7 +984,7 @@ func TestGetMember(t *testing.T) {
t.Fatal("should've gotten member for user") t.Fatal("should've gotten member for user")
} }
if result := <-store.Channel().GetMember(c2.Id, userId); result.Err != nil { if result := <-store.Channel().GetMember(c2.Id, userId, false); result.Err != nil {
t.Fatal("shouldn't have errored when getting member", result.Err) t.Fatal("shouldn't have errored when getting member", result.Err)
} else if member := result.Data.(*model.ChannelMember); member.ChannelId != c2.Id { } else if member := result.Data.(*model.ChannelMember); member.ChannelId != c2.Id {
t.Fatal("should've gotten member of channel 2") t.Fatal("should've gotten member of channel 2")

Просмотреть файл

@@ -106,7 +106,8 @@ type ChannelStore interface {
SaveMember(member *model.ChannelMember) StoreChannel SaveMember(member *model.ChannelMember) StoreChannel
UpdateMember(member *model.ChannelMember) StoreChannel UpdateMember(member *model.ChannelMember) StoreChannel
GetMembers(channelId string, offset, limit int) StoreChannel GetMembers(channelId string, offset, limit int) StoreChannel
GetMember(channelId string, userId string) StoreChannel GetMember(channelId string, userId string, allowFromCache bool) StoreChannel
InvalidateMember(channelId string, userId string)
GetAllChannelMembersForUser(userId string, allowFromCache bool) StoreChannel GetAllChannelMembersForUser(userId string, allowFromCache bool) StoreChannel
InvalidateAllChannelMembersForUser(userId string) InvalidateAllChannelMembersForUser(userId string)
IsUserInChannelUseCache(userId string, channelId string) bool IsUserInChannelUseCache(userId string, channelId string) bool