summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
authorYorick Peterse <yorickpeterse@gmail.com>2017-08-17 17:21:25 +0200
committerYorick Peterse <yorickpeterse@gmail.com>2017-08-18 13:09:09 +0200
commit049578ff6f75a5ab4ceaabdefa988045f1895d89 (patch)
tree414a34a32bdccbd2405c56619c6f8e1005a48bb6 /app/models
parent133c72ae421b97f483417d5c427721336719b5da (diff)
downloadgitlab-ce-cache-issue-and-mr-counts.tar.gz
Cache the number of open issues and merge requestscache-issue-and-mr-counts
Every project page displays a navigation menu that in turn displays the number of open issues and merge requests. This means that for every project page we run two COUNT(*) queries, each taking up roughly 30 milliseconds on GitLab.com. By caching these numbers and refreshing them whenever necessary we can reduce loading times of all these pages by up to roughly 60 milliseconds. The number of open issues _includes_ confidential issues, even if you can not see these issues. This is a trade-off to keep the code simple and to ensure refreshing the data only needs 2 COUNT(*) queries instead of 3. Further, by including all issues we don't need any additional work to determine if the issue counter we display to a user should include confidential issues or not. This does mean that if a project has 10 issues of which 5 are confidential, everybody (that can see the project) will see the number 10. Because we now have 3 similar counting service classes the code previously used in Projects::ForksCountService has mostly been moved to Projects::CountService, which in turn is reused by the various service classes. Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/36622
Diffstat (limited to 'app/models')
-rw-r--r--app/models/issue.rb5
-rw-r--r--app/models/merge_request.rb5
-rw-r--r--app/models/project.rb6
3 files changed, 15 insertions, 1 deletions
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 1c948c8957e..9dbc018ed3e 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -54,6 +54,7 @@ class Issue < ActiveRecord::Base
scope :preload_associations, -> { preload(:labels, project: :namespace) }
after_save :expire_etag_cache
+ after_commit :update_project_counter_caches, on: :destroy
attr_spammable :title, spam_title: true
attr_spammable :description, spam_description: true
@@ -269,6 +270,10 @@ class Issue < ActiveRecord::Base
end
end
+ def update_project_counter_caches
+ Projects::OpenIssuesCountService.new(project).refresh_cache
+ end
+
private
# Returns `true` if the given User can read the current Issue.
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index ac08dc0ee1f..7fe7df75944 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -32,6 +32,7 @@ class MergeRequest < ActiveRecord::Base
after_create :ensure_merge_request_diff, unless: :importing?
after_update :reload_diff_if_branch_changed
+ after_commit :update_project_counter_caches, on: :destroy
# When this attribute is true some MR validation is ignored
# It allows us to close or modify broken merge requests
@@ -937,6 +938,10 @@ class MergeRequest < ActiveRecord::Base
true
end
+ def update_project_counter_caches
+ Projects::OpenMergeRequestsCountService.new(target_project).refresh_cache
+ end
+
private
def write_ref
diff --git a/app/models/project.rb b/app/models/project.rb
index be248bc99e1..ddef8b82dee 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1158,7 +1158,11 @@ class Project < ActiveRecord::Base
end
def open_issues_count
- issues.opened.count
+ Projects::OpenIssuesCountService.new(self).count
+ end
+
+ def open_merge_requests_count
+ Projects::OpenMergeRequestsCountService.new(self).count
end
def visibility_level_allowed_as_fork?(level = self.visibility_level)