Skip to content

Commit 0751153

Browse files
authored
refactor issue indexer, add some testing and fix a bug (#6131)
* refactor issue indexer, add some testing and fix a bug * fix error copyright year on comment header * issues indexer package import keep consistent
1 parent eaf9ded commit 0751153

File tree

11 files changed

+231
-171
lines changed

11 files changed

+231
-171
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ coverage.all
6262
/integrations/pgsql.ini
6363
/integrations/mssql.ini
6464
/node_modules
65+
/modules/indexer/issues/indexers
6566

6667

6768
# Snapcraft

models/issue.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,11 @@ func getIssueIDsByRepoID(e Engine, repoID int64) ([]int64, error) {
12311231
return ids, err
12321232
}
12331233

1234+
// GetIssueIDsByRepoID returns all issue ids by repo id
1235+
func GetIssueIDsByRepoID(repoID int64) ([]int64, error) {
1236+
return getIssueIDsByRepoID(x, repoID)
1237+
}
1238+
12341239
// GetIssuesByIDs return issues with the given IDs.
12351240
func GetIssuesByIDs(issueIDs []int64) ([]*Issue, error) {
12361241
return getIssuesByIDs(x, issueIDs)

models/issue_indexer.go

Lines changed: 0 additions & 148 deletions
This file was deleted.

models/unit_tests.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ func MainTest(m *testing.M, pathToGiteaRoot string) {
4444
fatalTestError("Error creating test engine: %v\n", err)
4545
}
4646

47-
if err = InitIssueIndexer(); err != nil {
48-
fatalTestError("Error InitIssueIndexer: %v\n", err)
49-
}
50-
5147
setting.AppURL = "https://try.gitea.io/"
5248
setting.RunUser = "runuser"
5349
setting.SSH.Port = 3000

modules/indexer/issues/indexer.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44

55
package issues
66

7+
import (
8+
"fmt"
9+
10+
"code.gitea.io/gitea/models"
11+
"code.gitea.io/gitea/modules/log"
12+
"code.gitea.io/gitea/modules/setting"
13+
"code.gitea.io/gitea/modules/util"
14+
)
15+
716
// IndexerData data stored in the issue indexer
817
type IndexerData struct {
918
ID int64
@@ -34,3 +43,142 @@ type Indexer interface {
3443
Delete(ids ...int64) error
3544
Search(kw string, repoID int64, limit, start int) (*SearchResult, error)
3645
}
46+
47+
var (
48+
// issueIndexerUpdateQueue queue of issue ids to be updated
49+
issueIndexerUpdateQueue Queue
50+
issueIndexer Indexer
51+
)
52+
53+
// InitIssueIndexer initialize issue indexer, syncReindex is true then reindex until
54+
// all issue index done.
55+
func InitIssueIndexer(syncReindex bool) error {
56+
var populate bool
57+
switch setting.Indexer.IssueType {
58+
case "bleve":
59+
issueIndexer = NewBleveIndexer(setting.Indexer.IssuePath)
60+
exist, err := issueIndexer.Init()
61+
if err != nil {
62+
return err
63+
}
64+
populate = !exist
65+
default:
66+
return fmt.Errorf("unknow issue indexer type: %s", setting.Indexer.IssueType)
67+
}
68+
69+
var err error
70+
switch setting.Indexer.IssueIndexerQueueType {
71+
case setting.LevelQueueType:
72+
issueIndexerUpdateQueue, err = NewLevelQueue(
73+
issueIndexer,
74+
setting.Indexer.IssueIndexerQueueDir,
75+
setting.Indexer.IssueIndexerQueueBatchNumber)
76+
if err != nil {
77+
return err
78+
}
79+
case setting.ChannelQueueType:
80+
issueIndexerUpdateQueue = NewChannelQueue(issueIndexer, setting.Indexer.IssueIndexerQueueBatchNumber)
81+
default:
82+
return fmt.Errorf("Unsupported indexer queue type: %v", setting.Indexer.IssueIndexerQueueType)
83+
}
84+
85+
go issueIndexerUpdateQueue.Run()
86+
87+
if populate {
88+
if syncReindex {
89+
populateIssueIndexer()
90+
} else {
91+
go populateIssueIndexer()
92+
}
93+
}
94+
95+
return nil
96+
}
97+
98+
// populateIssueIndexer populate the issue indexer with issue data
99+
func populateIssueIndexer() {
100+
for page := 1; ; page++ {
101+
repos, _, err := models.SearchRepositoryByName(&models.SearchRepoOptions{
102+
Page: page,
103+
PageSize: models.RepositoryListDefaultPageSize,
104+
OrderBy: models.SearchOrderByID,
105+
Private: true,
106+
Collaborate: util.OptionalBoolFalse,
107+
})
108+
if err != nil {
109+
log.Error(4, "SearchRepositoryByName: %v", err)
110+
continue
111+
}
112+
if len(repos) == 0 {
113+
return
114+
}
115+
116+
for _, repo := range repos {
117+
is, err := models.Issues(&models.IssuesOptions{
118+
RepoIDs: []int64{repo.ID},
119+
IsClosed: util.OptionalBoolNone,
120+
IsPull: util.OptionalBoolNone,
121+
})
122+
if err != nil {
123+
log.Error(4, "Issues: %v", err)
124+
continue
125+
}
126+
if err = models.IssueList(is).LoadDiscussComments(); err != nil {
127+
log.Error(4, "LoadComments: %v", err)
128+
continue
129+
}
130+
for _, issue := range is {
131+
UpdateIssueIndexer(issue)
132+
}
133+
}
134+
}
135+
}
136+
137+
// UpdateIssueIndexer add/update an issue to the issue indexer
138+
func UpdateIssueIndexer(issue *models.Issue) {
139+
var comments []string
140+
for _, comment := range issue.Comments {
141+
if comment.Type == models.CommentTypeComment {
142+
comments = append(comments, comment.Content)
143+
}
144+
}
145+
issueIndexerUpdateQueue.Push(&IndexerData{
146+
ID: issue.ID,
147+
RepoID: issue.RepoID,
148+
Title: issue.Title,
149+
Content: issue.Content,
150+
Comments: comments,
151+
})
152+
}
153+
154+
// DeleteRepoIssueIndexer deletes repo's all issues indexes
155+
func DeleteRepoIssueIndexer(repo *models.Repository) {
156+
var ids []int64
157+
ids, err := models.GetIssueIDsByRepoID(repo.ID)
158+
if err != nil {
159+
log.Error(4, "getIssueIDsByRepoID failed: %v", err)
160+
return
161+
}
162+
163+
if len(ids) <= 0 {
164+
return
165+
}
166+
167+
issueIndexerUpdateQueue.Push(&IndexerData{
168+
IDs: ids,
169+
IsDelete: true,
170+
})
171+
}
172+
173+
// SearchIssuesByKeyword search issue ids by keywords and repo id
174+
func SearchIssuesByKeyword(repoID int64, keyword string) ([]int64, error) {
175+
var issueIDs []int64
176+
res, err := issueIndexer.Search(keyword, repoID, 1000, 0)
177+
if err != nil {
178+
return nil, err
179+
}
180+
for _, r := range res.Hits {
181+
issueIDs = append(issueIDs, r.ID)
182+
}
183+
return issueIDs, nil
184+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2019 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package issues
6+
7+
import (
8+
"fmt"
9+
"os"
10+
"path/filepath"
11+
"testing"
12+
"time"
13+
14+
"code.gitea.io/gitea/models"
15+
"code.gitea.io/gitea/modules/setting"
16+
17+
"github.com/stretchr/testify/assert"
18+
)
19+
20+
func fatalTestError(fmtStr string, args ...interface{}) {
21+
fmt.Fprintf(os.Stderr, fmtStr, args...)
22+
os.Exit(1)
23+
}
24+
25+
func TestMain(m *testing.M) {
26+
models.MainTest(m, filepath.Join("..", "..", ".."))
27+
}
28+
29+
func TestSearchIssues(t *testing.T) {
30+
assert.NoError(t, models.PrepareTestDatabase())
31+
32+
os.RemoveAll(setting.Indexer.IssueIndexerQueueDir)
33+
os.RemoveAll(setting.Indexer.IssuePath)
34+
if err := InitIssueIndexer(true); err != nil {
35+
fatalTestError("Error InitIssueIndexer: %v\n", err)
36+
}
37+
38+
time.Sleep(10 * time.Second)
39+
40+
ids, err := SearchIssuesByKeyword(1, "issue2")
41+
assert.NoError(t, err)
42+
assert.EqualValues(t, []int64{2}, ids)
43+
44+
ids, err = SearchIssuesByKeyword(1, "first")
45+
assert.NoError(t, err)
46+
assert.EqualValues(t, []int64{1}, ids)
47+
48+
ids, err = SearchIssuesByKeyword(1, "for")
49+
assert.NoError(t, err)
50+
assert.EqualValues(t, []int64{1, 2, 3, 5}, ids)
51+
}

0 commit comments

Comments
 (0)