diff options
author | zeripath <art27@cantab.net> | 2019-12-24 07:26:34 +0000 |
---|---|---|
committer | Lunny Xiao <xiaolunwen@gmail.com> | 2019-12-24 15:26:34 +0800 |
commit | 30181d459da79ef57c58bb3789e2ce7130d08b77 (patch) | |
tree | 7bb0b7bca82561f47d785faebcef2a9fdc581ee7 /modules/indexer/code/wrapped.go | |
parent | 34688e1db37cebe76df73ab47bc57764821c787c (diff) | |
download | gitea-30181d459da79ef57c58bb3789e2ce7130d08b77.tar.gz gitea-30181d459da79ef57c58bb3789e2ce7130d08b77.zip |
Wrap the code indexer (#9476)
* Wrap the code indexer
In order to prevent a data race in the code indexer it must be wrapped
with a holder otherwise it is possible to Search/Index on an
incompletely initialised indexer, and search will fail with a nil
pointer until the repository indexer is initialised.
Further a completely initialised repository indexer should not be closed
until Termination otherwise actions in Hammer/Shutdown phases could
block or be lost.
Finally, there is a complex dance of shutdown etiquette should the index
initialisation fail. This PR restores that.
* Always return err if closed whilst waiting
Co-authored-by: techknowlogick <matti@mdranta.net>
Diffstat (limited to 'modules/indexer/code/wrapped.go')
-rw-r--r-- | modules/indexer/code/wrapped.go | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/modules/indexer/code/wrapped.go b/modules/indexer/code/wrapped.go new file mode 100644 index 0000000000..6a20883989 --- /dev/null +++ b/modules/indexer/code/wrapped.go @@ -0,0 +1,94 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package code + +import ( + "fmt" + "sync" +) + +var ( + indexer = newWrappedIndexer() +) + +// ErrWrappedIndexerClosed is the error returned if the indexer was closed before it was ready +var ErrWrappedIndexerClosed = fmt.Errorf("Indexer closed before ready") + +type wrappedIndexer struct { + internal Indexer + lock sync.RWMutex + cond *sync.Cond + closed bool +} + +func newWrappedIndexer() *wrappedIndexer { + w := &wrappedIndexer{} + w.cond = sync.NewCond(w.lock.RLocker()) + return w +} + +func (w *wrappedIndexer) set(indexer Indexer) { + w.lock.Lock() + defer w.lock.Unlock() + if w.closed { + // Too late! + indexer.Close() + } + w.internal = indexer + w.cond.Broadcast() +} + +func (w *wrappedIndexer) get() (Indexer, error) { + w.lock.RLock() + defer w.lock.RUnlock() + if w.internal == nil { + if w.closed { + return nil, ErrWrappedIndexerClosed + } + w.cond.Wait() + if w.closed { + return nil, ErrWrappedIndexerClosed + } + } + return w.internal, nil +} + +func (w *wrappedIndexer) Index(repoID int64) error { + indexer, err := w.get() + if err != nil { + return err + } + return indexer.Index(repoID) +} + +func (w *wrappedIndexer) Delete(repoID int64) error { + indexer, err := w.get() + if err != nil { + return err + } + return indexer.Delete(repoID) +} + +func (w *wrappedIndexer) Search(repoIDs []int64, keyword string, page, pageSize int) (int64, []*SearchResult, error) { + indexer, err := w.get() + if err != nil { + return 0, nil, err + } + return indexer.Search(repoIDs, keyword, page, pageSize) + +} + +func (w *wrappedIndexer) Close() { + w.lock.Lock() + defer w.lock.Unlock() + if w.closed { + return + } + w.closed = true + w.cond.Broadcast() + if w.internal != nil { + w.internal.Close() + } +} |