From 5525452bdf517227e1e6f92fc4adde5f45b4d858 Mon Sep 17 00:00:00 2001 From: guillep2k <18600385+guillep2k@users.noreply.github.com> Date: Sat, 15 Feb 2020 14:07:09 -0300 Subject: [PATCH] Divide GetIssueStats query in smaller chunks (#10176) (#10282) * Divide GetIssueStats query in smaller chunks * Skip chunking if count is low enough * Fix lint * Define maxQueryParameters * Remove absMaxQueryParameters because of lint * Restart CI * Restart CI Co-authored-by: Lunny Xiao Co-authored-by: zeripath Co-authored-by: Lauris BH Co-authored-by: Lunny Xiao Co-authored-by: zeripath Co-authored-by: Lauris BH --- models/issue.go | 30 ++++++++++++++++++++++++++++++ models/models.go | 6 ++++++ 2 files changed, 36 insertions(+) diff --git a/models/issue.go b/models/issue.go index 7c7a7c295ad..5d6c9a83e2e 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1336,6 +1336,36 @@ type IssueStatsOptions struct { // GetIssueStats returns issue statistic information by given conditions. func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { + if len(opts.IssueIDs) <= maxQueryParameters { + return getIssueStatsChunk(opts, opts.IssueIDs) + } + + // If too long a list of IDs is provided, we get the statistics in + // smaller chunks and get accumulates. Note: this could potentially + // get us invalid results. The alternative is to insert the list of + // ids in a temporary table and join from them. + accum := &IssueStats{} + for i := 0; i < len(opts.IssueIDs); { + chunk := i + maxQueryParameters + if chunk > len(opts.IssueIDs) { + chunk = len(opts.IssueIDs) + } + stats, err := getIssueStatsChunk(opts, opts.IssueIDs[i:chunk]) + if err != nil { + return nil, err + } + accum.OpenCount += stats.OpenCount + accum.ClosedCount += stats.ClosedCount + accum.YourRepositoriesCount += stats.YourRepositoriesCount + accum.AssignCount += stats.AssignCount + accum.CreateCount += stats.CreateCount + accum.OpenCount += stats.MentionCount + i = chunk + } + return accum, nil +} + +func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats, error) { stats := &IssueStats{} countSession := func(opts *IssueStatsOptions) *xorm.Session { diff --git a/models/models.go b/models/models.go index 9eb174e200d..fa578403820 100644 --- a/models/models.go +++ b/models/models.go @@ -46,6 +46,12 @@ type Engine interface { Asc(colNames ...string) *xorm.Session } +const ( + // When queries are broken down in parts because of the number + // of parameters, attempt to break by this amount + maxQueryParameters = 300 +) + var ( x *xorm.Engine tables []interface{}