summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBo-Yi Wu <appleboy.tw@gmail.com>2018-02-21 18:55:34 +0800
committerGitHub <noreply@github.com>2018-02-21 18:55:34 +0800
commit04b3e8cbdc2bb4eafe8feb3fe4882f010e931860 (patch)
treeca463be266c44aaf52e5106aac77dfd56402057b
parentd27d720f05835dfc4633587aec885ab9b93b5f86 (diff)
downloadgitea-04b3e8cbdc2bb4eafe8feb3fe4882f010e931860.tar.gz
gitea-04b3e8cbdc2bb4eafe8feb3fe4882f010e931860.zip
refactor: reduce sql query in retrieveFeeds (#3547)
-rw-r--r--models/action.go11
-rw-r--r--models/action_list.go98
-rw-r--r--routers/user/home.go39
3 files changed, 116 insertions, 32 deletions
diff --git a/models/action.go b/models/action.go
index 5333f62772..b551d79bb8 100644
--- a/models/action.go
+++ b/models/action.go
@@ -742,5 +742,14 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
}
actions := make([]*Action, 0, 20)
- return actions, x.Limit(20).Desc("id").Where(cond).Find(&actions)
+
+ if err := x.Limit(20).Desc("id").Where(cond).Find(&actions); err != nil {
+ return nil, fmt.Errorf("Find: %v", err)
+ }
+
+ if err := ActionList(actions).LoadAttributes(); err != nil {
+ return nil, fmt.Errorf("LoadAttributes: %v", err)
+ }
+
+ return actions, nil
}
diff --git a/models/action_list.go b/models/action_list.go
new file mode 100644
index 0000000000..6f726f4b34
--- /dev/null
+++ b/models/action_list.go
@@ -0,0 +1,98 @@
+// Copyright 2018 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package models
+
+import "fmt"
+
+// ActionList defines a list of actions
+type ActionList []*Action
+
+func (actions ActionList) getUserIDs() []int64 {
+ userIDs := make(map[int64]struct{}, len(actions))
+ for _, action := range actions {
+ if _, ok := userIDs[action.ActUserID]; !ok {
+ userIDs[action.ActUserID] = struct{}{}
+ }
+ }
+ return keysInt64(userIDs)
+}
+
+func (actions ActionList) loadUsers(e Engine) ([]*User, error) {
+ if len(actions) == 0 {
+ return nil, nil
+ }
+
+ userIDs := actions.getUserIDs()
+ userMaps := make(map[int64]*User, len(userIDs))
+ err := e.
+ In("id", userIDs).
+ Find(&userMaps)
+ if err != nil {
+ return nil, fmt.Errorf("find user: %v", err)
+ }
+
+ for _, action := range actions {
+ action.ActUser = userMaps[action.ActUserID]
+ }
+ return valuesUser(userMaps), nil
+}
+
+// LoadUsers loads actions' all users
+func (actions ActionList) LoadUsers() ([]*User, error) {
+ return actions.loadUsers(x)
+}
+
+func (actions ActionList) getRepoIDs() []int64 {
+ repoIDs := make(map[int64]struct{}, len(actions))
+ for _, action := range actions {
+ if _, ok := repoIDs[action.RepoID]; !ok {
+ repoIDs[action.RepoID] = struct{}{}
+ }
+ }
+ return keysInt64(repoIDs)
+}
+
+func (actions ActionList) loadRepositories(e Engine) ([]*Repository, error) {
+ if len(actions) == 0 {
+ return nil, nil
+ }
+
+ repoIDs := actions.getRepoIDs()
+ repoMaps := make(map[int64]*Repository, len(repoIDs))
+ err := e.
+ In("id", repoIDs).
+ Find(&repoMaps)
+ if err != nil {
+ return nil, fmt.Errorf("find repository: %v", err)
+ }
+
+ for _, action := range actions {
+ action.Repo = repoMaps[action.RepoID]
+ }
+ return valuesRepository(repoMaps), nil
+}
+
+// LoadRepositories loads actions' all repositories
+func (actions ActionList) LoadRepositories() ([]*Repository, error) {
+ return actions.loadRepositories(x)
+}
+
+// loadAttributes loads all attributes
+func (actions ActionList) loadAttributes(e Engine) (err error) {
+ if _, err = actions.loadUsers(e); err != nil {
+ return
+ }
+
+ if _, err = actions.loadRepositories(e); err != nil {
+ return
+ }
+
+ return nil
+}
+
+// LoadAttributes loads attributes of the actions
+func (actions ActionList) LoadAttributes() error {
+ return actions.loadAttributes(x)
+}
diff --git a/routers/user/home.go b/routers/user/home.go
index 5687cb4f1a..2a193bbdef 100644
--- a/routers/user/home.go
+++ b/routers/user/home.go
@@ -66,39 +66,14 @@ func retrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) {
if ctx.User != nil {
userCache[ctx.User.ID] = ctx.User
}
- repoCache := map[int64]*models.Repository{}
for _, act := range actions {
- // Cache results to reduce queries.
- u, ok := userCache[act.ActUserID]
- if !ok {
- u, err = models.GetUserByID(act.ActUserID)
- if err != nil {
- if models.IsErrUserNotExist(err) {
- continue
- }
- ctx.ServerError("GetUserByID", err)
- return
- }
- userCache[act.ActUserID] = u
- }
- act.ActUser = u
-
- repo, ok := repoCache[act.RepoID]
- if !ok {
- repo, err = models.GetRepositoryByID(act.RepoID)
- if err != nil {
- if models.IsErrRepoNotExist(err) {
- continue
- }
- ctx.ServerError("GetRepositoryByID", err)
- return
- }
+ if act.ActUser != nil {
+ userCache[act.ActUserID] = act.ActUser
}
- act.Repo = repo
- repoOwner, ok := userCache[repo.OwnerID]
+ repoOwner, ok := userCache[act.Repo.OwnerID]
if !ok {
- repoOwner, err = models.GetUserByID(repo.OwnerID)
+ repoOwner, err = models.GetUserByID(act.Repo.OwnerID)
if err != nil {
if models.IsErrUserNotExist(err) {
continue
@@ -106,8 +81,9 @@ func retrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) {
ctx.ServerError("GetUserByID", err)
return
}
+ userCache[repoOwner.ID] = repoOwner
}
- repo.Owner = repoOwner
+ act.Repo.Owner = repoOwner
}
ctx.Data["Feeds"] = actions
}
@@ -154,7 +130,8 @@ func Dashboard(ctx *context.Context) {
ctx.Data["MirrorCount"] = len(mirrors)
ctx.Data["Mirrors"] = mirrors
- retrieveFeeds(ctx, models.GetFeedsOptions{RequestedUser: ctxUser,
+ retrieveFeeds(ctx, models.GetFeedsOptions{
+ RequestedUser: ctxUser,
IncludePrivate: true,
OnlyPerformedBy: false,
IncludeDeleted: false,