Skip to content

Commit e4b1ea6

Browse files
authored
Bypass MariaDB performance bug of the "IN" sub-query, fix incorrect IssueIndex (#26279)
Close #26277 Fix #26285
1 parent 24fbf4e commit e4b1ea6

File tree

3 files changed

+59
-9
lines changed

3 files changed

+59
-9
lines changed

models/activities/action.go

+24-8
Original file line numberDiff line numberDiff line change
@@ -685,18 +685,34 @@ func NotifyWatchersActions(acts []*Action) error {
685685
}
686686

687687
// DeleteIssueActions delete all actions related with issueID
688-
func DeleteIssueActions(ctx context.Context, repoID, issueID int64) error {
688+
func DeleteIssueActions(ctx context.Context, repoID, issueID, issueIndex int64) error {
689689
// delete actions assigned to this issue
690-
subQuery := builder.Select("`id`").
691-
From("`comment`").
692-
Where(builder.Eq{"`issue_id`": issueID})
693-
if _, err := db.GetEngine(ctx).In("comment_id", subQuery).Delete(&Action{}); err != nil {
694-
return err
690+
e := db.GetEngine(ctx)
691+
692+
// MariaDB has a performance bug: https://jira.mariadb.org/browse/MDEV-16289
693+
// so here it uses "DELETE ... WHERE IN" with pre-queried IDs.
694+
var lastCommentID int64
695+
commentIDs := make([]int64, 0, db.DefaultMaxInSize)
696+
for {
697+
commentIDs = commentIDs[:0]
698+
err := e.Select("`id`").Table(&issues_model.Comment{}).
699+
Where(builder.Eq{"issue_id": issueID}).And("`id` > ?", lastCommentID).
700+
OrderBy("`id`").Limit(db.DefaultMaxInSize).
701+
Find(&commentIDs)
702+
if err != nil {
703+
return err
704+
} else if len(commentIDs) == 0 {
705+
break
706+
} else if _, err = db.GetEngine(ctx).In("comment_id", commentIDs).Delete(&Action{}); err != nil {
707+
return err
708+
} else {
709+
lastCommentID = commentIDs[len(commentIDs)-1]
710+
}
695711
}
696712

697-
_, err := db.GetEngine(ctx).Table("action").Where("repo_id = ?", repoID).
713+
_, err := e.Where("repo_id = ?", repoID).
698714
In("op_type", ActionCreateIssue, ActionCreatePullRequest).
699-
Where("content LIKE ?", strconv.FormatInt(issueID, 10)+"|%").
715+
Where("content LIKE ?", strconv.FormatInt(issueIndex, 10)+"|%"). // "IssueIndex|content..."
700716
Delete(&Action{})
701717
return err
702718
}

models/activities/action_test.go

+34
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package activities_test
55

66
import (
7+
"fmt"
78
"path"
89
"testing"
910

@@ -284,3 +285,36 @@ func TestConsistencyUpdateAction(t *testing.T) {
284285
assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions))
285286
unittest.CheckConsistencyFor(t, &activities_model.Action{})
286287
}
288+
289+
func TestDeleteIssueActions(t *testing.T) {
290+
assert.NoError(t, unittest.PrepareTestDatabase())
291+
292+
// load an issue
293+
issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4})
294+
assert.NotEqualValues(t, issue.ID, issue.Index) // it needs to use different ID/Index to test the DeleteIssueActions to delete some actions by IssueIndex
295+
296+
// insert a comment
297+
err := db.Insert(db.DefaultContext, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID})
298+
assert.NoError(t, err)
299+
comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID})
300+
301+
// truncate action table and insert some actions
302+
err = db.TruncateBeans(db.DefaultContext, &activities_model.Action{})
303+
assert.NoError(t, err)
304+
err = db.Insert(db.DefaultContext, &activities_model.Action{
305+
OpType: activities_model.ActionCommentIssue,
306+
CommentID: comment.ID,
307+
})
308+
assert.NoError(t, err)
309+
err = db.Insert(db.DefaultContext, &activities_model.Action{
310+
OpType: activities_model.ActionCreateIssue,
311+
RepoID: issue.RepoID,
312+
Content: fmt.Sprintf("%d|content...", issue.Index),
313+
})
314+
assert.NoError(t, err)
315+
316+
// assert that the actions exist, then delete them
317+
unittest.AssertCount(t, &activities_model.Action{}, 2)
318+
assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index))
319+
unittest.AssertCount(t, &activities_model.Action{}, 0)
320+
}

services/issue/issue.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ func deleteIssue(ctx context.Context, issue *issues_model.Issue) error {
248248
issue.MilestoneID, err)
249249
}
250250

251-
if err := activities_model.DeleteIssueActions(ctx, issue.RepoID, issue.ID); err != nil {
251+
if err := activities_model.DeleteIssueActions(ctx, issue.RepoID, issue.ID, issue.Index); err != nil {
252252
return err
253253
}
254254

0 commit comments

Comments
 (0)