PLT-4982 Adding caching to user profiles (#4782)
Этот коммит содержится в:
@@ -2735,7 +2735,7 @@ func getProfilesByIds(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if result := <-Srv.Store.User().GetProfileByIds(userIds); result.Err != nil {
|
if result := <-Srv.Store.User().GetProfileByIds(userIds, true); result.Err != nil {
|
||||||
c.Err = result.Err
|
c.Err = result.Err
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ func InvalidateCacheForUser(userId string) {
|
|||||||
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)
|
||||||
|
Srv.Store.User().InvalidatProfileCacheForUser(userId)
|
||||||
|
|
||||||
if len(hubs) != 0 {
|
if len(hubs) != 0 {
|
||||||
GetHubForUserId(userId).InvalidateUser(userId)
|
GetHubForUserId(userId).InvalidateUser(userId)
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ const (
|
|||||||
MISSING_AUTH_ACCOUNT_ERROR = "store.sql_user.get_by_auth.missing_account.app_error"
|
MISSING_AUTH_ACCOUNT_ERROR = "store.sql_user.get_by_auth.missing_account.app_error"
|
||||||
PROFILES_IN_CHANNEL_CACHE_SIZE = 5000
|
PROFILES_IN_CHANNEL_CACHE_SIZE = 5000
|
||||||
PROFILES_IN_CHANNEL_CACHE_SEC = 900 // 15 mins
|
PROFILES_IN_CHANNEL_CACHE_SEC = 900 // 15 mins
|
||||||
|
PROFILE_BY_IDS_CACHE_SIZE = 20000
|
||||||
|
PROFILE_BY_IDS_CACHE_SEC = 900 // 15 mins
|
||||||
USER_SEARCH_OPTION_NAMES_ONLY = "names_only"
|
USER_SEARCH_OPTION_NAMES_ONLY = "names_only"
|
||||||
USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME = "names_only_no_full_name"
|
USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME = "names_only_no_full_name"
|
||||||
USER_SEARCH_OPTION_ALL_NO_FULL_NAME = "all_no_full_name"
|
USER_SEARCH_OPTION_ALL_NO_FULL_NAME = "all_no_full_name"
|
||||||
@@ -34,9 +36,15 @@ type SqlUserStore struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var profilesInChannelCache *utils.Cache = utils.NewLru(PROFILES_IN_CHANNEL_CACHE_SIZE)
|
var profilesInChannelCache *utils.Cache = utils.NewLru(PROFILES_IN_CHANNEL_CACHE_SIZE)
|
||||||
|
var profileByIdsCache *utils.Cache = utils.NewLru(PROFILE_BY_IDS_CACHE_SIZE)
|
||||||
|
|
||||||
func ClearUserCaches() {
|
func ClearUserCaches() {
|
||||||
profilesInChannelCache.Purge()
|
profilesInChannelCache.Purge()
|
||||||
|
profileByIdsCache.Purge()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (us SqlUserStore) InvalidatProfileCacheForUser(userId string) {
|
||||||
|
profileByIdsCache.Remove(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSqlUserStore(sqlStore *SqlStore) UserStore {
|
func NewSqlUserStore(sqlStore *SqlStore) UserStore {
|
||||||
@@ -776,7 +784,7 @@ func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string) StoreChannel
|
|||||||
return storeChannel
|
return storeChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us SqlUserStore) GetProfileByIds(userIds []string) StoreChannel {
|
func (us SqlUserStore) GetProfileByIds(userIds []string, allowFromCache bool) StoreChannel {
|
||||||
|
|
||||||
storeChannel := make(StoreChannel, 1)
|
storeChannel := make(StoreChannel, 1)
|
||||||
|
|
||||||
@@ -784,10 +792,33 @@ func (us SqlUserStore) GetProfileByIds(userIds []string) StoreChannel {
|
|||||||
result := StoreResult{}
|
result := StoreResult{}
|
||||||
|
|
||||||
var users []*model.User
|
var users []*model.User
|
||||||
|
userMap := make(map[string]*model.User)
|
||||||
props := make(map[string]interface{})
|
props := make(map[string]interface{})
|
||||||
idQuery := ""
|
idQuery := ""
|
||||||
|
remainingUserIds := make([]string, 0)
|
||||||
|
|
||||||
for index, userId := range userIds {
|
if allowFromCache {
|
||||||
|
for _, userId := range userIds {
|
||||||
|
if cacheItem, ok := profileByIdsCache.Get(userId); ok {
|
||||||
|
u := cacheItem.(*model.User)
|
||||||
|
userMap[u.Id] = u
|
||||||
|
} else {
|
||||||
|
remainingUserIds = append(remainingUserIds, userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remainingUserIds = userIds
|
||||||
|
}
|
||||||
|
|
||||||
|
// If everything came from the cache then just return
|
||||||
|
if len(remainingUserIds) == 0 {
|
||||||
|
result.Data = userMap
|
||||||
|
storeChannel <- result
|
||||||
|
close(storeChannel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for index, userId := range remainingUserIds {
|
||||||
if len(idQuery) > 0 {
|
if len(idQuery) > 0 {
|
||||||
idQuery += ", "
|
idQuery += ", "
|
||||||
}
|
}
|
||||||
@@ -800,13 +831,12 @@ func (us SqlUserStore) GetProfileByIds(userIds []string) StoreChannel {
|
|||||||
result.Err = model.NewLocAppError("SqlUserStore.GetProfileByIds", "store.sql_user.get_profiles.app_error", nil, err.Error())
|
result.Err = model.NewLocAppError("SqlUserStore.GetProfileByIds", "store.sql_user.get_profiles.app_error", nil, err.Error())
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
userMap := make(map[string]*model.User)
|
|
||||||
|
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
u.Password = ""
|
u.Password = ""
|
||||||
u.AuthData = new(string)
|
u.AuthData = new(string)
|
||||||
*u.AuthData = ""
|
*u.AuthData = ""
|
||||||
userMap[u.Id] = u
|
userMap[u.Id] = u
|
||||||
|
profileByIdsCache.AddWithExpiresInSecs(u.Id, u, PROFILE_BY_IDS_CACHE_SEC)
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Data = userMap
|
result.Data = userMap
|
||||||
|
|||||||
@@ -453,7 +453,33 @@ func TestUserStoreGetProfilesByIds(t *testing.T) {
|
|||||||
Must(store.User().Save(u2))
|
Must(store.User().Save(u2))
|
||||||
Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
|
Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
|
||||||
|
|
||||||
if r1 := <-store.User().GetProfileByIds([]string{u1.Id, u2.Id}); r1.Err != nil {
|
if r1 := <-store.User().GetProfileByIds([]string{u1.Id}, false); r1.Err != nil {
|
||||||
|
t.Fatal(r1.Err)
|
||||||
|
} else {
|
||||||
|
users := r1.Data.(map[string]*model.User)
|
||||||
|
if len(users) != 1 {
|
||||||
|
t.Fatal("invalid returned users")
|
||||||
|
}
|
||||||
|
|
||||||
|
if users[u1.Id].Id != u1.Id {
|
||||||
|
t.Fatal("invalid returned user")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r1 := <-store.User().GetProfileByIds([]string{u1.Id}, true); r1.Err != nil {
|
||||||
|
t.Fatal(r1.Err)
|
||||||
|
} else {
|
||||||
|
users := r1.Data.(map[string]*model.User)
|
||||||
|
if len(users) != 1 {
|
||||||
|
t.Fatal("invalid returned users")
|
||||||
|
}
|
||||||
|
|
||||||
|
if users[u1.Id].Id != u1.Id {
|
||||||
|
t.Fatal("invalid returned user")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r1 := <-store.User().GetProfileByIds([]string{u1.Id, u2.Id}, true); r1.Err != nil {
|
||||||
t.Fatal(r1.Err)
|
t.Fatal(r1.Err)
|
||||||
} else {
|
} else {
|
||||||
users := r1.Data.(map[string]*model.User)
|
users := r1.Data.(map[string]*model.User)
|
||||||
@@ -466,7 +492,33 @@ func TestUserStoreGetProfilesByIds(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if r1 := <-store.User().GetProfileByIds([]string{u1.Id}); r1.Err != nil {
|
if r1 := <-store.User().GetProfileByIds([]string{u1.Id, u2.Id}, true); r1.Err != nil {
|
||||||
|
t.Fatal(r1.Err)
|
||||||
|
} else {
|
||||||
|
users := r1.Data.(map[string]*model.User)
|
||||||
|
if len(users) != 2 {
|
||||||
|
t.Fatal("invalid returned users")
|
||||||
|
}
|
||||||
|
|
||||||
|
if users[u1.Id].Id != u1.Id {
|
||||||
|
t.Fatal("invalid returned user")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r1 := <-store.User().GetProfileByIds([]string{u1.Id, u2.Id}, false); r1.Err != nil {
|
||||||
|
t.Fatal(r1.Err)
|
||||||
|
} else {
|
||||||
|
users := r1.Data.(map[string]*model.User)
|
||||||
|
if len(users) != 2 {
|
||||||
|
t.Fatal("invalid returned users")
|
||||||
|
}
|
||||||
|
|
||||||
|
if users[u1.Id].Id != u1.Id {
|
||||||
|
t.Fatal("invalid returned user")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r1 := <-store.User().GetProfileByIds([]string{u1.Id}, false); r1.Err != nil {
|
||||||
t.Fatal(r1.Err)
|
t.Fatal(r1.Err)
|
||||||
} else {
|
} else {
|
||||||
users := r1.Data.(map[string]*model.User)
|
users := r1.Data.(map[string]*model.User)
|
||||||
|
|||||||
@@ -155,7 +155,8 @@ type UserStore interface {
|
|||||||
GetProfilesByUsernames(usernames []string, teamId string) StoreChannel
|
GetProfilesByUsernames(usernames []string, teamId string) StoreChannel
|
||||||
GetAllProfiles(offset int, limit int) StoreChannel
|
GetAllProfiles(offset int, limit int) StoreChannel
|
||||||
GetProfiles(teamId string, offset int, limit int) StoreChannel
|
GetProfiles(teamId string, offset int, limit int) StoreChannel
|
||||||
GetProfileByIds(userId []string) StoreChannel
|
GetProfileByIds(userId []string, allowFromCache bool) StoreChannel
|
||||||
|
InvalidatProfileCacheForUser(userId string)
|
||||||
GetByEmail(email string) StoreChannel
|
GetByEmail(email string) StoreChannel
|
||||||
GetByAuth(authData *string, authService string) StoreChannel
|
GetByAuth(authData *string, authService string) StoreChannel
|
||||||
GetAllUsingAuthService(authService string) StoreChannel
|
GetAllUsingAuthService(authService string) StoreChannel
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user