Skip to content

Commit ed2ba84

Browse files
appleboylafriks
authored andcommitted
refactor: reduce sql query in retrieveFeeds (#3554)
1 parent e8015a5 commit ed2ba84

File tree

3 files changed

+116
-32
lines changed

3 files changed

+116
-32
lines changed

models/action.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,5 +742,14 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
742742
}
743743

744744
actions := make([]*Action, 0, 20)
745-
return actions, x.Limit(20).Desc("id").Where(cond).Find(&actions)
745+
746+
if err := x.Limit(20).Desc("id").Where(cond).Find(&actions); err != nil {
747+
return nil, fmt.Errorf("Find: %v", err)
748+
}
749+
750+
if err := ActionList(actions).LoadAttributes(); err != nil {
751+
return nil, fmt.Errorf("LoadAttributes: %v", err)
752+
}
753+
754+
return actions, nil
746755
}

models/action_list.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright 2018 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package models
6+
7+
import "fmt"
8+
9+
// ActionList defines a list of actions
10+
type ActionList []*Action
11+
12+
func (actions ActionList) getUserIDs() []int64 {
13+
userIDs := make(map[int64]struct{}, len(actions))
14+
for _, action := range actions {
15+
if _, ok := userIDs[action.ActUserID]; !ok {
16+
userIDs[action.ActUserID] = struct{}{}
17+
}
18+
}
19+
return keysInt64(userIDs)
20+
}
21+
22+
func (actions ActionList) loadUsers(e Engine) ([]*User, error) {
23+
if len(actions) == 0 {
24+
return nil, nil
25+
}
26+
27+
userIDs := actions.getUserIDs()
28+
userMaps := make(map[int64]*User, len(userIDs))
29+
err := e.
30+
In("id", userIDs).
31+
Find(&userMaps)
32+
if err != nil {
33+
return nil, fmt.Errorf("find user: %v", err)
34+
}
35+
36+
for _, action := range actions {
37+
action.ActUser = userMaps[action.ActUserID]
38+
}
39+
return valuesUser(userMaps), nil
40+
}
41+
42+
// LoadUsers loads actions' all users
43+
func (actions ActionList) LoadUsers() ([]*User, error) {
44+
return actions.loadUsers(x)
45+
}
46+
47+
func (actions ActionList) getRepoIDs() []int64 {
48+
repoIDs := make(map[int64]struct{}, len(actions))
49+
for _, action := range actions {
50+
if _, ok := repoIDs[action.RepoID]; !ok {
51+
repoIDs[action.RepoID] = struct{}{}
52+
}
53+
}
54+
return keysInt64(repoIDs)
55+
}
56+
57+
func (actions ActionList) loadRepositories(e Engine) ([]*Repository, error) {
58+
if len(actions) == 0 {
59+
return nil, nil
60+
}
61+
62+
repoIDs := actions.getRepoIDs()
63+
repoMaps := make(map[int64]*Repository, len(repoIDs))
64+
err := e.
65+
In("id", repoIDs).
66+
Find(&repoMaps)
67+
if err != nil {
68+
return nil, fmt.Errorf("find repository: %v", err)
69+
}
70+
71+
for _, action := range actions {
72+
action.Repo = repoMaps[action.RepoID]
73+
}
74+
return valuesRepository(repoMaps), nil
75+
}
76+
77+
// LoadRepositories loads actions' all repositories
78+
func (actions ActionList) LoadRepositories() ([]*Repository, error) {
79+
return actions.loadRepositories(x)
80+
}
81+
82+
// loadAttributes loads all attributes
83+
func (actions ActionList) loadAttributes(e Engine) (err error) {
84+
if _, err = actions.loadUsers(e); err != nil {
85+
return
86+
}
87+
88+
if _, err = actions.loadRepositories(e); err != nil {
89+
return
90+
}
91+
92+
return nil
93+
}
94+
95+
// LoadAttributes loads attributes of the actions
96+
func (actions ActionList) LoadAttributes() error {
97+
return actions.loadAttributes(x)
98+
}

routers/user/home.go

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -66,48 +66,24 @@ func retrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) {
6666
if ctx.User != nil {
6767
userCache[ctx.User.ID] = ctx.User
6868
}
69-
repoCache := map[int64]*models.Repository{}
7069
for _, act := range actions {
71-
// Cache results to reduce queries.
72-
u, ok := userCache[act.ActUserID]
73-
if !ok {
74-
u, err = models.GetUserByID(act.ActUserID)
75-
if err != nil {
76-
if models.IsErrUserNotExist(err) {
77-
continue
78-
}
79-
ctx.ServerError("GetUserByID", err)
80-
return
81-
}
82-
userCache[act.ActUserID] = u
83-
}
84-
act.ActUser = u
85-
86-
repo, ok := repoCache[act.RepoID]
87-
if !ok {
88-
repo, err = models.GetRepositoryByID(act.RepoID)
89-
if err != nil {
90-
if models.IsErrRepoNotExist(err) {
91-
continue
92-
}
93-
ctx.ServerError("GetRepositoryByID", err)
94-
return
95-
}
70+
if act.ActUser != nil {
71+
userCache[act.ActUserID] = act.ActUser
9672
}
97-
act.Repo = repo
9873

99-
repoOwner, ok := userCache[repo.OwnerID]
74+
repoOwner, ok := userCache[act.Repo.OwnerID]
10075
if !ok {
101-
repoOwner, err = models.GetUserByID(repo.OwnerID)
76+
repoOwner, err = models.GetUserByID(act.Repo.OwnerID)
10277
if err != nil {
10378
if models.IsErrUserNotExist(err) {
10479
continue
10580
}
10681
ctx.ServerError("GetUserByID", err)
10782
return
10883
}
84+
userCache[repoOwner.ID] = repoOwner
10985
}
110-
repo.Owner = repoOwner
86+
act.Repo.Owner = repoOwner
11187
}
11288
ctx.Data["Feeds"] = actions
11389
}
@@ -154,7 +130,8 @@ func Dashboard(ctx *context.Context) {
154130
ctx.Data["MirrorCount"] = len(mirrors)
155131
ctx.Data["Mirrors"] = mirrors
156132

157-
retrieveFeeds(ctx, models.GetFeedsOptions{RequestedUser: ctxUser,
133+
retrieveFeeds(ctx, models.GetFeedsOptions{
134+
RequestedUser: ctxUser,
158135
IncludePrivate: true,
159136
OnlyPerformedBy: false,
160137
IncludeDeleted: false,

0 commit comments

Comments
 (0)