diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2019-02-19 22:39:39 +0800 |
---|---|---|
committer | techknowlogick <matti@mdranta.net> | 2019-02-19 09:39:39 -0500 |
commit | 830ae614560b0c504c00d693b63d9889bac1a2d8 (patch) | |
tree | 5fd933f8124f4dd30d0215def2a7bcc0181573be /models | |
parent | 094263db4d9f1b53c4b4c021005eec07baddd253 (diff) | |
download | gitea-830ae614560b0c504c00d693b63d9889bac1a2d8.tar.gz gitea-830ae614560b0c504c00d693b63d9889bac1a2d8.zip |
Refactor issue indexer (#5363)
Diffstat (limited to 'models')
-rw-r--r-- | models/issue.go | 18 | ||||
-rw-r--r-- | models/issue_comment.go | 2 | ||||
-rw-r--r-- | models/issue_indexer.go | 166 | ||||
-rw-r--r-- | models/issue_list.go | 16 | ||||
-rw-r--r-- | models/models.go | 14 | ||||
-rw-r--r-- | models/unit_tests.go | 4 |
6 files changed, 126 insertions, 94 deletions
diff --git a/models/issue.go b/models/issue.go index 8ce8658fee..835c6cf9fc 100644 --- a/models/issue.go +++ b/models/issue.go @@ -183,12 +183,21 @@ func (issue *Issue) LoadPullRequest() error { } func (issue *Issue) loadComments(e Engine) (err error) { + return issue.loadCommentsByType(e, CommentTypeUnknown) +} + +// LoadDiscussComments loads discuss comments +func (issue *Issue) LoadDiscussComments() error { + return issue.loadCommentsByType(x, CommentTypeComment) +} + +func (issue *Issue) loadCommentsByType(e Engine, tp CommentType) (err error) { if issue.Comments != nil { return nil } issue.Comments, err = findComments(e, FindCommentsOptions{ IssueID: issue.ID, - Type: CommentTypeUnknown, + Type: tp, }) return err } @@ -681,7 +690,6 @@ func updateIssueCols(e Engine, issue *Issue, cols ...string) error { if _, err := e.ID(issue.ID).Cols(cols...).Update(issue); err != nil { return err } - UpdateIssueIndexerCols(issue.ID, cols...) return nil } @@ -1217,6 +1225,12 @@ func getIssuesByIDs(e Engine, issueIDs []int64) ([]*Issue, error) { return issues, e.In("id", issueIDs).Find(&issues) } +func getIssueIDsByRepoID(e Engine, repoID int64) ([]int64, error) { + var ids = make([]int64, 0, 10) + err := e.Table("issue").Where("repo_id = ?", repoID).Find(&ids) + return ids, err +} + // GetIssuesByIDs return issues with the given IDs. func GetIssuesByIDs(issueIDs []int64) ([]*Issue, error) { return getIssuesByIDs(x, issueIDs) diff --git a/models/issue_comment.go b/models/issue_comment.go index 1b02918cb7..c3654460ff 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -1035,6 +1035,7 @@ func UpdateComment(doer *User, c *Comment, oldContent string) error { if err := c.LoadIssue(); err != nil { return err } + if err := c.Issue.LoadAttributes(); err != nil { return err } @@ -1093,6 +1094,7 @@ func DeleteComment(doer *User, comment *Comment) error { if err := comment.LoadIssue(); err != nil { return err } + if err := comment.Issue.LoadAttributes(); err != nil { return err } diff --git a/models/issue_indexer.go b/models/issue_indexer.go index 48c0b9f246..d02b7164da 100644 --- a/models/issue_indexer.go +++ b/models/issue_indexer.go @@ -7,25 +7,60 @@ package models import ( "fmt" - "code.gitea.io/gitea/modules/indexer" + "code.gitea.io/gitea/modules/indexer/issues" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) -// issueIndexerUpdateQueue queue of issue ids to be updated -var issueIndexerUpdateQueue chan int64 +var ( + // issueIndexerUpdateQueue queue of issue ids to be updated + issueIndexerUpdateQueue issues.Queue + issueIndexer issues.Indexer +) // InitIssueIndexer initialize issue indexer -func InitIssueIndexer() { - indexer.InitIssueIndexer(populateIssueIndexer) - issueIndexerUpdateQueue = make(chan int64, setting.Indexer.UpdateQueueLength) - go processIssueIndexerUpdateQueue() +func InitIssueIndexer() error { + var populate bool + switch setting.Indexer.IssueType { + case "bleve": + issueIndexer = issues.NewBleveIndexer(setting.Indexer.IssuePath) + exist, err := issueIndexer.Init() + if err != nil { + return err + } + populate = !exist + default: + return fmt.Errorf("unknow issue indexer type: %s", setting.Indexer.IssueType) + } + + var err error + switch setting.Indexer.IssueIndexerQueueType { + case setting.LevelQueueType: + issueIndexerUpdateQueue, err = issues.NewLevelQueue( + issueIndexer, + setting.Indexer.IssueIndexerQueueDir, + setting.Indexer.IssueIndexerQueueBatchNumber) + if err != nil { + return err + } + case setting.ChannelQueueType: + issueIndexerUpdateQueue = issues.NewChannelQueue(issueIndexer, setting.Indexer.IssueIndexerQueueBatchNumber) + default: + return fmt.Errorf("Unsupported indexer queue type: %v", setting.Indexer.IssueIndexerQueueType) + } + + go issueIndexerUpdateQueue.Run() + + if populate { + go populateIssueIndexer() + } + + return nil } // populateIssueIndexer populate the issue indexer with issue data -func populateIssueIndexer() error { - batch := indexer.IssueIndexerBatch() +func populateIssueIndexer() { for page := 1; ; page++ { repos, _, err := SearchRepositoryByName(&SearchRepoOptions{ Page: page, @@ -35,98 +70,79 @@ func populateIssueIndexer() error { Collaborate: util.OptionalBoolFalse, }) if err != nil { - return fmt.Errorf("Repositories: %v", err) + log.Error(4, "SearchRepositoryByName: %v", err) + continue } if len(repos) == 0 { - return batch.Flush() + return } + for _, repo := range repos { - issues, err := Issues(&IssuesOptions{ + is, err := Issues(&IssuesOptions{ RepoIDs: []int64{repo.ID}, IsClosed: util.OptionalBoolNone, IsPull: util.OptionalBoolNone, }) if err != nil { - return err + log.Error(4, "Issues: %v", err) + continue } - if err = IssueList(issues).LoadComments(); err != nil { - return err + if err = IssueList(is).LoadDiscussComments(); err != nil { + log.Error(4, "LoadComments: %v", err) + continue } - for _, issue := range issues { - if err := issue.update().AddToFlushingBatch(batch); err != nil { - return err - } + for _, issue := range is { + UpdateIssueIndexer(issue) } } } } -func processIssueIndexerUpdateQueue() { - batch := indexer.IssueIndexerBatch() - for { - var issueID int64 - select { - case issueID = <-issueIndexerUpdateQueue: - default: - // flush whatever updates we currently have, since we - // might have to wait a while - if err := batch.Flush(); err != nil { - log.Error(4, "IssueIndexer: %v", err) - } - issueID = <-issueIndexerUpdateQueue - } - issue, err := GetIssueByID(issueID) - if err != nil { - log.Error(4, "GetIssueByID: %v", err) - } else if err = issue.update().AddToFlushingBatch(batch); err != nil { - log.Error(4, "IssueIndexer: %v", err) - } - } -} - -func (issue *Issue) update() indexer.IssueIndexerUpdate { - comments := make([]string, 0, 5) +// UpdateIssueIndexer add/update an issue to the issue indexer +func UpdateIssueIndexer(issue *Issue) { + var comments []string for _, comment := range issue.Comments { if comment.Type == CommentTypeComment { comments = append(comments, comment.Content) } } - return indexer.IssueIndexerUpdate{ - IssueID: issue.ID, - Data: &indexer.IssueIndexerData{ - RepoID: issue.RepoID, - Title: issue.Title, - Content: issue.Content, - Comments: comments, - }, - } + issueIndexerUpdateQueue.Push(&issues.IndexerData{ + ID: issue.ID, + RepoID: issue.RepoID, + Title: issue.Title, + Content: issue.Content, + Comments: comments, + }) } -// updateNeededCols whether a change to the specified columns requires updating -// the issue indexer -func updateNeededCols(cols []string) bool { - for _, col := range cols { - switch col { - case "name", "content": - return true - } +// DeleteRepoIssueIndexer deletes repo's all issues indexes +func DeleteRepoIssueIndexer(repo *Repository) { + var ids []int64 + ids, err := getIssueIDsByRepoID(x, repo.ID) + if err != nil { + log.Error(4, "getIssueIDsByRepoID failed: %v", err) + return + } + + if len(ids) <= 0 { + return } - return false -} -// UpdateIssueIndexerCols update an issue in the issue indexer, given changes -// to the specified columns -func UpdateIssueIndexerCols(issueID int64, cols ...string) { - updateNeededCols(cols) + issueIndexerUpdateQueue.Push(&issues.IndexerData{ + IDs: ids, + IsDelete: true, + }) } -// UpdateIssueIndexer add/update an issue to the issue indexer -func UpdateIssueIndexer(issueID int64) { - select { - case issueIndexerUpdateQueue <- issueID: - default: - go func() { - issueIndexerUpdateQueue <- issueID - }() +// SearchIssuesByKeyword search issue ids by keywords and repo id +func SearchIssuesByKeyword(repoID int64, keyword string) ([]int64, error) { + var issueIDs []int64 + res, err := issueIndexer.Search(keyword, repoID, 1000, 0) + if err != nil { + return nil, err + } + for _, r := range res.Hits { + issueIDs = append(issueIDs, r.ID) } + return issueIDs, nil } diff --git a/models/issue_list.go b/models/issue_list.go index 7e4c264643..a1aab488fc 100644 --- a/models/issue_list.go +++ b/models/issue_list.go @@ -4,7 +4,11 @@ package models -import "fmt" +import ( + "fmt" + + "github.com/go-xorm/builder" +) // IssueList defines a list of issues type IssueList []*Issue @@ -338,7 +342,7 @@ func (issues IssueList) loadAttachments(e Engine) (err error) { return nil } -func (issues IssueList) loadComments(e Engine) (err error) { +func (issues IssueList) loadComments(e Engine, cond builder.Cond) (err error) { if len(issues) == 0 { return nil } @@ -354,6 +358,7 @@ func (issues IssueList) loadComments(e Engine) (err error) { rows, err := e.Table("comment"). Join("INNER", "issue", "issue.id = comment.issue_id"). In("issue.id", issuesIDs[:limit]). + Where(cond). Rows(new(Comment)) if err != nil { return err @@ -479,5 +484,10 @@ func (issues IssueList) LoadAttachments() error { // LoadComments loads comments func (issues IssueList) LoadComments() error { - return issues.loadComments(x) + return issues.loadComments(x, builder.NewCond()) +} + +// LoadDiscussComments loads discuss comments +func (issues IssueList) LoadDiscussComments() error { + return issues.loadComments(x, builder.Eq{"comment.type": CommentTypeComment}) } diff --git a/models/models.go b/models/models.go index daef7c07e8..b8fe588b5a 100644 --- a/models/models.go +++ b/models/models.go @@ -12,7 +12,6 @@ import ( "net/url" "os" "path" - "path/filepath" "strings" "code.gitea.io/gitea/modules/log" @@ -158,19 +157,6 @@ func LoadConfigs() { DbCfg.SSLMode = sec.Key("SSL_MODE").MustString("disable") DbCfg.Path = sec.Key("PATH").MustString("data/gitea.db") DbCfg.Timeout = sec.Key("SQLITE_TIMEOUT").MustInt(500) - - sec = setting.Cfg.Section("indexer") - setting.Indexer.IssuePath = sec.Key("ISSUE_INDEXER_PATH").MustString(path.Join(setting.AppDataPath, "indexers/issues.bleve")) - if !filepath.IsAbs(setting.Indexer.IssuePath) { - setting.Indexer.IssuePath = path.Join(setting.AppWorkPath, setting.Indexer.IssuePath) - } - setting.Indexer.RepoIndexerEnabled = sec.Key("REPO_INDEXER_ENABLED").MustBool(false) - setting.Indexer.RepoPath = sec.Key("REPO_INDEXER_PATH").MustString(path.Join(setting.AppDataPath, "indexers/repos.bleve")) - if !filepath.IsAbs(setting.Indexer.RepoPath) { - setting.Indexer.RepoPath = path.Join(setting.AppWorkPath, setting.Indexer.RepoPath) - } - setting.Indexer.UpdateQueueLength = sec.Key("UPDATE_BUFFER_LEN").MustInt(20) - setting.Indexer.MaxIndexerFileSize = sec.Key("MAX_FILE_SIZE").MustInt64(1024 * 1024) } // parsePostgreSQLHostPort parses given input in various forms defined in diff --git a/models/unit_tests.go b/models/unit_tests.go index 28cd91215e..f87dd7ee96 100644 --- a/models/unit_tests.go +++ b/models/unit_tests.go @@ -44,6 +44,10 @@ func MainTest(m *testing.M, pathToGiteaRoot string) { fatalTestError("Error creating test engine: %v\n", err) } + if err = InitIssueIndexer(); err != nil { + fatalTestError("Error InitIssueIndexer: %v\n", err) + } + setting.AppURL = "https://try.gitea.io/" setting.RunUser = "runuser" setting.SSH.Port = 3000 |