forked from gitea/gitea
Speed up HasUserStopwatch & GetActiveStopwatch (#23051)
GetActiveStopwatch & HasUserStopwatch is a hot piece of code that is repeatedly called and on examination of the cpu profile for TestGit it represents 0.44 seconds of CPU time. This PR reduces this time to 80ms. --------- Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: KN4CK3R <admin@oldschoolhack.me> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: delvh <leon@kske.dev>
This commit is contained in:
parent
0e7bec1849
commit
ef4fc30246
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
@ -132,12 +133,26 @@ func StopwatchExists(userID, issueID int64) bool {
|
|||
}
|
||||
|
||||
// HasUserStopwatch returns true if the user has a stopwatch
|
||||
func HasUserStopwatch(ctx context.Context, userID int64) (exists bool, sw *Stopwatch, err error) {
|
||||
sw = new(Stopwatch)
|
||||
func HasUserStopwatch(ctx context.Context, userID int64) (exists bool, sw *Stopwatch, issue *Issue, err error) {
|
||||
type stopwatchIssueRepo struct {
|
||||
Stopwatch `xorm:"extends"`
|
||||
Issue `xorm:"extends"`
|
||||
repo.Repository `xorm:"extends"`
|
||||
}
|
||||
|
||||
swIR := new(stopwatchIssueRepo)
|
||||
exists, err = db.GetEngine(ctx).
|
||||
Table("stopwatch").
|
||||
Where("user_id = ?", userID).
|
||||
Get(sw)
|
||||
return exists, sw, err
|
||||
Join("INNER", "issue", "issue.id = stopwatch.issue_id").
|
||||
Join("INNER", "repository", "repository.id = issue.repo_id").
|
||||
Get(swIR)
|
||||
if exists {
|
||||
sw = &swIR.Stopwatch
|
||||
issue = &swIR.Issue
|
||||
issue.Repo = &swIR.Repository
|
||||
}
|
||||
return exists, sw, issue, err
|
||||
}
|
||||
|
||||
// FinishIssueStopwatchIfPossible if stopwatch exist then finish it otherwise ignore
|
||||
|
@ -217,23 +232,18 @@ func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss
|
|||
}
|
||||
|
||||
// if another stopwatch is running: stop it
|
||||
exists, sw, err := HasUserStopwatch(ctx, user.ID)
|
||||
exists, _, otherIssue, err := HasUserStopwatch(ctx, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
issue, err := GetIssueByID(ctx, sw.IssueID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := FinishIssueStopwatch(ctx, user, issue); err != nil {
|
||||
if err := FinishIssueStopwatch(ctx, user, otherIssue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create stopwatch
|
||||
sw = &Stopwatch{
|
||||
sw := &Stopwatch{
|
||||
UserID: user.ID,
|
||||
IssueID: issue.ID,
|
||||
}
|
||||
|
|
|
@ -45,12 +45,12 @@ func TestStopwatchExists(t *testing.T) {
|
|||
func TestHasUserStopwatch(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
exists, sw, err := issues_model.HasUserStopwatch(db.DefaultContext, 1)
|
||||
exists, sw, _, err := issues_model.HasUserStopwatch(db.DefaultContext, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, exists)
|
||||
assert.Equal(t, int64(1), sw.ID)
|
||||
|
||||
exists, _, err = issues_model.HasUserStopwatch(db.DefaultContext, 3)
|
||||
exists, _, _, err = issues_model.HasUserStopwatch(db.DefaultContext, 3)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, exists)
|
||||
}
|
||||
|
|
|
@ -1432,25 +1432,16 @@ func ViewIssue(ctx *context.Context) {
|
|||
ctx.Data["IsStopwatchRunning"] = issues_model.StopwatchExists(ctx.Doer.ID, issue.ID)
|
||||
if !ctx.Data["IsStopwatchRunning"].(bool) {
|
||||
var exists bool
|
||||
var sw *issues_model.Stopwatch
|
||||
if exists, sw, err = issues_model.HasUserStopwatch(ctx, ctx.Doer.ID); err != nil {
|
||||
var swIssue *issues_model.Issue
|
||||
if exists, _, swIssue, err = issues_model.HasUserStopwatch(ctx, ctx.Doer.ID); err != nil {
|
||||
ctx.ServerError("HasUserStopwatch", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["HasUserStopwatch"] = exists
|
||||
if exists {
|
||||
// Add warning if the user has already a stopwatch
|
||||
var otherIssue *issues_model.Issue
|
||||
if otherIssue, err = issues_model.GetIssueByID(ctx, sw.IssueID); err != nil {
|
||||
ctx.ServerError("GetIssueByID", err)
|
||||
return
|
||||
}
|
||||
if err = otherIssue.LoadRepo(ctx); err != nil {
|
||||
ctx.ServerError("LoadRepo", err)
|
||||
return
|
||||
}
|
||||
// Add link to the issue of the already running stopwatch
|
||||
ctx.Data["OtherStopwatchURL"] = otherIssue.Link()
|
||||
ctx.Data["OtherStopwatchURL"] = swIssue.Link()
|
||||
}
|
||||
}
|
||||
ctx.Data["CanUseTimetracker"] = ctx.Repo.CanUseTimetracker(issue, ctx.Doer)
|
||||
|
|
|
@ -86,7 +86,7 @@ func GetActiveStopwatch(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
_, sw, err := issues_model.HasUserStopwatch(ctx, ctx.Doer.ID)
|
||||
_, sw, issue, err := issues_model.HasUserStopwatch(ctx, ctx.Doer.ID)
|
||||
if err != nil {
|
||||
ctx.ServerError("HasUserStopwatch", err)
|
||||
return
|
||||
|
@ -96,18 +96,6 @@ func GetActiveStopwatch(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
issue, err := issues_model.GetIssueByID(ctx, sw.IssueID)
|
||||
if err != nil || issue == nil {
|
||||
if !issues_model.IsErrIssueNotExist(err) {
|
||||
ctx.ServerError("GetIssueByID", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
ctx.ServerError("LoadRepo", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["ActiveStopwatch"] = StopwatchTmplInfo{
|
||||
issue.Link(),
|
||||
issue.Repo.FullName(),
|
||||
|
|
Loading…
Reference in New Issue