Skip to content

Commit 5fe2ec2

Browse files
guillep2ktechknowlogick
authored andcommitted
Retry create issue to cope with duplicate keys (#7898)
* Retry create issue to cope with duplicate keys * Use .SetExpr().Where().Insert()
1 parent 541fab1 commit 5fe2ec2

39 files changed

+2002
-1415
lines changed

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ require (
4545
github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
4646
github.com/go-redis/redis v6.15.2+incompatible
4747
github.com/go-sql-driver/mysql v1.4.1
48-
github.com/go-xorm/xorm v0.7.4
48+
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b
4949
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561
5050
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
5151
github.com/google/go-github/v24 v24.0.1
@@ -117,5 +117,5 @@ require (
117117
mvdan.cc/xurls/v2 v2.0.0
118118
strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a
119119
xorm.io/builder v0.3.5
120-
xorm.io/core v0.6.3
120+
xorm.io/core v0.7.0
121121
)

go.sum

+7
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk
143143
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
144144
github.com/go-xorm/xorm v0.7.4 h1:g/NgC590SzqV5VKmdRDNe/K3Holw3YJUCXX28r+rFGw=
145145
github.com/go-xorm/xorm v0.7.4/go.mod h1:vpza5fydeRgt+stvo9qgMhSNohYqmNt0I1/D6hkCekA=
146+
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b h1:Y0hWUheXDHpIs7BWtJcykO4d1VOsVDKg1PsP5YJwxxM=
147+
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls=
146148
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04PgtpyVOS2TYcQEld9qLCD5b5EbVNOuLA=
147149
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ=
148150
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -430,6 +432,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
430432
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
431433
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
432434
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
435+
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
433436
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
434437
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
435438
golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -446,6 +449,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
446449
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
447450
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
448451
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
452+
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
449453
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
450454
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
451455
golang.org/x/tools v0.0.0-20190731214159-1e85ed8060aa h1:kwa/4M1dbmhZqOIqYiTtbA6JrvPwo1+jqlub2qDXX90=
@@ -454,6 +458,7 @@ google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMt
454458
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
455459
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
456460
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
461+
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
457462
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
458463
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
459464
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -509,3 +514,5 @@ xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A=
509514
xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8=
510515
xorm.io/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M=
511516
xorm.io/core v0.6.3/go.mod h1:8kz/C6arVW/O9vk3PgCiMJO2hIAm1UcuOL3dSPyZ2qo=
517+
xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM=
518+
xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI=

models/issue.go

+23-29
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package models
66

77
import (
8-
"errors"
98
"fmt"
109
"path"
1110
"regexp"
@@ -74,6 +73,7 @@ var (
7473

7574
const issueTasksRegexpStr = `(^\s*[-*]\s\[[\sx]\]\s.)|(\n\s*[-*]\s\[[\sx]\]\s.)`
7675
const issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[x]\]\s.)|(\n\s*[-*]\s\[[x]\]\s.)`
76+
const issueMaxDupIndexAttempts = 3
7777

7878
func init() {
7979
issueTasksPat = regexp.MustCompile(issueTasksRegexpStr)
@@ -1031,36 +1031,9 @@ type NewIssueOptions struct {
10311031
IsPull bool
10321032
}
10331033

1034-
// GetMaxIndexOfIssue returns the max index on issue
1035-
func GetMaxIndexOfIssue(repoID int64) (int64, error) {
1036-
return getMaxIndexOfIssue(x, repoID)
1037-
}
1038-
1039-
func getMaxIndexOfIssue(e Engine, repoID int64) (int64, error) {
1040-
var (
1041-
maxIndex int64
1042-
has bool
1043-
err error
1044-
)
1045-
1046-
has, err = e.SQL("SELECT COALESCE((SELECT MAX(`index`) FROM issue WHERE repo_id = ?),0)", repoID).Get(&maxIndex)
1047-
if err != nil {
1048-
return 0, err
1049-
} else if !has {
1050-
return 0, errors.New("Retrieve Max index from issue failed")
1051-
}
1052-
return maxIndex, nil
1053-
}
1054-
10551034
func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
10561035
opts.Issue.Title = strings.TrimSpace(opts.Issue.Title)
10571036

1058-
maxIndex, err := getMaxIndexOfIssue(e, opts.Issue.RepoID)
1059-
if err != nil {
1060-
return err
1061-
}
1062-
opts.Issue.Index = maxIndex + 1
1063-
10641037
if opts.Issue.MilestoneID > 0 {
10651038
milestone, err := getMilestoneByRepoID(e, opts.Issue.RepoID, opts.Issue.MilestoneID)
10661039
if err != nil && !IsErrMilestoneNotExist(err) {
@@ -1109,10 +1082,31 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
11091082
}
11101083

11111084
// Milestone and assignee validation should happen before insert actual object.
1112-
if _, err = e.Insert(opts.Issue); err != nil {
1085+
1086+
// There's no good way to identify a duplicate key error in database/sql; brute force some retries
1087+
dupIndexAttempts := issueMaxDupIndexAttempts
1088+
for {
1089+
_, err := e.SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
1090+
Where("repo_id=?", opts.Issue.RepoID).
1091+
Insert(opts.Issue)
1092+
if err == nil {
1093+
break
1094+
}
1095+
1096+
dupIndexAttempts--
1097+
if dupIndexAttempts <= 0 {
1098+
return err
1099+
}
1100+
}
1101+
1102+
inserted, err := getIssueByID(e, opts.Issue.ID)
1103+
if err != nil {
11131104
return err
11141105
}
11151106

1107+
// Patch Index with the value calculated by the database
1108+
opts.Issue.Index = inserted.Index
1109+
11161110
if opts.Issue.MilestoneID > 0 {
11171111
if err = changeMilestoneAssign(e, doer, opts.Issue, -1); err != nil {
11181112
return err

routers/api/v1/repo/pull.go

-7
Original file line numberDiff line numberDiff line change
@@ -252,15 +252,8 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
252252
deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
253253
}
254254

255-
maxIndex, err := models.GetMaxIndexOfIssue(repo.ID)
256-
if err != nil {
257-
ctx.ServerError("GetPatch", err)
258-
return
259-
}
260-
261255
prIssue := &models.Issue{
262256
RepoID: repo.ID,
263-
Index: maxIndex + 1,
264257
Title: form.Title,
265258
PosterID: ctx.User.ID,
266259
Poster: ctx.User,

routers/repo/pull.go

-7
Original file line numberDiff line numberDiff line change
@@ -710,15 +710,8 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
710710
return
711711
}
712712

713-
maxIndex, err := models.GetMaxIndexOfIssue(repo.ID)
714-
if err != nil {
715-
ctx.ServerError("GetPatch", err)
716-
return
717-
}
718-
719713
pullIssue := &models.Issue{
720714
RepoID: repo.ID,
721-
Index: maxIndex + 1,
722715
Title: form.Title,
723716
PosterID: ctx.User.ID,
724717
Poster: ctx.User,

0 commit comments

Comments
 (0)