forked from gitea/gitea
Bypass MariaDB performance bug of the "IN" sub-query, fix incorrect IssueIndex (#26279)
Close #26277 Fix #26285
This commit is contained in:
parent
24fbf4e059
commit
e4b1ea6f15
|
@ -685,18 +685,34 @@ func NotifyWatchersActions(acts []*Action) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteIssueActions delete all actions related with issueID
|
// DeleteIssueActions delete all actions related with issueID
|
||||||
func DeleteIssueActions(ctx context.Context, repoID, issueID int64) error {
|
func DeleteIssueActions(ctx context.Context, repoID, issueID, issueIndex int64) error {
|
||||||
// delete actions assigned to this issue
|
// delete actions assigned to this issue
|
||||||
subQuery := builder.Select("`id`").
|
e := db.GetEngine(ctx)
|
||||||
From("`comment`").
|
|
||||||
Where(builder.Eq{"`issue_id`": issueID})
|
// MariaDB has a performance bug: https://jira.mariadb.org/browse/MDEV-16289
|
||||||
if _, err := db.GetEngine(ctx).In("comment_id", subQuery).Delete(&Action{}); err != nil {
|
// so here it uses "DELETE ... WHERE IN" with pre-queried IDs.
|
||||||
return err
|
var lastCommentID int64
|
||||||
|
commentIDs := make([]int64, 0, db.DefaultMaxInSize)
|
||||||
|
for {
|
||||||
|
commentIDs = commentIDs[:0]
|
||||||
|
err := e.Select("`id`").Table(&issues_model.Comment{}).
|
||||||
|
Where(builder.Eq{"issue_id": issueID}).And("`id` > ?", lastCommentID).
|
||||||
|
OrderBy("`id`").Limit(db.DefaultMaxInSize).
|
||||||
|
Find(&commentIDs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if len(commentIDs) == 0 {
|
||||||
|
break
|
||||||
|
} else if _, err = db.GetEngine(ctx).In("comment_id", commentIDs).Delete(&Action{}); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
lastCommentID = commentIDs[len(commentIDs)-1]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := db.GetEngine(ctx).Table("action").Where("repo_id = ?", repoID).
|
_, err := e.Where("repo_id = ?", repoID).
|
||||||
In("op_type", ActionCreateIssue, ActionCreatePullRequest).
|
In("op_type", ActionCreateIssue, ActionCreatePullRequest).
|
||||||
Where("content LIKE ?", strconv.FormatInt(issueID, 10)+"|%").
|
Where("content LIKE ?", strconv.FormatInt(issueIndex, 10)+"|%"). // "IssueIndex|content..."
|
||||||
Delete(&Action{})
|
Delete(&Action{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package activities_test
|
package activities_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -284,3 +285,36 @@ func TestConsistencyUpdateAction(t *testing.T) {
|
||||||
assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions))
|
assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions))
|
||||||
unittest.CheckConsistencyFor(t, &activities_model.Action{})
|
unittest.CheckConsistencyFor(t, &activities_model.Action{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteIssueActions(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
// load an issue
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4})
|
||||||
|
assert.NotEqualValues(t, issue.ID, issue.Index) // it needs to use different ID/Index to test the DeleteIssueActions to delete some actions by IssueIndex
|
||||||
|
|
||||||
|
// insert a comment
|
||||||
|
err := db.Insert(db.DefaultContext, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID})
|
||||||
|
|
||||||
|
// truncate action table and insert some actions
|
||||||
|
err = db.TruncateBeans(db.DefaultContext, &activities_model.Action{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = db.Insert(db.DefaultContext, &activities_model.Action{
|
||||||
|
OpType: activities_model.ActionCommentIssue,
|
||||||
|
CommentID: comment.ID,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = db.Insert(db.DefaultContext, &activities_model.Action{
|
||||||
|
OpType: activities_model.ActionCreateIssue,
|
||||||
|
RepoID: issue.RepoID,
|
||||||
|
Content: fmt.Sprintf("%d|content...", issue.Index),
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// assert that the actions exist, then delete them
|
||||||
|
unittest.AssertCount(t, &activities_model.Action{}, 2)
|
||||||
|
assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index))
|
||||||
|
unittest.AssertCount(t, &activities_model.Action{}, 0)
|
||||||
|
}
|
||||||
|
|
|
@ -248,7 +248,7 @@ func deleteIssue(ctx context.Context, issue *issues_model.Issue) error {
|
||||||
issue.MilestoneID, err)
|
issue.MilestoneID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := activities_model.DeleteIssueActions(ctx, issue.RepoID, issue.ID); err != nil {
|
if err := activities_model.DeleteIssueActions(ctx, issue.RepoID, issue.ID, issue.Index); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue