From 1d879ed0f4b2c1cf8d7fd9b595d043effb6bcf3e Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Thu, 11 Jan 2024 10:18:36 +0530 Subject: [PATCH] MM-55295: Improve DB performance of some (Take 2) (#25865) * Revert "Revert "MM-55295: Improve DB performance of some APIs (#25318)" (#25852)" This reverts commit 077221a9405f99fb263af4f1bf08614d0ca0a6d9. * Fix the issue ```release-note NONE ``` * lint fix ```release-note NONE ``` --- server/channels/app/authorization.go | 20 +++-- server/channels/app/channel.go | 15 ++++ server/channels/app/post.go | 38 +++++----- .../opentracinglayer/opentracinglayer.go | 24 +++++- .../channels/store/retrylayer/retrylayer.go | 25 ++++++- .../store/searchlayer/channel_layer.go | 2 +- .../channels/store/sqlstore/channel_store.go | 36 +++++---- server/channels/store/store.go | 3 +- .../channels/store/storetest/channel_store.go | 73 +++++++++++++++++++ .../store/storetest/mocks/ChannelStore.go | 28 ++++++- .../channels/store/timerlayer/timerlayer.go | 22 +++++- .../bleveengine/indexer/indexing_job.go | 2 +- 12 files changed, 232 insertions(+), 56 deletions(-) diff --git a/server/channels/app/authorization.go b/server/channels/app/authorization.go index 50af57201a..7fac445d56 100644 --- a/server/channels/app/authorization.go +++ b/server/channels/app/authorization.go @@ -83,7 +83,6 @@ func (a *App) SessionHasPermissionToChannel(c request.CTX, session model.Session } ids, err := a.Srv().Store().Channel().GetAllChannelMembersForUser(session.UserId, true, true) - var channelRoles []string if err == nil { if roles, ok := ids[channelID]; ok { @@ -260,17 +259,22 @@ func (a *App) HasPermissionToChannel(c request.CTX, askingUserId string, channel return false } - channelMember, err := a.GetChannelMember(c, channelID, askingUserId) + // We call GetAllChannelMembersForUser instead of just getting + // a single member from the DB, because it's cache backed + // and this is a very frequent call. + ids, err := a.Srv().Store().Channel().GetAllChannelMembersForUser(askingUserId, true, true) + var channelRoles []string if err == nil { - roles := channelMember.GetRoles() - if a.RolesGrantPermission(roles, permission.Id) { - return true + if roles, ok := ids[channelID]; ok { + channelRoles = strings.Fields(roles) + if a.RolesGrantPermission(channelRoles, permission.Id) { + return true + } } } - var channel *model.Channel - channel, err = a.GetChannel(c, channelID) - if err == nil { + channel, appErr := a.GetChannel(c, channelID) + if appErr == nil { return a.HasPermissionToTeam(c, askingUserId, channel.TeamId, permission) } diff --git a/server/channels/app/channel.go b/server/channels/app/channel.go index 3999ee02ea..d8680a3bd2 100644 --- a/server/channels/app/channel.go +++ b/server/channels/app/channel.go @@ -2063,6 +2063,21 @@ func (s *Server) getChannelMember(c request.CTX, channelID string, userID string return channelMember, nil } +func (s *Server) getChannelMemberLastViewedAt(c request.CTX, channelID string, userID string) (int64, *model.AppError) { + lastViewedAt, err := s.Store().Channel().GetMemberLastViewedAt(c.Context(), channelID, userID) + if err != nil { + var nfErr *store.ErrNotFound + switch { + case errors.As(err, &nfErr): + return 0, model.NewAppError("getChannelMemberLastViewedAt", MissingChannelMemberError, nil, "", http.StatusNotFound).Wrap(err) + default: + return 0, model.NewAppError("getChannelMemberLastViewedAt", "app.channel.get_member.app_error", nil, "", http.StatusInternalServerError).Wrap(err) + } + } + + return lastViewedAt, nil +} + func (a *App) GetChannelMembersPage(c request.CTX, channelID string, page, perPage int) (model.ChannelMembers, *model.AppError) { channelMembers, err := a.Srv().Store().Channel().GetMembers(channelID, page*perPage, perPage) if err != nil { diff --git a/server/channels/app/post.go b/server/channels/app/post.go index 277084198b..c7ad217669 100644 --- a/server/channels/app/post.go +++ b/server/channels/app/post.go @@ -810,9 +810,9 @@ func (a *App) publishWebsocketEventForPermalinkPost(c request.CTX, post *model.P return false, err } - channelMembers, err := a.GetChannelMembersPage(c, post.ChannelId, 0, 10000000) - if err != nil { - return false, err + userIDs, nErr := a.Srv().Store().Channel().GetAllChannelMemberIdsByChannelId(post.ChannelId) + if nErr != nil { + return false, model.NewAppError("publishWebsocketEventForPermalinkPost", "app.channel.get_members.app_error", nil, "", http.StatusInternalServerError).Wrap(err) } permalinkPreviewedChannel, err := a.GetChannel(c, previewedPost.ChannelId) @@ -827,19 +827,19 @@ func (a *App) publishWebsocketEventForPermalinkPost(c request.CTX, post *model.P originalEmbeds := post.Metadata.Embeds originalProps := post.GetProps() permalinkPreviewedPost := post.GetPreviewPost() - for _, cm := range channelMembers { + for _, userID := range userIDs { if permalinkPreviewedPost != nil { post.Metadata.Embeds = originalEmbeds post.SetProps(originalProps) } - postForUser := a.sanitizePostMetadataForUserAndChannel(c, post, permalinkPreviewedPost, permalinkPreviewedChannel, cm.UserId) + postForUser := a.sanitizePostMetadataForUserAndChannel(c, post, permalinkPreviewedPost, permalinkPreviewedChannel, userID) // Using DeepCopy here to avoid a race condition // between publishing the event and setting the "post" data value below. messageCopy := message.DeepCopy() broadcastCopy := messageCopy.GetBroadcast() - broadcastCopy.UserId = cm.UserId + broadcastCopy.UserId = userID messageCopy.SetBroadcast(broadcastCopy) postJSON, jsonErr := postForUser.ToJSON() @@ -1292,15 +1292,15 @@ func (a *App) AddCursorIdsForPostList(originalList *model.PostList, afterPost, b originalList.PrevPostId = prevPostId } func (a *App) GetPostsForChannelAroundLastUnread(c request.CTX, channelID, userID string, limitBefore, limitAfter int, skipFetchThreads bool, collapsedThreads, collapsedThreadsExtended bool) (*model.PostList, *model.AppError) { - var member *model.ChannelMember + var lastViewedAt int64 var err *model.AppError - if member, err = a.GetChannelMember(c, channelID, userID); err != nil { + if lastViewedAt, err = a.Srv().getChannelMemberLastViewedAt(c, channelID, userID); err != nil { return nil, err - } else if member.LastViewedAt == 0 { + } else if lastViewedAt == 0 { return model.NewPostList(), nil } - lastUnreadPostId, err := a.GetPostIdAfterTime(channelID, member.LastViewedAt, collapsedThreads) + lastUnreadPostId, err := a.GetPostIdAfterTime(channelID, lastViewedAt, collapsedThreads) if err != nil { return nil, err } else if lastUnreadPostId == "" { @@ -1870,9 +1870,9 @@ func (a *App) countThreadMentions(c request.CTX, user *model.User, post *model.P // countMentionsFromPost returns the number of posts in the post's channel that mention the user after and including the // given post. func (a *App) countMentionsFromPost(c request.CTX, user *model.User, post *model.Post) (int, int, int, *model.AppError) { - channel, err := a.GetChannel(c, post.ChannelId) - if err != nil { - return 0, 0, 0, err + channel, appErr := a.GetChannel(c, post.ChannelId) + if appErr != nil { + return 0, 0, 0, appErr } if channel.Type == model.ChannelTypeDirect || channel.Type == model.ChannelTypeGroup { @@ -1893,15 +1893,15 @@ func (a *App) countMentionsFromPost(c request.CTX, user *model.User, post *model return count, countRoot, urgentCount, nil } - channelMember, err := a.GetChannelMember(c, channel.Id, user.Id) + members, err := a.Srv().Store().Channel().GetAllChannelMembersNotifyPropsForChannel(channel.Id, true) if err != nil { - return 0, 0, 0, err + return 0, 0, 0, model.NewAppError("countMentionsFromPost", "app.channel.count_posts_since.app_error", nil, "", http.StatusInternalServerError).Wrap(err) } keywords := MentionKeywords{} keywords.AddUser( user, - channelMember.NotifyProps, + members[user.Id], &model.Status{Status: model.StatusOnline}, // Assume the user is online since they would've triggered this true, // Assume channel mentions are always allowed for simplicity ) @@ -1911,9 +1911,9 @@ func (a *App) countMentionsFromPost(c request.CTX, user *model.User, post *model // A mapping of thread root IDs to whether or not a post in that thread mentions the user mentionedByThread := make(map[string]bool) - thread, err := a.GetPostThread(post.Id, model.GetPostsOptions{}, user.Id) - if err != nil { - return 0, 0, 0, err + thread, appErr := a.GetPostThread(post.Id, model.GetPostsOptions{}, user.Id) + if appErr != nil { + return 0, 0, 0, appErr } count := 0 diff --git a/server/channels/store/opentracinglayer/opentracinglayer.go b/server/channels/store/opentracinglayer/opentracinglayer.go index 3ab03205cf..50d56dd9eb 100644 --- a/server/channels/store/opentracinglayer/opentracinglayer.go +++ b/server/channels/store/opentracinglayer/opentracinglayer.go @@ -965,16 +965,16 @@ func (s *OpenTracingLayerChannelStore) GetAll(teamID string) ([]*model.Channel, return result, err } -func (s *OpenTracingLayerChannelStore) GetAllChannelMembersById(id string) ([]string, error) { +func (s *OpenTracingLayerChannelStore) GetAllChannelMemberIdsByChannelId(id string) ([]string, error) { origCtx := s.Root.Store.Context() - span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetAllChannelMembersById") + span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetAllChannelMemberIdsByChannelId") s.Root.Store.SetContext(newCtx) defer func() { s.Root.Store.SetContext(origCtx) }() defer span.Finish() - result, err := s.ChannelStore.GetAllChannelMembersById(id) + result, err := s.ChannelStore.GetAllChannelMemberIdsByChannelId(id) if err != nil { span.LogFields(spanlog.Error(err)) ext.Error.Set(span, true) @@ -1572,6 +1572,24 @@ func (s *OpenTracingLayerChannelStore) GetMemberForPost(postID string, userID st return result, err } +func (s *OpenTracingLayerChannelStore) GetMemberLastViewedAt(ctx context.Context, channelID string, userID string) (int64, error) { + origCtx := s.Root.Store.Context() + span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetMemberLastViewedAt") + s.Root.Store.SetContext(newCtx) + defer func() { + s.Root.Store.SetContext(origCtx) + }() + + defer span.Finish() + result, err := s.ChannelStore.GetMemberLastViewedAt(ctx, channelID, userID) + if err != nil { + span.LogFields(spanlog.Error(err)) + ext.Error.Set(span, true) + } + + return result, err +} + func (s *OpenTracingLayerChannelStore) GetMembers(channelID string, offset int, limit int) (model.ChannelMembers, error) { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetMembers") diff --git a/server/channels/store/retrylayer/retrylayer.go b/server/channels/store/retrylayer/retrylayer.go index b6ecb74e39..08d6db7437 100644 --- a/server/channels/store/retrylayer/retrylayer.go +++ b/server/channels/store/retrylayer/retrylayer.go @@ -1049,11 +1049,11 @@ func (s *RetryLayerChannelStore) GetAll(teamID string) ([]*model.Channel, error) } -func (s *RetryLayerChannelStore) GetAllChannelMembersById(id string) ([]string, error) { +func (s *RetryLayerChannelStore) GetAllChannelMemberIdsByChannelId(id string) ([]string, error) { tries := 0 for { - result, err := s.ChannelStore.GetAllChannelMembersById(id) + result, err := s.ChannelStore.GetAllChannelMemberIdsByChannelId(id) if err == nil { return result, nil } @@ -1748,6 +1748,27 @@ func (s *RetryLayerChannelStore) GetMemberForPost(postID string, userID string, } +func (s *RetryLayerChannelStore) GetMemberLastViewedAt(ctx context.Context, channelID string, userID string) (int64, error) { + + tries := 0 + for { + result, err := s.ChannelStore.GetMemberLastViewedAt(ctx, channelID, userID) + if err == nil { + return result, nil + } + if !isRepeatableError(err) { + return result, err + } + tries++ + if tries >= 3 { + err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures") + return result, err + } + timepkg.Sleep(100 * timepkg.Millisecond) + } + +} + func (s *RetryLayerChannelStore) GetMembers(channelID string, offset int, limit int) (model.ChannelMembers, error) { tries := 0 diff --git a/server/channels/store/searchlayer/channel_layer.go b/server/channels/store/searchlayer/channel_layer.go index f3206decd3..ea3bebf67c 100644 --- a/server/channels/store/searchlayer/channel_layer.go +++ b/server/channels/store/searchlayer/channel_layer.go @@ -40,7 +40,7 @@ func (c *SearchChannelStore) indexChannel(rctx request.CTX, channel *model.Chann var userIDs, teamMemberIDs []string var err error if channel.Type == model.ChannelTypePrivate { - userIDs, err = c.GetAllChannelMembersById(channel.Id) + userIDs, err = c.GetAllChannelMemberIdsByChannelId(channel.Id) if err != nil { rctx.Logger().Warn("Encountered error while indexing channel", mlog.String("channel_id", channel.Id), mlog.Err(err)) return diff --git a/server/channels/store/sqlstore/channel_store.go b/server/channels/store/sqlstore/channel_store.go index bf2031732f..e841a8c7f3 100644 --- a/server/channels/store/sqlstore/channel_store.go +++ b/server/channels/store/sqlstore/channel_store.go @@ -1126,26 +1126,16 @@ func (s SqlChannelStore) GetChannelsByUser(userId string, includeDeleted bool, l return channels, nil } -func (s SqlChannelStore) GetAllChannelMembersById(channelID string) ([]string, error) { - sql, args, err := s.channelMembersForTeamWithSchemeSelectQuery.Where(sq.Eq{ - "ChannelId": channelID, - }).ToSql() - if err != nil { - return nil, errors.Wrap(err, "GetAllChannelMembersById_ToSql") - } - - dbMembers := channelMemberWithSchemeRolesList{} - err = s.GetReplicaX().Select(&dbMembers, sql, args...) +func (s SqlChannelStore) GetAllChannelMemberIdsByChannelId(channelID string) ([]string, error) { + userIDs := []string{} + err := s.GetReplicaX().Select(&userIDs, `SELECT UserId + FROM ChannelMembers + WHERE ChannelId=?`, channelID) if err != nil { return nil, errors.Wrapf(err, "failed to get ChannelMembers with channelID=%s", channelID) } - res := make([]string, len(dbMembers)) - for i, member := range dbMembers.ToModel() { - res[i] = member.UserId - } - - return res, nil + return userIDs, nil } func (s SqlChannelStore) GetAllChannels(offset, limit int, opts store.ChannelSearchOpts) (model.ChannelListWithTeamData, error) { @@ -2070,6 +2060,20 @@ func (s SqlChannelStore) GetMember(ctx context.Context, channelID string, userID return dbMember.ToModel(), nil } +func (s SqlChannelStore) GetMemberLastViewedAt(ctx context.Context, channelID string, userID string) (int64, error) { + var lastViewedAt int64 + if err := s.DBXFromContext(ctx).Get(&lastViewedAt, `SELECT COALESCE(LastViewedAt, 0) AS LastViewedAt + FROM ChannelMembers + WHERE ChannelId=? AND UserId=?`, channelID, userID); err != nil { + if err == sql.ErrNoRows { + return 0, store.NewErrNotFound("LastViewedAt", fmt.Sprintf("channelId=%s, userId=%s", channelID, userID)) + } + return 0, errors.Wrapf(err, "failed to get lastViewedAt with channelId=%s and userId=%s", channelID, userID) + } + + return lastViewedAt, nil +} + func (s SqlChannelStore) InvalidateAllChannelMembersForUser(userId string) { allChannelMembersForUserCache.Remove(userId) allChannelMembersForUserCache.Remove(userId + "_deleted") diff --git a/server/channels/store/store.go b/server/channels/store/store.go index 6ade13c6f6..db10eb7627 100644 --- a/server/channels/store/store.go +++ b/server/channels/store/store.go @@ -205,7 +205,7 @@ type ChannelStore interface { GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error) GetChannels(teamID, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, error) GetChannelsByUser(userID string, includeDeleted bool, lastDeleteAt, pageSize int, fromChannelID string) (model.ChannelList, error) - GetAllChannelMembersById(id string) ([]string, error) + GetAllChannelMemberIdsByChannelId(id string) ([]string, error) GetAllChannels(page, perPage int, opts ChannelSearchOpts) (model.ChannelListWithTeamData, error) GetAllChannelsCount(opts ChannelSearchOpts) (int64, error) GetMoreChannels(teamID string, userID string, offset int, limit int) (model.ChannelList, error) @@ -227,6 +227,7 @@ type ChannelStore interface { UpdateMemberNotifyProps(channelID, userID string, props map[string]string) (*model.ChannelMember, error) GetMembers(channelID string, offset, limit int) (model.ChannelMembers, error) GetMember(ctx context.Context, channelID string, userID string) (*model.ChannelMember, error) + GetMemberLastViewedAt(ctx context.Context, channelID string, userID string) (int64, error) GetChannelMembersTimezones(channelID string) ([]model.StringMap, error) GetAllChannelMembersForUser(userID string, allowFromCache bool, includeDeleted bool) (map[string]string, error) GetChannelsMemberCount(channelIDs []string) (map[string]int64, error) diff --git a/server/channels/store/storetest/channel_store.go b/server/channels/store/storetest/channel_store.go index d3f3adcff7..c174a3c8fc 100644 --- a/server/channels/store/storetest/channel_store.go +++ b/server/channels/store/storetest/channel_store.go @@ -110,6 +110,7 @@ func TestChannelStore(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore t.Run("IncrementMentionCount", func(t *testing.T) { testChannelStoreIncrementMentionCount(t, rctx, ss) }) t.Run("UpdateChannelMember", func(t *testing.T) { testUpdateChannelMember(t, rctx, ss) }) t.Run("GetMember", func(t *testing.T) { testGetMember(t, rctx, ss) }) + t.Run("GetMemberLastViewedAt", func(t *testing.T) { testGetMemberLastViewedAt(t, rctx, ss) }) t.Run("GetMemberForPost", func(t *testing.T) { testChannelStoreGetMemberForPost(t, rctx, ss) }) t.Run("GetMemberCount", func(t *testing.T) { testGetMemberCount(t, rctx, ss) }) t.Run("GetMemberCountsByGroup", func(t *testing.T) { testGetMemberCountsByGroup(t, rctx, ss) }) @@ -246,6 +247,10 @@ func testChannelStoreSaveDirectChannel(t *testing.T, rctx request.CTX, ss store. require.NoError(t, nErr) require.Len(t, members, 2, "should have saved 2 members") + userIDs, nErr := ss.Channel().GetAllChannelMemberIdsByChannelId(o1.Id) + require.NoError(t, nErr) + require.ElementsMatch(t, []string{u1.Id, u2.Id}, userIDs) + _, nErr = ss.Channel().SaveDirectChannel(rctx, &o1, &m1, &m2) require.Error(t, nErr, "shouldn't be a able to update from save") @@ -282,6 +287,10 @@ func testChannelStoreSaveDirectChannel(t *testing.T, rctx request.CTX, ss store. require.NoError(t, nErr) require.Len(t, members, 1, "should have saved just 1 member") + userIDs, nErr = ss.Channel().GetAllChannelMemberIdsByChannelId(o1.Id) + require.NoError(t, nErr) + require.ElementsMatch(t, []string{u1.Id}, userIDs) + // Manually truncate Channels table until testlib can handle cleanups s.GetMasterX().Exec("TRUNCATE Channels") } @@ -4892,6 +4901,62 @@ func testGetMember(t *testing.T, rctx request.CTX, ss store.Store) { ss.Channel().InvalidateCacheForChannelMembersNotifyProps(c2.Id) } +func testGetMemberLastViewedAt(t *testing.T, rctx request.CTX, ss store.Store) { + userId := model.NewId() + + c1 := &model.Channel{ + TeamId: model.NewId(), + DisplayName: model.NewId(), + Name: model.NewId(), + Type: model.ChannelTypeOpen, + } + _, nErr := ss.Channel().Save(c1, -1) + require.NoError(t, nErr) + + c2 := &model.Channel{ + TeamId: c1.TeamId, + DisplayName: model.NewId(), + Name: model.NewId(), + Type: model.ChannelTypeOpen, + } + _, nErr = ss.Channel().Save(c2, -1) + require.NoError(t, nErr) + + m1 := &model.ChannelMember{ + ChannelId: c1.Id, + UserId: userId, + NotifyProps: model.GetDefaultChannelNotifyProps(), + LastViewedAt: int64(100), + } + _, err := ss.Channel().SaveMember(m1) + require.NoError(t, err) + + m2 := &model.ChannelMember{ + ChannelId: c2.Id, + UserId: userId, + NotifyProps: model.GetDefaultChannelNotifyProps(), + LastViewedAt: int64(200), + } + _, err = ss.Channel().SaveMember(m2) + require.NoError(t, err) + + _, err = ss.Channel().GetMemberLastViewedAt(context.Background(), model.NewId(), userId) + require.Error(t, err, "should've failed to get member for non-existent channel") + + _, err = ss.Channel().GetMemberLastViewedAt(context.Background(), c1.Id, model.NewId()) + require.Error(t, err, "should've failed to get member for non-existent user") + + lvAt, err := ss.Channel().GetMemberLastViewedAt(context.Background(), c1.Id, userId) + require.NoError(t, err, "shouldn't have errored when getting member", err) + require.Equal(t, m1.LastViewedAt, lvAt, "should've gotten LastViewedAt of channel 1") + + lvAt, err = ss.Channel().GetMemberLastViewedAt(context.Background(), c2.Id, userId) + require.NoError(t, err, "shouldn't have errored when getting member", err) + require.Equal(t, m2.LastViewedAt, lvAt, "should've gotten gotten LastViewedAt of channel 2") + + ss.Channel().InvalidateCacheForChannelMembersNotifyProps(c2.Id) +} + func testChannelStoreGetMemberForPost(t *testing.T, rctx request.CTX, ss store.Store) { ch := &model.Channel{ TeamId: model.NewId(), @@ -7477,6 +7542,10 @@ func testChannelStoreRemoveAllDeactivatedMembers(t *testing.T, rctx request.CTX, assert.NoError(t, err) assert.Len(t, d1, 3) + userIDs, nErr := ss.Channel().GetAllChannelMemberIdsByChannelId(c1.Id) + require.NoError(t, nErr) + require.ElementsMatch(t, []string{u1.Id, u2.Id, u3.Id}, userIDs) + // Deactivate users 1 & 2. u1.DeleteAt = model.GetMillis() u2.DeleteAt = model.GetMillis() @@ -7494,6 +7563,10 @@ func testChannelStoreRemoveAllDeactivatedMembers(t *testing.T, rctx request.CTX, assert.Len(t, d2, 1) assert.Equal(t, u3.Id, d2[0].UserId) + userIDs, nErr = ss.Channel().GetAllChannelMemberIdsByChannelId(c1.Id) + require.NoError(t, nErr) + require.ElementsMatch(t, []string{u3.Id}, userIDs) + // Manually truncate Channels table until testlib can handle cleanups s.GetMasterX().Exec("TRUNCATE Channels") } diff --git a/server/channels/store/storetest/mocks/ChannelStore.go b/server/channels/store/storetest/mocks/ChannelStore.go index 3653582f39..5bfaddd439 100644 --- a/server/channels/store/storetest/mocks/ChannelStore.go +++ b/server/channels/store/storetest/mocks/ChannelStore.go @@ -432,8 +432,8 @@ func (_m *ChannelStore) GetAll(teamID string) ([]*model.Channel, error) { return r0, r1 } -// GetAllChannelMembersById provides a mock function with given fields: id -func (_m *ChannelStore) GetAllChannelMembersById(id string) ([]string, error) { +// GetAllChannelMemberIdsByChannelId provides a mock function with given fields: id +func (_m *ChannelStore) GetAllChannelMemberIdsByChannelId(id string) ([]string, error) { ret := _m.Called(id) var r0 []string @@ -1314,6 +1314,30 @@ func (_m *ChannelStore) GetMemberForPost(postID string, userID string, includeAr return r0, r1 } +// GetMemberLastViewedAt provides a mock function with given fields: ctx, channelID, userID +func (_m *ChannelStore) GetMemberLastViewedAt(ctx context.Context, channelID string, userID string) (int64, error) { + ret := _m.Called(ctx, channelID, userID) + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (int64, error)); ok { + return rf(ctx, channelID, userID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) int64); ok { + r0 = rf(ctx, channelID, userID) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, channelID, userID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetMembers provides a mock function with given fields: channelID, offset, limit func (_m *ChannelStore) GetMembers(channelID string, offset int, limit int) (model.ChannelMembers, error) { ret := _m.Called(channelID, offset, limit) diff --git a/server/channels/store/timerlayer/timerlayer.go b/server/channels/store/timerlayer/timerlayer.go index 5727c9094b..3663c12eaf 100644 --- a/server/channels/store/timerlayer/timerlayer.go +++ b/server/channels/store/timerlayer/timerlayer.go @@ -917,10 +917,10 @@ func (s *TimerLayerChannelStore) GetAll(teamID string) ([]*model.Channel, error) return result, err } -func (s *TimerLayerChannelStore) GetAllChannelMembersById(id string) ([]string, error) { +func (s *TimerLayerChannelStore) GetAllChannelMemberIdsByChannelId(id string) ([]string, error) { start := time.Now() - result, err := s.ChannelStore.GetAllChannelMembersById(id) + result, err := s.ChannelStore.GetAllChannelMemberIdsByChannelId(id) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil { @@ -928,7 +928,7 @@ func (s *TimerLayerChannelStore) GetAllChannelMembersById(id string) ([]string, if err == nil { success = "true" } - s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetAllChannelMembersById", success, elapsed) + s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetAllChannelMemberIdsByChannelId", success, elapsed) } return result, err } @@ -1461,6 +1461,22 @@ func (s *TimerLayerChannelStore) GetMemberForPost(postID string, userID string, return result, err } +func (s *TimerLayerChannelStore) GetMemberLastViewedAt(ctx context.Context, channelID string, userID string) (int64, error) { + start := time.Now() + + result, err := s.ChannelStore.GetMemberLastViewedAt(ctx, channelID, userID) + + elapsed := float64(time.Since(start)) / float64(time.Second) + if s.Root.Metrics != nil { + success := "false" + if err == nil { + success = "true" + } + s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetMemberLastViewedAt", success, elapsed) + } + return result, err +} + func (s *TimerLayerChannelStore) GetMembers(channelID string, offset int, limit int) (model.ChannelMembers, error) { start := time.Now() diff --git a/server/platform/services/searchengine/bleveengine/indexer/indexing_job.go b/server/platform/services/searchengine/bleveengine/indexer/indexing_job.go index 5d17133b1b..7f1091a7e9 100644 --- a/server/platform/services/searchengine/bleveengine/indexer/indexing_job.go +++ b/server/platform/services/searchengine/bleveengine/indexer/indexing_job.go @@ -526,7 +526,7 @@ func (worker *BleveIndexerWorker) BulkIndexChannels(logger mlog.LoggerIFace, cha var userIDs []string var err error if channel.Type == model.ChannelTypePrivate { - userIDs, err = worker.jobServer.Store.Channel().GetAllChannelMembersById(channel.Id) + userIDs, err = worker.jobServer.Store.Channel().GetAllChannelMemberIdsByChannelId(channel.Id) if err != nil { return nil, model.NewAppError("BleveIndexerWorker.BulkIndexChannels", "bleveengine.indexer.do_job.bulk_index_channels.batch_error", nil, "", http.StatusInternalServerError).Wrap(err) }