* Add webhook cache

* Add channel by name cache

* Fxing profiles in channels cache

* Fix merge
Этот коммит содержится в:
Joram Wilander
2017-01-27 14:07:34 -05:00
коммит произвёл GitHub
родитель 8eab04e944
Коммит 097289f8e4
19 изменённых файлов: 173 добавлений и 51 удалений

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

@@ -34,7 +34,7 @@ func (me *JoinProvider) GetCommand(c *Context) *model.Command {
} }
func (me *JoinProvider) DoCommand(c *Context, args *model.CommandArgs, message string) *model.CommandResponse { func (me *JoinProvider) DoCommand(c *Context, args *model.CommandArgs, message string) *model.CommandResponse {
if result := <-app.Srv.Store.Channel().GetByName(c.TeamId, message); result.Err != nil { if result := <-app.Srv.Store.Channel().GetByName(c.TeamId, message, true); result.Err != nil {
return &model.CommandResponse{Text: c.T("api.command_join.list.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} return &model.CommandResponse{Text: c.T("api.command_join.list.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
} else { } else {
channel := result.Data.(*model.Channel) channel := result.Data.(*model.Channel)

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

@@ -64,7 +64,7 @@ func (me *msgProvider) DoCommand(c *Context, args *model.CommandArgs, message st
channelName := model.GetDMNameFromIds(c.Session.UserId, userProfile.Id) channelName := model.GetDMNameFromIds(c.Session.UserId, userProfile.Id)
targetChannelId := "" targetChannelId := ""
if channel := <-app.Srv.Store.Channel().GetByName(c.TeamId, channelName); channel.Err != nil { if channel := <-app.Srv.Store.Channel().GetByName(c.TeamId, channelName, true); channel.Err != nil {
if channel.Err.Id == "store.sql_channel.get_by_name.missing.app_error" { if channel.Err.Id == "store.sql_channel.get_by_name.missing.app_error" {
if directChannel, err := app.CreateDirectChannel(c.Session.UserId, userProfile.Id); err != nil { if directChannel, err := app.CreateDirectChannel(c.Session.UserId, userProfile.Id); err != nil {
c.Err = err c.Err = err

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

@@ -109,7 +109,7 @@ func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
if result := <-app.Srv.Store.Webhook().GetIncoming(id); result.Err != nil { if result := <-app.Srv.Store.Webhook().GetIncoming(id, true); result.Err != nil {
c.Err = result.Err c.Err = result.Err
return return
} else { } else {
@@ -125,6 +125,8 @@ func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
app.InvalidateCacheForWebhook(id)
c.LogAudit("success") c.LogAudit("success")
w.Write([]byte(model.MapToJson(props))) w.Write([]byte(model.MapToJson(props)))
} }
@@ -352,7 +354,7 @@ func incomingWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r) params := mux.Vars(r)
id := params["id"] id := params["id"]
hchan := app.Srv.Store.Webhook().GetIncoming(id) hchan := app.Srv.Store.Webhook().GetIncoming(id, true)
r.ParseForm() r.ParseForm()
@@ -448,7 +450,7 @@ func incomingWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
channelName = channelName[1:] channelName = channelName[1:]
} }
cchan = app.Srv.Store.Channel().GetByName(hook.TeamId, channelName) cchan = app.Srv.Store.Channel().GetByName(hook.TeamId, channelName, true)
} else { } else {
cchan = app.Srv.Store.Channel().Get(hook.ChannelId, true) cchan = app.Srv.Store.Channel().Get(hook.ChannelId, true)
} }

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

@@ -89,6 +89,7 @@ func InvalidateAllCachesSkipSend() {
store.ClearChannelCaches() store.ClearChannelCaches()
store.ClearUserCaches() store.ClearUserCaches()
store.ClearPostCaches() store.ClearPostCaches()
store.ClearWebhookCaches()
} }
func GetConfig() *model.Config { func GetConfig() *model.Config {

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

@@ -88,7 +88,7 @@ func CreateDefaultChannels(teamId string) ([]*model.Channel, *model.AppError) {
func JoinDefaultChannels(teamId string, user *model.User, channelRole string) *model.AppError { func JoinDefaultChannels(teamId string, user *model.User, channelRole string) *model.AppError {
var err *model.AppError = nil var err *model.AppError = nil
if result := <-Srv.Store.Channel().GetByName(teamId, "town-square"); result.Err != nil { if result := <-Srv.Store.Channel().GetByName(teamId, "town-square", true); result.Err != nil {
err = result.Err err = result.Err
} else { } else {
cm := &model.ChannelMember{ChannelId: result.Data.(*model.Channel).Id, UserId: user.Id, cm := &model.ChannelMember{ChannelId: result.Data.(*model.Channel).Id, UserId: user.Id,
@@ -105,14 +105,14 @@ func JoinDefaultChannels(teamId string, user *model.User, channelRole string) *m
UserId: user.Id, UserId: user.Id,
} }
InvalidateCacheForChannel(result.Data.(*model.Channel).Id) InvalidateCacheForChannelMembers(result.Data.(*model.Channel).Id)
if _, err := CreatePost(post, teamId, false); err != nil { if _, err := CreatePost(post, teamId, false); err != nil {
l4g.Error(utils.T("api.channel.post_user_add_remove_message_and_forget.error"), err) l4g.Error(utils.T("api.channel.post_user_add_remove_message_and_forget.error"), err)
} }
} }
if result := <-Srv.Store.Channel().GetByName(teamId, "off-topic"); result.Err != nil { if result := <-Srv.Store.Channel().GetByName(teamId, "off-topic", true); result.Err != nil {
err = result.Err err = result.Err
} else { } else {
cm := &model.ChannelMember{ChannelId: result.Data.(*model.Channel).Id, UserId: user.Id, cm := &model.ChannelMember{ChannelId: result.Data.(*model.Channel).Id, UserId: user.Id,
@@ -129,7 +129,7 @@ func JoinDefaultChannels(teamId string, user *model.User, channelRole string) *m
UserId: user.Id, UserId: user.Id,
} }
InvalidateCacheForChannel(result.Data.(*model.Channel).Id) InvalidateCacheForChannelMembers(result.Data.(*model.Channel).Id)
if _, err := CreatePost(post, teamId, false); err != nil { if _, err := CreatePost(post, teamId, false); err != nil {
l4g.Error(utils.T("api.channel.post_user_add_remove_message_and_forget.error"), err) l4g.Error(utils.T("api.channel.post_user_add_remove_message_and_forget.error"), err)
@@ -195,7 +195,7 @@ func UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError) {
if result := <-Srv.Store.Channel().Update(channel); result.Err != nil { if result := <-Srv.Store.Channel().Update(channel); result.Err != nil {
return nil, result.Err return nil, result.Err
} else { } else {
InvalidateCacheForChannel(channel.Id) InvalidateCacheForChannel(channel)
return channel, nil return channel, nil
} }
} }
@@ -287,6 +287,7 @@ func DeleteChannel(channel *model.Channel, userId string) *model.AppError {
if result := <-Srv.Store.Webhook().DeleteIncoming(hook.Id, now); result.Err != nil { if result := <-Srv.Store.Webhook().DeleteIncoming(hook.Id, now); result.Err != nil {
l4g.Error(utils.T("api.channel.delete_channel.incoming_webhook.error"), hook.Id) l4g.Error(utils.T("api.channel.delete_channel.incoming_webhook.error"), hook.Id)
} }
InvalidateCacheForWebhook(hook.Id)
} }
for _, hook := range outgoingHooks { for _, hook := range outgoingHooks {
@@ -298,7 +299,7 @@ func DeleteChannel(channel *model.Channel, userId string) *model.AppError {
if dresult := <-Srv.Store.Channel().Delete(channel.Id, model.GetMillis()); dresult.Err != nil { if dresult := <-Srv.Store.Channel().Delete(channel.Id, model.GetMillis()); dresult.Err != nil {
return dresult.Err return dresult.Err
} }
InvalidateCacheForChannel(channel.Id) InvalidateCacheForChannel(channel)
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_DELETED, channel.TeamId, "", "", nil) message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_DELETED, channel.TeamId, "", "", nil)
message.Add("channel_id", channel.Id) message.Add("channel_id", channel.Id)
@@ -351,7 +352,7 @@ func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelM
} }
InvalidateCacheForUser(user.Id) InvalidateCacheForUser(user.Id)
InvalidateCacheForChannel(channel.Id) InvalidateCacheForChannelMembers(channel.Id)
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_USER_ADDED, "", channel.Id, "", nil) message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_USER_ADDED, "", channel.Id, "", nil)
message.Add("user_id", user.Id) message.Add("user_id", user.Id)
@@ -508,7 +509,7 @@ func GetChannel(channelId string) (*model.Channel, *model.AppError) {
} }
func GetChannelByName(channelName, teamId string) (*model.Channel, *model.AppError) { func GetChannelByName(channelName, teamId string) (*model.Channel, *model.AppError) {
if result := <-Srv.Store.Channel().GetByName(teamId, channelName); result.Err != nil { if result := <-Srv.Store.Channel().GetByName(teamId, channelName, true); result.Err != nil {
return nil, result.Err return nil, result.Err
} else { } else {
return result.Data.(*model.Channel), nil return result.Data.(*model.Channel), nil
@@ -650,7 +651,7 @@ func RemoveUserFromChannel(userIdToRemove string, removerUserId string, channel
} }
InvalidateCacheForUser(userIdToRemove) InvalidateCacheForUser(userIdToRemove)
InvalidateCacheForChannel(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)
message.Add("user_id", userIdToRemove) message.Add("user_id", userIdToRemove)

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

@@ -182,7 +182,7 @@ func ImportChannel(data *ChannelImportData, dryRun bool) *model.AppError {
} }
var channel *model.Channel var channel *model.Channel
if result := <-Srv.Store.Channel().GetByNameIncludeDeleted(team.Id, *data.Name); result.Err == nil { if result := <-Srv.Store.Channel().GetByNameIncludeDeleted(team.Id, *data.Name, true); result.Err == nil {
channel = result.Data.(*model.Channel) channel = result.Data.(*model.Channel)
} else { } else {
channel = &model.Channel{} channel = &model.Channel{}

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

@@ -35,12 +35,6 @@ func SendNotifications(post *model.Post, team *model.Team, channel *model.Channe
profileMap = result.Data.(map[string]*model.User) profileMap = result.Data.(map[string]*model.User)
} }
// If the user who made the post isn't in the channel, don't send a notification
if _, ok := profileMap[post.UserId]; !ok && post.Props["from_webhook"] != "true" {
l4g.Debug(utils.T("api.post.send_notifications.user_id.debug"), post.Id, channel.Id, post.UserId)
return []string{}, nil
}
mentionedUserIds := make(map[string]bool) mentionedUserIds := make(map[string]bool)
allActivityPushUserIds := []string{} allActivityPushUserIds := []string{}
hereNotification := false hereNotification := false

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

@@ -110,9 +110,6 @@ func CreatePost(post *model.Post, teamId string, triggerWebhooks bool) (*model.P
} }
} }
InvalidateCacheForChannel(rpost.ChannelId)
InvalidateCacheForChannelPosts(rpost.ChannelId)
if err := handlePostEvents(rpost, teamId, triggerWebhooks); err != nil { if err := handlePostEvents(rpost, teamId, triggerWebhooks); err != nil {
return nil, err return nil, err
} }
@@ -139,6 +136,9 @@ func handlePostEvents(post *model.Post, teamId string, triggerWebhooks bool) *mo
channel = result.Data.(*model.Channel) channel = result.Data.(*model.Channel)
} }
InvalidateCacheForChannel(channel)
InvalidateCacheForChannelPosts(channel.Id)
var user *model.User var user *model.User
if result := <-uchan; result.Err != nil { if result := <-uchan; result.Err != nil {
return result.Err return result.Err

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

@@ -472,7 +472,7 @@ func SlackAddChannels(teamId string, slackchannels []SlackChannel, posts map[str
newChannel = SlackSanitiseChannelProperties(newChannel) newChannel = SlackSanitiseChannelProperties(newChannel)
var mChannel *model.Channel var mChannel *model.Channel
if result := <-Srv.Store.Channel().GetByName(teamId, sChannel.Name); result.Err == nil { if result := <-Srv.Store.Channel().GetByName(teamId, sChannel.Name, true); result.Err == nil {
// The channel already exists as an active channel. Merge with the existing one. // The channel already exists as an active channel. Merge with the existing one.
mChannel = result.Data.(*model.Channel) mChannel = result.Data.(*model.Channel)
log.WriteString(utils.T("api.slackimport.slack_add_channels.merge", map[string]interface{}{"DisplayName": newChannel.DisplayName})) log.WriteString(utils.T("api.slackimport.slack_add_channels.merge", map[string]interface{}{"DisplayName": newChannel.DisplayName}))

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

@@ -408,7 +408,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 {
InvalidateCacheForChannel(channel.Id) InvalidateCacheForChannelMembers(channel.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
} }

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

@@ -103,18 +103,35 @@ func PublishSkipClusterSend(message *model.WebSocketEvent) {
} }
} }
func InvalidateCacheForChannel(channelId string) { func InvalidateCacheForChannel(channel *model.Channel) {
InvalidateCacheForChannelSkipClusterSend(channelId) InvalidateCacheForChannelSkipClusterSend(channel.Id)
InvalidateCacheForChannelByNameSkipClusterSend(channel.TeamId, channel.Name)
if cluster := einterfaces.GetClusterInterface(); cluster != nil { if cluster := einterfaces.GetClusterInterface(); cluster != nil {
cluster.InvalidateCacheForChannel(channelId) cluster.InvalidateCacheForChannel(channel.Id)
cluster.InvalidateCacheForChannelByName(channel.TeamId, channel.Name)
}
}
func InvalidateCacheForChannelMembers(channelId string) {
InvalidateCacheForChannelMembersSkipClusterSend(channelId)
if cluster := einterfaces.GetClusterInterface(); cluster != nil {
cluster.InvalidateCacheForChannelMembers(channelId)
} }
} }
func InvalidateCacheForChannelSkipClusterSend(channelId string) { func InvalidateCacheForChannelSkipClusterSend(channelId string) {
Srv.Store.Channel().InvalidateChannel(channelId)
}
func InvalidateCacheForChannelMembersSkipClusterSend(channelId string) {
Srv.Store.User().InvalidateProfilesInChannelCache(channelId) Srv.Store.User().InvalidateProfilesInChannelCache(channelId)
Srv.Store.Channel().InvalidateMemberCount(channelId) Srv.Store.Channel().InvalidateMemberCount(channelId)
Srv.Store.Channel().InvalidateChannel(channelId) }
func InvalidateCacheForChannelByNameSkipClusterSend(teamId, name string) {
Srv.Store.Channel().InvalidateChannelByName(teamId, name)
} }
func InvalidateCacheForChannelPosts(channelId string) { func InvalidateCacheForChannelPosts(channelId string) {
@@ -147,6 +164,18 @@ func InvalidateCacheForUserSkipClusterSend(userId string) {
} }
} }
func InvalidateCacheForWebhook(webhookId string) {
InvalidateCacheForWebhookSkipClusterSend(webhookId)
if cluster := einterfaces.GetClusterInterface(); cluster != nil {
cluster.InvalidateCacheForWebhook(webhookId)
}
}
func InvalidateCacheForWebhookSkipClusterSend(webhookId string) {
Srv.Store.Webhook().InvalidateWebhookCache(webhookId)
}
func InvalidateWebConnSessionCacheForUser(userId string) { func InvalidateWebConnSessionCacheForUser(userId string) {
if len(hubs) != 0 { if len(hubs) != 0 {
GetHubForUserId(userId).InvalidateUser(userId) GetHubForUserId(userId).InvalidateUser(userId)

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

@@ -42,7 +42,7 @@ func getChannelFromChannelArg(channelArg string) *model.Channel {
return nil return nil
} }
if result := <-app.Srv.Store.Channel().GetByNameIncludeDeleted(team.Id, channelPart); result.Err == nil { if result := <-app.Srv.Store.Channel().GetByNameIncludeDeleted(team.Id, channelPart, true); result.Err == nil {
channel = result.Data.(*model.Channel) channel = result.Data.(*model.Channel)
} else { } else {
fmt.Println(result.Err.Error()) fmt.Println(result.Err.Error())

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

@@ -478,7 +478,7 @@ func cmdJoinChannel() {
} }
var channel *model.Channel var channel *model.Channel
if result := <-app.Srv.Store.Channel().GetByName(team.Id, flagChannelName); result.Err != nil { if result := <-app.Srv.Store.Channel().GetByName(team.Id, flagChannelName, true); result.Err != nil {
l4g.Error("%v", result.Err) l4g.Error("%v", result.Err)
flushLogAndExit(1) flushLogAndExit(1)
} else { } else {
@@ -539,7 +539,7 @@ func cmdLeaveChannel() {
} }
var channel *model.Channel var channel *model.Channel
if result := <-app.Srv.Store.Channel().GetByName(team.Id, flagChannelName); result.Err != nil { if result := <-app.Srv.Store.Channel().GetByName(team.Id, flagChannelName, true); result.Err != nil {
l4g.Error("%v", result.Err) l4g.Error("%v", result.Err)
flushLogAndExit(1) flushLogAndExit(1)
} else { } else {

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

@@ -15,7 +15,10 @@ type ClusterInterface interface {
ClearSessionCacheForUser(userId string) ClearSessionCacheForUser(userId string)
InvalidateCacheForUser(userId string) InvalidateCacheForUser(userId string)
InvalidateCacheForChannel(channelId string) InvalidateCacheForChannel(channelId string)
InvalidateCacheForChannelByName(teamId, name string)
InvalidateCacheForChannelMembers(channelId string)
InvalidateCacheForChannelPosts(channelId string) InvalidateCacheForChannelPosts(channelId string)
InvalidateCacheForWebhook(webhookId 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)

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

@@ -38,11 +38,13 @@ type SqlChannelStore struct {
var channelMemberCountsCache = utils.NewLru(CHANNEL_MEMBERS_COUNTS_CACHE_SIZE) var channelMemberCountsCache = utils.NewLru(CHANNEL_MEMBERS_COUNTS_CACHE_SIZE)
var allChannelMembersForUserCache = utils.NewLru(ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE) var allChannelMembersForUserCache = utils.NewLru(ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE)
var channelCache = utils.NewLru(CHANNEL_CACHE_SIZE) var channelCache = utils.NewLru(CHANNEL_CACHE_SIZE)
var channelByNameCache = utils.NewLru(CHANNEL_CACHE_SIZE)
func ClearChannelCaches() { func ClearChannelCaches() {
channelMemberCountsCache.Purge() channelMemberCountsCache.Purge()
allChannelMembersForUserCache.Purge() allChannelMembersForUserCache.Purge()
channelCache.Purge() channelCache.Purge()
channelByNameCache.Purge()
} }
func NewSqlChannelStore(sqlStore *SqlStore) ChannelStore { func NewSqlChannelStore(sqlStore *SqlStore) ChannelStore {
@@ -306,6 +308,10 @@ func (us SqlChannelStore) InvalidateChannel(id string) {
channelCache.Remove(id) channelCache.Remove(id)
} }
func (us SqlChannelStore) InvalidateChannelByName(teamId, name string) {
channelCache.Remove(teamId + name)
}
func (s SqlChannelStore) Get(id string, allowFromCache bool) StoreChannel { func (s SqlChannelStore) Get(id string, allowFromCache bool) StoreChannel {
return s.get(id, false, allowFromCache) return s.get(id, false, allowFromCache)
} }
@@ -539,15 +545,15 @@ func (s SqlChannelStore) GetTeamChannels(teamId string) StoreChannel {
return storeChannel return storeChannel
} }
func (s SqlChannelStore) GetByName(teamId string, name string) StoreChannel { func (s SqlChannelStore) GetByName(teamId string, name string, allowFromCache bool) StoreChannel {
return s.getByName(teamId, name, false) return s.getByName(teamId, name, false, allowFromCache)
} }
func (s SqlChannelStore) GetByNameIncludeDeleted(teamId string, name string) StoreChannel { func (s SqlChannelStore) GetByNameIncludeDeleted(teamId string, name string, allowFromCache bool) StoreChannel {
return s.getByName(teamId, name, true) return s.getByName(teamId, name, true, allowFromCache)
} }
func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bool) StoreChannel { func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bool, allowFromCache bool) StoreChannel {
storeChannel := make(StoreChannel, 1) storeChannel := make(StoreChannel, 1)
var query string var query string
@@ -562,6 +568,23 @@ func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bo
channel := model.Channel{} channel := model.Channel{}
if allowFromCache {
metrics := einterfaces.GetMetricsInterface()
if cacheItem, ok := channelByNameCache.Get(teamId + name); ok {
if metrics != nil {
metrics.IncrementMemCacheHitCounter("Channel By Name")
}
result.Data = cacheItem.(*model.Channel)
storeChannel <- result
close(storeChannel)
return
} else {
if metrics != nil {
metrics.IncrementMemCacheMissCounter("Channel By Name")
}
}
}
if err := s.GetReplica().SelectOne(&channel, query, map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil { if err := s.GetReplica().SelectOne(&channel, query, map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
result.Err = model.NewLocAppError("SqlChannelStore.GetByName", MISSING_CHANNEL_ERROR, nil, "teamId="+teamId+", "+"name="+name+", "+err.Error()) result.Err = model.NewLocAppError("SqlChannelStore.GetByName", MISSING_CHANNEL_ERROR, nil, "teamId="+teamId+", "+"name="+name+", "+err.Error())
@@ -570,6 +593,7 @@ func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bo
} }
} else { } else {
result.Data = &channel result.Data = &channel
channelByNameCache.AddWithExpiresInSecs(teamId+name, &channel, CHANNEL_CACHE_SEC)
} }
storeChannel <- result storeChannel <- result

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

@@ -352,7 +352,7 @@ func TestChannelStoreGetByName(t *testing.T) {
o1.Type = model.CHANNEL_OPEN o1.Type = model.CHANNEL_OPEN
Must(store.Channel().Save(&o1)) Must(store.Channel().Save(&o1))
r1 := <-store.Channel().GetByName(o1.TeamId, o1.Name) r1 := <-store.Channel().GetByName(o1.TeamId, o1.Name, true)
if r1.Err != nil { if r1.Err != nil {
t.Fatal(r1.Err) t.Fatal(r1.Err)
} else { } else {
@@ -361,13 +361,25 @@ func TestChannelStoreGetByName(t *testing.T) {
} }
} }
if err := (<-store.Channel().GetByName(o1.TeamId, "")).Err; err == nil { if err := (<-store.Channel().GetByName(o1.TeamId, "", true)).Err; err == nil {
t.Fatal("Missing id should have failed")
}
if r1 := <-store.Channel().GetByName(o1.TeamId, o1.Name, false); r1.Err != nil {
t.Fatal(r1.Err)
} else {
if r1.Data.(*model.Channel).ToJson() != o1.ToJson() {
t.Fatal("invalid returned channel")
}
}
if err := (<-store.Channel().GetByName(o1.TeamId, "", false)).Err; err == nil {
t.Fatal("Missing id should have failed") t.Fatal("Missing id should have failed")
} }
Must(store.Channel().Delete(r1.Data.(*model.Channel).Id, model.GetMillis())) Must(store.Channel().Delete(r1.Data.(*model.Channel).Id, model.GetMillis()))
if err := (<-store.Channel().GetByName(o1.TeamId, "")).Err; err == nil { if err := (<-store.Channel().GetByName(o1.TeamId, "", false)).Err; err == nil {
t.Fatal("Deleted channel should not be returned by GetByName()") t.Fatal("Deleted channel should not be returned by GetByName()")
} }
} }

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

@@ -4,13 +4,26 @@
package store package store
import ( import (
"github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/model" "github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
) )
type SqlWebhookStore struct { type SqlWebhookStore struct {
*SqlStore *SqlStore
} }
const (
WEBHOOK_CACHE_SIZE = 25000
WEBHOOK_CACHE_SEC = 900 // 15 minutes
)
var webhookCache = utils.NewLru(WEBHOOK_CACHE_SIZE)
func ClearWebhookCaches() {
webhookCache.Purge()
}
func NewSqlWebhookStore(sqlStore *SqlStore) WebhookStore { func NewSqlWebhookStore(sqlStore *SqlStore) WebhookStore {
s := &SqlWebhookStore{sqlStore} s := &SqlWebhookStore{sqlStore}
@@ -54,6 +67,10 @@ func (s SqlWebhookStore) CreateIndexesIfNotExists() {
s.CreateIndexIfNotExists("idx_outgoing_webhook_delete_at", "OutgoingWebhooks", "DeleteAt") s.CreateIndexIfNotExists("idx_outgoing_webhook_delete_at", "OutgoingWebhooks", "DeleteAt")
} }
func (s SqlWebhookStore) InvalidateWebhookCache(webhookId string) {
webhookCache.Remove(webhookId)
}
func (s SqlWebhookStore) SaveIncoming(webhook *model.IncomingWebhook) StoreChannel { func (s SqlWebhookStore) SaveIncoming(webhook *model.IncomingWebhook) StoreChannel {
storeChannel := make(StoreChannel, 1) storeChannel := make(StoreChannel, 1)
@@ -88,18 +105,39 @@ func (s SqlWebhookStore) SaveIncoming(webhook *model.IncomingWebhook) StoreChann
return storeChannel return storeChannel
} }
func (s SqlWebhookStore) GetIncoming(id string) StoreChannel { func (s SqlWebhookStore) GetIncoming(id string, allowFromCache bool) StoreChannel {
storeChannel := make(StoreChannel, 1) storeChannel := make(StoreChannel, 1)
go func() { go func() {
result := StoreResult{} result := StoreResult{}
if allowFromCache {
metrics := einterfaces.GetMetricsInterface()
if cacheItem, ok := webhookCache.Get(id); ok {
if metrics != nil {
metrics.IncrementMemCacheHitCounter("Webhook")
}
result.Data = cacheItem.(*model.IncomingWebhook)
storeChannel <- result
close(storeChannel)
return
} else {
if metrics != nil {
metrics.IncrementMemCacheMissCounter("Webhook")
}
}
}
var webhook model.IncomingWebhook var webhook model.IncomingWebhook
if err := s.GetReplica().SelectOne(&webhook, "SELECT * FROM IncomingWebhooks WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id}); err != nil { if err := s.GetReplica().SelectOne(&webhook, "SELECT * FROM IncomingWebhooks WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id}); err != nil {
result.Err = model.NewLocAppError("SqlWebhookStore.GetIncoming", "store.sql_webhooks.get_incoming.app_error", nil, "id="+id+", err="+err.Error()) result.Err = model.NewLocAppError("SqlWebhookStore.GetIncoming", "store.sql_webhooks.get_incoming.app_error", nil, "id="+id+", err="+err.Error())
} }
if result.Err == nil {
webhookCache.AddWithExpiresInSecs(id, &webhook, WEBHOOK_CACHE_SEC)
}
result.Data = &webhook result.Data = &webhook
storeChannel <- result storeChannel <- result

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

@@ -35,7 +35,7 @@ func TestWebhookStoreGetIncoming(t *testing.T) {
o1 = (<-store.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook) o1 = (<-store.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
if r1 := <-store.Webhook().GetIncoming(o1.Id); r1.Err != nil { if r1 := <-store.Webhook().GetIncoming(o1.Id, false); r1.Err != nil {
t.Fatal(r1.Err) t.Fatal(r1.Err)
} else { } else {
if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt { if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt {
@@ -43,7 +43,19 @@ func TestWebhookStoreGetIncoming(t *testing.T) {
} }
} }
if err := (<-store.Webhook().GetIncoming("123")).Err; err == nil { if r1 := <-store.Webhook().GetIncoming(o1.Id, true); r1.Err != nil {
t.Fatal(r1.Err)
} else {
if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt {
t.Fatal("invalid returned webhook")
}
}
if err := (<-store.Webhook().GetIncoming("123", false)).Err; err == nil {
t.Fatal("Missing id should have failed")
}
if err := (<-store.Webhook().GetIncoming("123", true)).Err; err == nil {
t.Fatal("Missing id should have failed") t.Fatal("Missing id should have failed")
} }
} }
@@ -85,7 +97,7 @@ func TestWebhookStoreDeleteIncoming(t *testing.T) {
o1 = (<-store.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook) o1 = (<-store.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
if r1 := <-store.Webhook().GetIncoming(o1.Id); r1.Err != nil { if r1 := <-store.Webhook().GetIncoming(o1.Id, true); r1.Err != nil {
t.Fatal(r1.Err) t.Fatal(r1.Err)
} else { } else {
if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt { if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt {
@@ -97,7 +109,9 @@ func TestWebhookStoreDeleteIncoming(t *testing.T) {
t.Fatal(r2.Err) t.Fatal(r2.Err)
} }
if r3 := (<-store.Webhook().GetIncoming(o1.Id)); r3.Err == nil { ClearWebhookCaches()
if r3 := (<-store.Webhook().GetIncoming(o1.Id, true)); r3.Err == nil {
t.Log(r3.Data) t.Log(r3.Data)
t.Fatal("Missing id should have failed") t.Fatal("Missing id should have failed")
} }
@@ -113,7 +127,7 @@ func TestWebhookStoreDeleteIncomingByUser(t *testing.T) {
o1 = (<-store.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook) o1 = (<-store.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
if r1 := <-store.Webhook().GetIncoming(o1.Id); r1.Err != nil { if r1 := <-store.Webhook().GetIncoming(o1.Id, true); r1.Err != nil {
t.Fatal(r1.Err) t.Fatal(r1.Err)
} else { } else {
if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt { if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt {
@@ -125,7 +139,9 @@ func TestWebhookStoreDeleteIncomingByUser(t *testing.T) {
t.Fatal(r2.Err) t.Fatal(r2.Err)
} }
if r3 := (<-store.Webhook().GetIncoming(o1.Id)); r3.Err == nil { ClearWebhookCaches()
if r3 := (<-store.Webhook().GetIncoming(o1.Id, true)); r3.Err == nil {
t.Log(r3.Data) t.Log(r3.Data)
t.Fatal("Missing id should have failed") t.Fatal("Missing id should have failed")
} }

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

@@ -87,12 +87,13 @@ type ChannelStore interface {
Update(channel *model.Channel) StoreChannel Update(channel *model.Channel) StoreChannel
Get(id string, allowFromCache bool) StoreChannel Get(id string, allowFromCache bool) StoreChannel
InvalidateChannel(id string) InvalidateChannel(id string)
InvalidateChannelByName(teamId, name string)
GetFromMaster(id string) StoreChannel GetFromMaster(id string) StoreChannel
Delete(channelId string, time int64) StoreChannel Delete(channelId string, time int64) StoreChannel
SetDeleteAt(channelId string, deleteAt int64, updateAt int64) StoreChannel SetDeleteAt(channelId string, deleteAt int64, updateAt int64) StoreChannel
PermanentDeleteByTeam(teamId string) StoreChannel PermanentDeleteByTeam(teamId string) StoreChannel
GetByName(team_id string, name string) StoreChannel GetByName(team_id string, name string, allowFromCache bool) StoreChannel
GetByNameIncludeDeleted(team_id string, name string) StoreChannel GetByNameIncludeDeleted(team_id string, name string, allowFromCache bool) StoreChannel
GetDeletedByName(team_id string, name string) StoreChannel GetDeletedByName(team_id string, name string) StoreChannel
GetChannels(teamId string, userId string) StoreChannel GetChannels(teamId string, userId string) StoreChannel
GetMoreChannels(teamId string, userId string, offset int, limit int) StoreChannel GetMoreChannels(teamId string, userId string, offset int, limit int) StoreChannel
@@ -245,7 +246,7 @@ type SystemStore interface {
type WebhookStore interface { type WebhookStore interface {
SaveIncoming(webhook *model.IncomingWebhook) StoreChannel SaveIncoming(webhook *model.IncomingWebhook) StoreChannel
GetIncoming(id string) StoreChannel GetIncoming(id string, allowFromCache bool) StoreChannel
GetIncomingByTeam(teamId string) StoreChannel GetIncomingByTeam(teamId string) StoreChannel
GetIncomingByChannel(channelId string) StoreChannel GetIncomingByChannel(channelId string) StoreChannel
DeleteIncoming(webhookId string, time int64) StoreChannel DeleteIncoming(webhookId string, time int64) StoreChannel
@@ -259,6 +260,7 @@ type WebhookStore interface {
UpdateOutgoing(hook *model.OutgoingWebhook) StoreChannel UpdateOutgoing(hook *model.OutgoingWebhook) StoreChannel
AnalyticsIncomingCount(teamId string) StoreChannel AnalyticsIncomingCount(teamId string) StoreChannel
AnalyticsOutgoingCount(teamId string) StoreChannel AnalyticsOutgoingCount(teamId string) StoreChannel
InvalidateWebhookCache(webhook string)
} }
type CommandStore interface { type CommandStore interface {