Adding caching to get channel member (#5544)

This commit is contained in:
Christopher Speller
2017-02-27 13:42:05 -05:00
committed by Joram Wilander
parent 3b8ed352d6
commit 75480bfdae
8 changed files with 76 additions and 20 deletions
+6 -2
View File
@@ -174,13 +174,15 @@ func UpdateUserToTeamAdmin(user *model.User, team *model.Team) {
func MakeUserChannelAdmin(user *model.User, channel *model.Channel) {
utils.DisableDebugLogForTest()
if cmr := <-Srv.Store.Channel().GetMember(channel.Id, user.Id); cmr.Err == nil {
if cmr := <-Srv.Store.Channel().GetMember(channel.Id, user.Id, true); cmr.Err == nil {
cm := cmr.Data.(model.ChannelMember)
cm.Roles = "channel_admin channel_user"
if sr := <-Srv.Store.Channel().UpdateMember(&cm); sr.Err != nil {
utils.EnableDebugLogForTest()
panic(sr.Err)
}
InvalidateCacheForChannelMember(cm.ChannelId, cm.UserId)
} else {
utils.EnableDebugLogForTest()
panic(cmr.Err)
@@ -192,13 +194,15 @@ func MakeUserChannelAdmin(user *model.User, channel *model.Channel) {
func MakeUserChannelUser(user *model.User, channel *model.Channel) {
utils.DisableDebugLogForTest()
if cmr := <-Srv.Store.Channel().GetMember(channel.Id, user.Id); cmr.Err == nil {
if cmr := <-Srv.Store.Channel().GetMember(channel.Id, user.Id, true); cmr.Err == nil {
cm := cmr.Data.(model.ChannelMember)
cm.Roles = "channel_user"
if sr := <-Srv.Store.Channel().UpdateMember(&cm); sr.Err != nil {
utils.EnableDebugLogForTest()
panic(sr.Err)
}
InvalidateCacheForChannelMember(cm.ChannelId, cm.UserId)
} else {
utils.EnableDebugLogForTest()
panic(cmr.Err)
+13 -11
View File
@@ -189,7 +189,7 @@ func WaitForChannelMembership(channelId string, userId string) {
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 result.Err == nil {
@@ -245,7 +245,7 @@ func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) {
}
sc := Srv.Store.Channel().Get(channel.Id, true)
cmc := Srv.Store.Channel().GetMember(channel.Id, c.Session.UserId)
cmc := Srv.Store.Channel().GetMember(channel.Id, c.Session.UserId, true)
if cresult := <-sc; cresult.Err != nil {
c.Err = cresult.Err
@@ -322,7 +322,7 @@ func updateChannelHeader(c *Context, w http.ResponseWriter, r *http.Request) {
}
sc := Srv.Store.Channel().Get(channelId, true)
cmc := Srv.Store.Channel().GetMember(channelId, c.Session.UserId)
cmc := Srv.Store.Channel().GetMember(channelId, c.Session.UserId, true)
if cresult := <-sc; cresult.Err != nil {
c.Err = cresult.Err
@@ -431,7 +431,7 @@ func updateChannelPurpose(c *Context, w http.ResponseWriter, r *http.Request) {
}
sc := Srv.Store.Channel().Get(channelId, true)
cmc := Srv.Store.Channel().GetMember(channelId, c.Session.UserId)
cmc := Srv.Store.Channel().GetMember(channelId, c.Session.UserId, true)
if cresult := <-sc; cresult.Err != nil {
c.Err = cresult.Err
@@ -588,7 +588,7 @@ func joinChannel(c *Context, channelChannel store.StoreChannel, userChannel stor
channel := cresult.Data.(*model.Channel)
user := uresult.Data.(*model.User)
if mresult := <-Srv.Store.Channel().GetMember(channel.Id, user.Id); mresult.Err == nil && mresult.Data != nil {
if mresult := <-Srv.Store.Channel().GetMember(channel.Id, user.Id, true); mresult.Err == nil && mresult.Data != nil {
// the user is already in the channel so just return successful
return nil, channel
}
@@ -631,7 +631,7 @@ func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelM
}
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 {
return nil, result.Err
@@ -665,6 +665,7 @@ func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelM
WaitForChannelMembership(channel.Id, user.Id)
InvalidateCacheForUser(user.Id)
InvalidateCacheForChannelMember(channel.Id, user.Id)
InvalidateCacheForChannelMembers(channel.Id)
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_USER_ADDED, "", channel.Id, "", nil)
@@ -801,7 +802,7 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
id := params["channel_id"]
sc := Srv.Store.Channel().Get(id, true)
scm := Srv.Store.Channel().GetMember(id, c.Session.UserId)
scm := Srv.Store.Channel().GetMember(id, c.Session.UserId, true)
cmc := Srv.Store.Channel().GetMemberCount(id, false)
uc := Srv.Store.User().Get(c.Session.UserId)
ihc := Srv.Store.Webhook().GetIncomingByChannel(id)
@@ -905,7 +906,7 @@ func getChannel(c *Context, w http.ResponseWriter, r *http.Request) {
id := params["channel_id"]
cchan := Srv.Store.Channel().Get(id, true)
cmchan := Srv.Store.Channel().GetMember(id, c.Session.UserId)
cmchan := Srv.Store.Channel().GetMember(id, c.Session.UserId, true)
if cresult := <-cchan; cresult.Err != nil {
c.Err = cresult.Err
@@ -1023,7 +1024,7 @@ func getChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if result := <-Srv.Store.Channel().GetMember(channelId, userId); result.Err != nil {
if result := <-Srv.Store.Channel().GetMember(channelId, userId, true); result.Err != nil {
c.Err = result.Err
return
} else {
@@ -1110,7 +1111,7 @@ func removeMember(c *Context, w http.ResponseWriter, r *http.Request) {
}
sc := Srv.Store.Channel().Get(channelId, true)
cmc := Srv.Store.Channel().GetMember(channelId, c.Session.UserId)
cmc := Srv.Store.Channel().GetMember(channelId, c.Session.UserId, true)
ouc := Srv.Store.User().Get(userIdToRemove)
if oresult := <-ouc; oresult.Err != nil {
@@ -1202,7 +1203,7 @@ func updateNotifyProps(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
result := <-Srv.Store.Channel().GetMember(channelId, userId)
result := <-Srv.Store.Channel().GetMember(channelId, userId, true)
if result.Err != nil {
c.Err = result.Err
return
@@ -1224,6 +1225,7 @@ func updateNotifyProps(c *Context, w http.ResponseWriter, r *http.Request) {
return
} else {
InvalidateCacheForUser(userId)
InvalidateCacheForChannelMember(channelId, userId)
// return the updated notify properties including any unchanged ones
w.Write([]byte(model.MapToJson(member.NotifyProps)))
+1
View File
@@ -191,6 +191,7 @@ func LeaveTeam(team *model.Team, user *model.User) *model.AppError {
for _, channel := range *channelList {
if channel.Type != model.CHANNEL_DIRECT {
InvalidateCacheForChannelMembers(channel.Id)
InvalidateCacheForChannelMember(channel.Id, user.Id)
if result := <-Srv.Store.Channel().RemoveMember(channel.Id, user.Id); result.Err != nil {
return result.Err
}
+12
View File
@@ -158,6 +158,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) {
Srv.Store.Channel().InvalidateAllChannelMembersForUser(userId)
Srv.Store.User().InvalidateProfilesInChannelCacheByUser(userId)
+1
View File
@@ -19,6 +19,7 @@ type ClusterInterface interface {
InvalidateCacheForChannelByName(teamId, name string)
InvalidateCacheForChannelPosts(channelId string)
InvalidateCacheForWebhook(webhookId string)
InvalidateCacheForChannelMember(channelId string, userId string)
Publish(event *model.WebSocketEvent)
UpdateStatus(status *model.Status)
GetLogs() ([]string, *model.AppError)
+36 -1
View File
@@ -24,6 +24,12 @@ const (
ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE = model.SESSION_CACHE_SIZE
ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SEC = 900 // 15 mins
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
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_SEC = 1800 // 30 mins
@@ -38,12 +44,14 @@ var channelMemberCountsCache = utils.NewLru(CHANNEL_MEMBERS_COUNTS_CACHE_SIZE)
var allChannelMembersForUserCache = utils.NewLru(ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE)
var channelCache = utils.NewLru(model.CHANNEL_CACHE_SIZE)
var channelByNameCache = utils.NewLru(model.CHANNEL_CACHE_SIZE)
var channelMemberCache = utils.NewLru(CHANNEL_MEMBER_CACHE_SIZE)
func ClearChannelCaches() {
channelMemberCountsCache.Purge()
allChannelMembersForUserCache.Purge()
channelCache.Purge()
channelByNameCache.Purge()
channelMemberCache.Purge()
}
func NewSqlChannelStore(sqlStore *SqlStore) ChannelStore {
@@ -710,11 +718,36 @@ func (s SqlChannelStore) GetMembers(channelId string) 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)
go func() {
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
@@ -726,6 +759,8 @@ func (s SqlChannelStore) GetMember(channelId string, userId string) StoreChannel
}
} else {
result.Data = member
channelMemberCache.AddWithExpiresInSecs(channelId+userId, &member, CHANNEL_MEMBER_CACHE_SEC)
}
storeChannel <- result
+5 -5
View File
@@ -458,7 +458,7 @@ func TestChannelMemberStore(t *testing.T) {
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 {
t.Fatal("should have go member")
}
@@ -920,15 +920,15 @@ func TestGetMember(t *testing.T) {
}
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")
}
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")
}
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)
} else if member := result.Data.(model.ChannelMember); member.ChannelId != c1.Id {
t.Fatal("should've gotten member of channel 1")
@@ -936,7 +936,7 @@ func TestGetMember(t *testing.T) {
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)
} else if member := result.Data.(model.ChannelMember); member.ChannelId != c2.Id {
t.Fatal("should've gotten member of channel 2")
+2 -1
View File
@@ -103,7 +103,8 @@ type ChannelStore interface {
SaveMember(member *model.ChannelMember) StoreChannel
UpdateMember(member *model.ChannelMember) StoreChannel
GetMembers(channelId string) 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
InvalidateAllChannelMembersForUser(userId string)
IsUserInChannelUseCache(userId string, channelId string) bool