mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Search: Downgrade Bluge, refactor code (#51560)
Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
parent
16f9830fc3
commit
f233a74b70
5
go.mod
5
go.mod
@ -240,8 +240,7 @@ require (
|
|||||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.4.0
|
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.4.0
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.17
|
github.com/Azure/go-autorest/autorest/adal v0.9.17
|
||||||
github.com/armon/go-radix v1.0.0
|
github.com/armon/go-radix v1.0.0
|
||||||
github.com/blugelabs/bluge v0.2.1
|
github.com/blugelabs/bluge v0.1.9
|
||||||
github.com/blugelabs/bluge_segment_api v0.2.0
|
|
||||||
github.com/getkin/kin-openapi v0.94.0
|
github.com/getkin/kin-openapi v0.94.0
|
||||||
github.com/golang-migrate/migrate/v4 v4.7.0
|
github.com/golang-migrate/migrate/v4 v4.7.0
|
||||||
github.com/grafana/dskit v0.0.0-20211011144203-3a88ec0b675f
|
github.com/grafana/dskit v0.0.0-20211011144203-3a88ec0b675f
|
||||||
@ -256,6 +255,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.100.2 // indirect
|
cloud.google.com/go v0.100.2 // indirect
|
||||||
github.com/armon/go-metrics v0.3.10 // indirect
|
github.com/armon/go-metrics v0.3.10 // indirect
|
||||||
|
github.com/blugelabs/bluge_segment_api v0.2.0 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/gosimple/unidecode v1.0.1 // indirect
|
github.com/gosimple/unidecode v1.0.1 // indirect
|
||||||
@ -282,7 +282,6 @@ require (
|
|||||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||||
github.com/blevesearch/vellum v1.0.7 // indirect
|
github.com/blevesearch/vellum v1.0.7 // indirect
|
||||||
github.com/blugelabs/ice v1.0.0 // indirect
|
github.com/blugelabs/ice v1.0.0 // indirect
|
||||||
github.com/blugelabs/ice/v2 v2.0.1 // indirect
|
|
||||||
github.com/caio/go-tdigest v3.1.0+incompatible // indirect
|
github.com/caio/go-tdigest v3.1.0+incompatible // indirect
|
||||||
github.com/chromedp/cdproto v0.0.0-20220208224320-6efb837e6bc2 // indirect
|
github.com/chromedp/cdproto v0.0.0-20220208224320-6efb837e6bc2 // indirect
|
||||||
github.com/containerd/containerd v1.6.6 // indirect
|
github.com/containerd/containerd v1.6.6 // indirect
|
||||||
|
7
go.sum
7
go.sum
@ -435,14 +435,13 @@ github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulN
|
|||||||
github.com/blevesearch/vellum v1.0.5/go.mod h1:atE0EH3fvk43zzS7t1YNdNC7DbmcC3uz+eMD5xZ2OyQ=
|
github.com/blevesearch/vellum v1.0.5/go.mod h1:atE0EH3fvk43zzS7t1YNdNC7DbmcC3uz+eMD5xZ2OyQ=
|
||||||
github.com/blevesearch/vellum v1.0.7 h1:+vn8rfyCRHxKVRgDLeR0FAXej2+6mEb5Q15aQE/XESQ=
|
github.com/blevesearch/vellum v1.0.7 h1:+vn8rfyCRHxKVRgDLeR0FAXej2+6mEb5Q15aQE/XESQ=
|
||||||
github.com/blevesearch/vellum v1.0.7/go.mod h1:doBZpmRhwTsASB4QdUZANlJvqVAUdUyX0ZK7QJCTeBE=
|
github.com/blevesearch/vellum v1.0.7/go.mod h1:doBZpmRhwTsASB4QdUZANlJvqVAUdUyX0ZK7QJCTeBE=
|
||||||
github.com/blugelabs/bluge v0.2.1 h1:lgd6IhAAIDoq6my9HQOwk3p6xqJBmR49+lpFmpeFHgU=
|
github.com/blugelabs/bluge v0.1.9 h1:bPgXlcsWugrXNjzeoLdOnvfJpHsyODKpYaAndayl/SM=
|
||||||
github.com/blugelabs/bluge v0.2.1/go.mod h1:am1LU9jS8dZgWkRzkGLQN3757EgMs3upWrU2fdN9foE=
|
github.com/blugelabs/bluge v0.1.9/go.mod h1:5d7LktUkQgvbh5Bmi6tPWtvo4+6uRTm6gAwP+5z6FqQ=
|
||||||
github.com/blugelabs/bluge_segment_api v0.2.0 h1:cCX1Y2y8v0LZ7+EEJ6gH7dW6TtVTW4RhG0vp3R+N2Lo=
|
github.com/blugelabs/bluge_segment_api v0.2.0 h1:cCX1Y2y8v0LZ7+EEJ6gH7dW6TtVTW4RhG0vp3R+N2Lo=
|
||||||
github.com/blugelabs/bluge_segment_api v0.2.0/go.mod h1:95XA+ZXfRj/IXADm7gZ+iTcWOJPg5jQTY1EReIzl3LA=
|
github.com/blugelabs/bluge_segment_api v0.2.0/go.mod h1:95XA+ZXfRj/IXADm7gZ+iTcWOJPg5jQTY1EReIzl3LA=
|
||||||
|
github.com/blugelabs/ice v0.2.0/go.mod h1:7foiDf4V83FIYYnGh2LOoRWsbNoCqAAMNgKn879Iyu0=
|
||||||
github.com/blugelabs/ice v1.0.0 h1:um7wf9e6jbkTVCrOyQq3tKK43fBMOvLUYxbj3Qtc4eo=
|
github.com/blugelabs/ice v1.0.0 h1:um7wf9e6jbkTVCrOyQq3tKK43fBMOvLUYxbj3Qtc4eo=
|
||||||
github.com/blugelabs/ice v1.0.0/go.mod h1:gNfFPk5zM+yxJROhthxhVQYjpBO9amuxWXJQ2Lo+IbQ=
|
github.com/blugelabs/ice v1.0.0/go.mod h1:gNfFPk5zM+yxJROhthxhVQYjpBO9amuxWXJQ2Lo+IbQ=
|
||||||
github.com/blugelabs/ice/v2 v2.0.1 h1:mzHbntLjk2v7eDRgoXCgzOsPKN1Tenu9Svo6l9cTLS4=
|
|
||||||
github.com/blugelabs/ice/v2 v2.0.1/go.mod h1:QxAWSPNwZwsIqS25c3lbIPFQrVvT1sphf5x5DfMLH5M=
|
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
||||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||||
|
@ -34,10 +34,10 @@ const (
|
|||||||
DocumentFieldUpdatedAt = "updated_at"
|
DocumentFieldUpdatedAt = "updated_at"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initIndex(dashboards []dashboard, logger log.Logger, extendDoc ExtendDashboardFunc) (*bluge.Reader, *bluge.Writer, error) {
|
func initOrgIndex(dashboards []dashboard, logger log.Logger, extendDoc ExtendDashboardFunc) (*orgIndex, error) {
|
||||||
writer, err := bluge.OpenWriter(bluge.InMemoryOnlyConfig())
|
dashboardWriter, err := bluge.OpenWriter(bluge.InMemoryOnlyConfig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("error opening writer: %v", err)
|
return nil, fmt.Errorf("error opening writer: %v", err)
|
||||||
}
|
}
|
||||||
// Not closing Writer here since we use it later while processing dashboard change events.
|
// Not closing Writer here since we use it later while processing dashboard change events.
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ func initIndex(dashboards []dashboard, logger log.Logger, extendDoc ExtendDashbo
|
|||||||
// In order to reduce memory usage while initial indexing we are limiting
|
// In order to reduce memory usage while initial indexing we are limiting
|
||||||
// the size of batch here.
|
// the size of batch here.
|
||||||
docsInBatch := 0
|
docsInBatch := 0
|
||||||
maxBatchSize := 300
|
maxBatchSize := 100
|
||||||
|
|
||||||
flushIfRequired := func(force bool) error {
|
flushIfRequired := func(force bool) error {
|
||||||
docsInBatch++
|
docsInBatch++
|
||||||
@ -57,7 +57,7 @@ func initIndex(dashboards []dashboard, logger log.Logger, extendDoc ExtendDashbo
|
|||||||
if !needFlush {
|
if !needFlush {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err := writer.Batch(batch)
|
err := dashboardWriter.Batch(batch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -74,11 +74,11 @@ func initIndex(dashboards []dashboard, logger log.Logger, extendDoc ExtendDashbo
|
|||||||
}
|
}
|
||||||
doc := getFolderDashboardDoc(dash)
|
doc := getFolderDashboardDoc(dash)
|
||||||
if err := extendDoc(dash.uid, doc); err != nil {
|
if err := extendDoc(dash.uid, doc); err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
batch.Insert(doc)
|
batch.Insert(doc)
|
||||||
if err := flushIfRequired(false); err != nil {
|
if err := flushIfRequired(false); err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
uid := dash.uid
|
uid := dash.uid
|
||||||
if uid == "" {
|
if uid == "" {
|
||||||
@ -96,11 +96,11 @@ func initIndex(dashboards []dashboard, logger log.Logger, extendDoc ExtendDashbo
|
|||||||
location := folderUID
|
location := folderUID
|
||||||
doc := getNonFolderDashboardDoc(dash, location)
|
doc := getNonFolderDashboardDoc(dash, location)
|
||||||
if err := extendDoc(dash.uid, doc); err != nil {
|
if err := extendDoc(dash.uid, doc); err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
batch.Insert(doc)
|
batch.Insert(doc)
|
||||||
if err := flushIfRequired(false); err != nil {
|
if err := flushIfRequired(false); err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index each panel in dashboard.
|
// Index each panel in dashboard.
|
||||||
@ -109,25 +109,27 @@ func initIndex(dashboards []dashboard, logger log.Logger, extendDoc ExtendDashbo
|
|||||||
}
|
}
|
||||||
location += dash.uid
|
location += dash.uid
|
||||||
docs := getDashboardPanelDocs(dash, location)
|
docs := getDashboardPanelDocs(dash, location)
|
||||||
|
|
||||||
for _, panelDoc := range docs {
|
for _, panelDoc := range docs {
|
||||||
batch.Insert(panelDoc)
|
batch.Insert(panelDoc)
|
||||||
if err := flushIfRequired(false); err != nil {
|
if err := flushIfRequired(false); err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flush docs in batch with force as we are in the end.
|
||||||
if err := flushIfRequired(true); err != nil {
|
if err := flushIfRequired(true); err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("Finish inserting docs into index", "elapsed", time.Since(label))
|
logger.Info("Finish inserting docs into index", "elapsed", time.Since(label))
|
||||||
|
|
||||||
reader, err := writer.Reader()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info("Finish building index", "totalElapsed", time.Since(start))
|
logger.Info("Finish building index", "totalElapsed", time.Since(start))
|
||||||
return reader, writer, err
|
return &orgIndex{
|
||||||
|
writers: map[indexType]*bluge.Writer{
|
||||||
|
indexTypeDashboard: dashboardWriter,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFolderDashboardDoc(dash dashboard) *bluge.Document {
|
func getFolderDashboardDoc(dash dashboard) *bluge.Document {
|
||||||
@ -244,8 +246,15 @@ func newSearchDocument(uid string, name string, descr string, url string) *bluge
|
|||||||
return doc
|
return doc
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDashboardPanelIDs(reader *bluge.Reader, panelLocation string) ([]string, error) {
|
func getDashboardPanelIDs(index *orgIndex, panelLocation string) ([]string, error) {
|
||||||
var panelIDs []string
|
var panelIDs []string
|
||||||
|
|
||||||
|
reader, cancel, err := index.readerForIndex(indexTypeDashboard)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
fullQuery := bluge.NewBooleanQuery()
|
fullQuery := bluge.NewBooleanQuery()
|
||||||
fullQuery.AddMust(bluge.NewTermQuery(panelLocation).SetField(documentFieldLocation))
|
fullQuery.AddMust(bluge.NewTermQuery(panelLocation).SetField(documentFieldLocation))
|
||||||
fullQuery.AddMust(bluge.NewTermQuery(string(entityKindPanel)).SetField(documentFieldKind))
|
fullQuery.AddMust(bluge.NewTermQuery(string(entityKindPanel)).SetField(documentFieldKind))
|
||||||
@ -272,14 +281,21 @@ func getDashboardPanelIDs(reader *bluge.Reader, panelLocation string) ([]string,
|
|||||||
return panelIDs, err
|
return panelIDs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDocsIDsByLocationPrefix(reader *bluge.Reader, prefix string) ([]string, error) {
|
func getDocsIDsByLocationPrefix(index *orgIndex, prefix string) ([]string, error) {
|
||||||
var ids []string
|
var ids []string
|
||||||
|
|
||||||
|
reader, cancel, err := index.readerForIndex(indexTypeDashboard)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting reader: %w", err)
|
||||||
|
}
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
fullQuery := bluge.NewBooleanQuery()
|
fullQuery := bluge.NewBooleanQuery()
|
||||||
fullQuery.AddMust(bluge.NewPrefixQuery(prefix).SetField(documentFieldLocation))
|
fullQuery.AddMust(bluge.NewPrefixQuery(prefix).SetField(documentFieldLocation))
|
||||||
req := bluge.NewAllMatches(fullQuery)
|
req := bluge.NewAllMatches(fullQuery)
|
||||||
documentMatchIterator, err := reader.Search(context.Background(), req)
|
documentMatchIterator, err := reader.Search(context.Background(), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("error search: %w", err)
|
||||||
}
|
}
|
||||||
match, err := documentMatchIterator.Next()
|
match, err := documentMatchIterator.Next()
|
||||||
for err == nil && match != nil {
|
for err == nil && match != nil {
|
||||||
@ -299,9 +315,16 @@ func getDocsIDsByLocationPrefix(reader *bluge.Reader, prefix string) ([]string,
|
|||||||
return ids, err
|
return ids, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDashboardLocation(reader *bluge.Reader, dashboardUID string) (string, bool, error) {
|
func getDashboardLocation(index *orgIndex, dashboardUID string) (string, bool, error) {
|
||||||
var dashboardLocation string
|
var dashboardLocation string
|
||||||
var found bool
|
var found bool
|
||||||
|
|
||||||
|
reader, cancel, err := index.readerForIndex(indexTypeDashboard)
|
||||||
|
if err != nil {
|
||||||
|
return "", false, err
|
||||||
|
}
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
fullQuery := bluge.NewBooleanQuery()
|
fullQuery := bluge.NewBooleanQuery()
|
||||||
fullQuery.AddMust(bluge.NewTermQuery(dashboardUID).SetField(documentFieldUID))
|
fullQuery.AddMust(bluge.NewTermQuery(dashboardUID).SetField(documentFieldUID))
|
||||||
fullQuery.AddMust(bluge.NewTermQuery(string(entityKindDashboard)).SetField(documentFieldKind))
|
fullQuery.AddMust(bluge.NewTermQuery(string(entityKindDashboard)).SetField(documentFieldKind))
|
||||||
@ -334,7 +357,7 @@ func getDashboardLocation(reader *bluge.Reader, dashboardUID string) (string, bo
|
|||||||
func doSearchQuery(
|
func doSearchQuery(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger log.Logger,
|
logger log.Logger,
|
||||||
reader *bluge.Reader,
|
index *orgIndex,
|
||||||
filter ResourceFilter,
|
filter ResourceFilter,
|
||||||
q DashboardQuery,
|
q DashboardQuery,
|
||||||
extender QueryExtender,
|
extender QueryExtender,
|
||||||
@ -343,6 +366,14 @@ func doSearchQuery(
|
|||||||
response := &backend.DataResponse{}
|
response := &backend.DataResponse{}
|
||||||
header := &customMeta{}
|
header := &customMeta{}
|
||||||
|
|
||||||
|
reader, cancel, err := index.readerForIndex(indexTypeDashboard)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("error getting reader for dashboard index: %v", err)
|
||||||
|
response.Error = err
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
hasConstraints := false
|
hasConstraints := false
|
||||||
fullQuery := bluge.NewBooleanQuery()
|
fullQuery := bluge.NewBooleanQuery()
|
||||||
fullQuery.AddMust(newPermissionFilter(filter, logger))
|
fullQuery.AddMust(newPermissionFilter(filter, logger))
|
||||||
|
@ -59,11 +59,32 @@ type buildSignal struct {
|
|||||||
done chan error
|
done chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
type dashboardIndex struct {
|
type orgIndex struct {
|
||||||
|
writers map[indexType]*bluge.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
type indexType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
indexTypeDashboard indexType = "dashboard"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i *orgIndex) writerForIndex(idxType indexType) *bluge.Writer {
|
||||||
|
return i.writers[idxType]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *orgIndex) readerForIndex(idxType indexType) (*bluge.Reader, func(), error) {
|
||||||
|
reader, err := i.writers[idxType].Reader()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return reader, func() { _ = reader.Close() }, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchIndex struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
loader dashboardLoader
|
loader dashboardLoader
|
||||||
perOrgReader map[int64]*bluge.Reader // orgId -> bluge reader
|
perOrgIndex map[int64]*orgIndex
|
||||||
perOrgWriter map[int64]*bluge.Writer // orgId -> bluge writer
|
|
||||||
eventStore eventStore
|
eventStore eventStore
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
buildSignals chan buildSignal
|
buildSignals chan buildSignal
|
||||||
@ -72,13 +93,12 @@ type dashboardIndex struct {
|
|||||||
syncCh chan chan struct{}
|
syncCh chan chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDashboardIndex(dashLoader dashboardLoader, evStore eventStore, extender DocumentExtender, folderIDs folderUIDLookup) *dashboardIndex {
|
func newSearchIndex(dashLoader dashboardLoader, evStore eventStore, extender DocumentExtender, folderIDs folderUIDLookup) *searchIndex {
|
||||||
return &dashboardIndex{
|
return &searchIndex{
|
||||||
loader: dashLoader,
|
loader: dashLoader,
|
||||||
eventStore: evStore,
|
eventStore: evStore,
|
||||||
perOrgReader: map[int64]*bluge.Reader{},
|
perOrgIndex: map[int64]*orgIndex{},
|
||||||
perOrgWriter: map[int64]*bluge.Writer{},
|
logger: log.New("searchIndex"),
|
||||||
logger: log.New("dashboardIndex"),
|
|
||||||
buildSignals: make(chan buildSignal),
|
buildSignals: make(chan buildSignal),
|
||||||
extender: extender,
|
extender: extender,
|
||||||
folderIdLookup: folderIDs,
|
folderIdLookup: folderIDs,
|
||||||
@ -86,7 +106,7 @@ func newDashboardIndex(dashLoader dashboardLoader, evStore eventStore, extender
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) sync(ctx context.Context) error {
|
func (i *searchIndex) sync(ctx context.Context) error {
|
||||||
doneCh := make(chan struct{}, 1)
|
doneCh := make(chan struct{}, 1)
|
||||||
select {
|
select {
|
||||||
case i.syncCh <- doneCh:
|
case i.syncCh <- doneCh:
|
||||||
@ -101,7 +121,7 @@ func (i *dashboardIndex) sync(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) run(ctx context.Context, orgIDs []int64, reIndexSignalCh chan struct{}) error {
|
func (i *searchIndex) run(ctx context.Context, orgIDs []int64, reIndexSignalCh chan struct{}) error {
|
||||||
reIndexInterval := 5 * time.Minute
|
reIndexInterval := 5 * time.Minute
|
||||||
fullReIndexTimer := time.NewTimer(reIndexInterval)
|
fullReIndexTimer := time.NewTimer(reIndexInterval)
|
||||||
defer fullReIndexTimer.Stop()
|
defer fullReIndexTimer.Stop()
|
||||||
@ -147,7 +167,7 @@ func (i *dashboardIndex) run(ctx context.Context, orgIDs []int64, reIndexSignalC
|
|||||||
case signal := <-i.buildSignals:
|
case signal := <-i.buildSignals:
|
||||||
// When search read request meets new not-indexed org we build index for it.
|
// When search read request meets new not-indexed org we build index for it.
|
||||||
i.mu.RLock()
|
i.mu.RLock()
|
||||||
_, ok := i.perOrgWriter[signal.orgID]
|
_, ok := i.perOrgIndex[signal.orgID]
|
||||||
if ok {
|
if ok {
|
||||||
// Index for org already exists, do nothing.
|
// Index for org already exists, do nothing.
|
||||||
i.mu.RUnlock()
|
i.mu.RUnlock()
|
||||||
@ -206,7 +226,7 @@ func (i *dashboardIndex) run(ctx context.Context, orgIDs []int64, reIndexSignalC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) buildInitialIndexes(ctx context.Context, orgIDs []int64) error {
|
func (i *searchIndex) buildInitialIndexes(ctx context.Context, orgIDs []int64) error {
|
||||||
started := time.Now()
|
started := time.Now()
|
||||||
i.logger.Info("Start building in-memory indexes")
|
i.logger.Info("Start building in-memory indexes")
|
||||||
for _, orgID := range orgIDs {
|
for _, orgID := range orgIDs {
|
||||||
@ -219,7 +239,7 @@ func (i *dashboardIndex) buildInitialIndexes(ctx context.Context, orgIDs []int64
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) buildInitialIndex(ctx context.Context, orgID int64) error {
|
func (i *searchIndex) buildInitialIndex(ctx context.Context, orgID int64) error {
|
||||||
debugCtx, debugCtxCancel := context.WithCancel(ctx)
|
debugCtx, debugCtxCancel := context.WithCancel(ctx)
|
||||||
if os.Getenv("GF_SEARCH_DEBUG") != "" {
|
if os.Getenv("GF_SEARCH_DEBUG") != "" {
|
||||||
go i.debugResourceUsage(debugCtx, 200*time.Millisecond)
|
go i.debugResourceUsage(debugCtx, 200*time.Millisecond)
|
||||||
@ -284,7 +304,7 @@ func getProcessCPU(currentPid int) (float64, error) {
|
|||||||
return 0, errors.New("process not found")
|
return 0, errors.New("process not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) debugResourceUsage(ctx context.Context, frequency time.Duration) {
|
func (i *searchIndex) debugResourceUsage(ctx context.Context, frequency time.Duration) {
|
||||||
var maxHeapInuse uint64
|
var maxHeapInuse uint64
|
||||||
var maxSys uint64
|
var maxSys uint64
|
||||||
|
|
||||||
@ -326,8 +346,14 @@ func (i *dashboardIndex) debugResourceUsage(ctx context.Context, frequency time.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) reportSizeOfIndexDiskBackup(orgID int64) {
|
func (i *searchIndex) reportSizeOfIndexDiskBackup(orgID int64) {
|
||||||
reader, _ := i.getOrgReader(orgID)
|
index, _ := i.getOrgIndex(orgID)
|
||||||
|
reader, cancel, err := index.readerForIndex(indexTypeDashboard)
|
||||||
|
if err != nil {
|
||||||
|
i.logger.Warn("Error getting reader", "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
// create a temp directory to store the index
|
// create a temp directory to store the index
|
||||||
tmpDir, err := ioutil.TempDir("", "grafana.dashboard_index")
|
tmpDir, err := ioutil.TempDir("", "grafana.dashboard_index")
|
||||||
@ -343,8 +369,8 @@ func (i *dashboardIndex) reportSizeOfIndexDiskBackup(orgID int64) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
cancel := make(chan struct{})
|
cancelCh := make(chan struct{})
|
||||||
err = reader.Backup(tmpDir, cancel)
|
err = reader.Backup(tmpDir, cancelCh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.logger.Error("can't create index disk backup", "error", err)
|
i.logger.Error("can't create index disk backup", "error", err)
|
||||||
return
|
return
|
||||||
@ -359,7 +385,7 @@ func (i *dashboardIndex) reportSizeOfIndexDiskBackup(orgID int64) {
|
|||||||
i.logger.Warn("Size of index disk backup", "size", formatBytes(uint64(size)))
|
i.logger.Warn("Size of index disk backup", "size", formatBytes(uint64(size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) buildOrgIndex(ctx context.Context, orgID int64) (int, error) {
|
func (i *searchIndex) buildOrgIndex(ctx context.Context, orgID int64) (int, error) {
|
||||||
started := time.Now()
|
started := time.Now()
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -373,7 +399,7 @@ func (i *dashboardIndex) buildOrgIndex(ctx context.Context, orgID int64) (int, e
|
|||||||
i.logger.Info("Finish loading org dashboards", "elapsed", orgSearchIndexLoadTime, "orgId", orgID)
|
i.logger.Info("Finish loading org dashboards", "elapsed", orgSearchIndexLoadTime, "orgId", orgID)
|
||||||
|
|
||||||
dashboardExtender := i.extender.GetDashboardExtender(orgID)
|
dashboardExtender := i.extender.GetDashboardExtender(orgID)
|
||||||
reader, writer, err := initIndex(dashboards, i.logger, dashboardExtender)
|
index, err := initOrgIndex(dashboards, i.logger, dashboardExtender)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("error initializing index: %w", err)
|
return 0, fmt.Errorf("error initializing index: %w", err)
|
||||||
}
|
}
|
||||||
@ -388,31 +414,34 @@ func (i *dashboardIndex) buildOrgIndex(ctx context.Context, orgID int64) (int, e
|
|||||||
"orgSearchDashboardCount", len(dashboards))
|
"orgSearchDashboardCount", len(dashboards))
|
||||||
|
|
||||||
i.mu.Lock()
|
i.mu.Lock()
|
||||||
if oldReader, ok := i.perOrgReader[orgID]; ok {
|
if oldIndex, ok := i.perOrgIndex[orgID]; ok {
|
||||||
_ = oldReader.Close()
|
for _, w := range oldIndex.writers {
|
||||||
|
_ = w.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if oldWriter, ok := i.perOrgWriter[orgID]; ok {
|
i.perOrgIndex[orgID] = index
|
||||||
_ = oldWriter.Close()
|
|
||||||
}
|
|
||||||
i.perOrgReader[orgID] = reader
|
|
||||||
i.perOrgWriter[orgID] = writer
|
|
||||||
i.mu.Unlock()
|
i.mu.Unlock()
|
||||||
|
|
||||||
if orgID == 1 {
|
if orgID == 1 {
|
||||||
go updateUsageStats(context.Background(), reader, i.logger)
|
go func() {
|
||||||
|
if reader, cancel, err := index.readerForIndex(indexTypeDashboard); err == nil {
|
||||||
|
defer cancel()
|
||||||
|
updateUsageStats(context.Background(), reader, i.logger)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
return len(dashboards), nil
|
return len(dashboards), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) getOrgReader(orgID int64) (*bluge.Reader, bool) {
|
func (i *searchIndex) getOrgIndex(orgID int64) (*orgIndex, bool) {
|
||||||
i.mu.RLock()
|
i.mu.RLock()
|
||||||
defer i.mu.RUnlock()
|
defer i.mu.RUnlock()
|
||||||
r, ok := i.perOrgReader[orgID]
|
r, ok := i.perOrgIndex[orgID]
|
||||||
return r, ok
|
return r, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) getOrCreateReader(ctx context.Context, orgID int64) (*bluge.Reader, error) {
|
func (i *searchIndex) getOrCreateOrgIndex(ctx context.Context, orgID int64) (*orgIndex, error) {
|
||||||
reader, ok := i.getOrgReader(orgID)
|
index, ok := i.getOrgIndex(orgID)
|
||||||
if !ok {
|
if !ok {
|
||||||
// For non-main organization indexes are built lazily.
|
// For non-main organization indexes are built lazily.
|
||||||
// If we don't have an index then we are blocking here until an index for
|
// If we don't have an index then we are blocking here until an index for
|
||||||
@ -433,22 +462,15 @@ func (i *dashboardIndex) getOrCreateReader(ctx context.Context, orgID int64) (*b
|
|||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
}
|
}
|
||||||
reader, _ = i.getOrgReader(orgID)
|
index, _ = i.getOrgIndex(orgID)
|
||||||
}
|
}
|
||||||
return reader, nil
|
return index, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) getOrgWriter(orgID int64) (*bluge.Writer, bool) {
|
func (i *searchIndex) reIndexFromScratch(ctx context.Context) {
|
||||||
i.mu.RLock()
|
i.mu.RLock()
|
||||||
defer i.mu.RUnlock()
|
orgIDs := make([]int64, 0, len(i.perOrgIndex))
|
||||||
w, ok := i.perOrgWriter[orgID]
|
for orgID := range i.perOrgIndex {
|
||||||
return w, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *dashboardIndex) reIndexFromScratch(ctx context.Context) {
|
|
||||||
i.mu.RLock()
|
|
||||||
orgIDs := make([]int64, 0, len(i.perOrgWriter))
|
|
||||||
for orgID := range i.perOrgWriter {
|
|
||||||
orgIDs = append(orgIDs, orgID)
|
orgIDs = append(orgIDs, orgID)
|
||||||
}
|
}
|
||||||
i.mu.RUnlock()
|
i.mu.RUnlock()
|
||||||
@ -462,7 +484,7 @@ func (i *dashboardIndex) reIndexFromScratch(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) applyIndexUpdates(ctx context.Context, lastEventID int64) int64 {
|
func (i *searchIndex) applyIndexUpdates(ctx context.Context, lastEventID int64) int64 {
|
||||||
events, err := i.eventStore.GetAllEventsAfter(context.Background(), lastEventID)
|
events, err := i.eventStore.GetAllEventsAfter(context.Background(), lastEventID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.logger.Error("can't load events", "error", err)
|
i.logger.Error("can't load events", "error", err)
|
||||||
@ -484,7 +506,7 @@ func (i *dashboardIndex) applyIndexUpdates(ctx context.Context, lastEventID int6
|
|||||||
return lastEventID
|
return lastEventID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) applyEventOnIndex(ctx context.Context, e *store.EntityEvent) error {
|
func (i *searchIndex) applyEventOnIndex(ctx context.Context, e *store.EntityEvent) error {
|
||||||
i.logger.Debug("processing event", "event", e)
|
i.logger.Debug("processing event", "event", e)
|
||||||
|
|
||||||
if !strings.HasPrefix(e.EntityId, "database/") {
|
if !strings.HasPrefix(e.EntityId, "database/") {
|
||||||
@ -508,9 +530,9 @@ func (i *dashboardIndex) applyEventOnIndex(ctx context.Context, e *store.EntityE
|
|||||||
return i.applyEvent(ctx, orgID, kind, uid, e.EventType)
|
return i.applyEvent(ctx, orgID, kind, uid, e.EventType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) applyEvent(ctx context.Context, orgID int64, kind store.EntityType, uid string, _ store.EntityEventType) error {
|
func (i *searchIndex) applyEvent(ctx context.Context, orgID int64, kind store.EntityType, uid string, _ store.EntityEventType) error {
|
||||||
i.mu.Lock()
|
i.mu.Lock()
|
||||||
_, ok := i.perOrgWriter[orgID]
|
_, ok := i.perOrgIndex[orgID]
|
||||||
if !ok {
|
if !ok {
|
||||||
// Skip event for org not yet indexed.
|
// Skip event for org not yet indexed.
|
||||||
i.mu.Unlock()
|
i.mu.Unlock()
|
||||||
@ -527,49 +549,39 @@ func (i *dashboardIndex) applyEvent(ctx context.Context, orgID int64, kind store
|
|||||||
i.mu.Lock()
|
i.mu.Lock()
|
||||||
defer i.mu.Unlock()
|
defer i.mu.Unlock()
|
||||||
|
|
||||||
writer, ok := i.perOrgWriter[orgID]
|
index, ok := i.perOrgIndex[orgID]
|
||||||
if !ok {
|
if !ok {
|
||||||
// Skip event for org not yet fully indexed.
|
// Skip event for org not yet fully indexed.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// TODO: should we release index lock while performing removeDashboard/updateDashboard?
|
|
||||||
reader, ok := i.perOrgReader[orgID]
|
|
||||||
if !ok {
|
|
||||||
// Skip event for org not yet fully indexed.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var newReader *bluge.Reader
|
|
||||||
|
|
||||||
// In the future we can rely on operation types to reduce work here.
|
// In the future we can rely on operation types to reduce work here.
|
||||||
if len(dbDashboards) == 0 {
|
if len(dbDashboards) == 0 {
|
||||||
switch kind {
|
switch kind {
|
||||||
case store.EntityTypeDashboard:
|
case store.EntityTypeDashboard:
|
||||||
newReader, err = i.removeDashboard(ctx, writer, reader, uid)
|
err = i.removeDashboard(ctx, index, uid)
|
||||||
case store.EntityTypeFolder:
|
case store.EntityTypeFolder:
|
||||||
newReader, err = i.removeFolder(ctx, writer, reader, uid)
|
err = i.removeFolder(ctx, index, uid)
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newReader, err = i.updateDashboard(ctx, orgID, writer, reader, dbDashboards[0])
|
err = i.updateDashboard(ctx, orgID, index, dbDashboards[0])
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_ = reader.Close()
|
|
||||||
i.perOrgReader[orgID] = newReader
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) removeDashboard(_ context.Context, writer *bluge.Writer, reader *bluge.Reader, dashboardUID string) (*bluge.Reader, error) {
|
func (i *searchIndex) removeDashboard(_ context.Context, index *orgIndex, dashboardUID string) error {
|
||||||
dashboardLocation, ok, err := getDashboardLocation(reader, dashboardUID)
|
dashboardLocation, ok, err := getDashboardLocation(index, dashboardUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
// No dashboard, nothing to remove.
|
// No dashboard, nothing to remove.
|
||||||
return reader, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all panel docs to remove with dashboard.
|
// Find all panel docs to remove with dashboard.
|
||||||
@ -577,40 +589,35 @@ func (i *dashboardIndex) removeDashboard(_ context.Context, writer *bluge.Writer
|
|||||||
if dashboardLocation != "" {
|
if dashboardLocation != "" {
|
||||||
panelLocation = dashboardLocation + "/" + dashboardUID
|
panelLocation = dashboardLocation + "/" + dashboardUID
|
||||||
}
|
}
|
||||||
panelIDs, err := getDocsIDsByLocationPrefix(reader, panelLocation)
|
panelIDs, err := getDocsIDsByLocationPrefix(index, panelLocation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writer := index.writerForIndex(indexTypeDashboard)
|
||||||
|
|
||||||
batch := bluge.NewBatch()
|
batch := bluge.NewBatch()
|
||||||
batch.Delete(bluge.NewDocument(dashboardUID).ID())
|
batch.Delete(bluge.NewDocument(dashboardUID).ID())
|
||||||
for _, panelID := range panelIDs {
|
for _, panelID := range panelIDs {
|
||||||
batch.Delete(bluge.NewDocument(panelID).ID())
|
batch.Delete(bluge.NewDocument(panelID).ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writer.Batch(batch)
|
return writer.Batch(batch)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return writer.Reader()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) removeFolder(_ context.Context, writer *bluge.Writer, reader *bluge.Reader, folderUID string) (*bluge.Reader, error) {
|
func (i *searchIndex) removeFolder(_ context.Context, index *orgIndex, folderUID string) error {
|
||||||
ids, err := getDocsIDsByLocationPrefix(reader, folderUID)
|
ids, err := getDocsIDsByLocationPrefix(index, folderUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return fmt.Errorf("error getting by location prefix: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
batch := bluge.NewBatch()
|
batch := bluge.NewBatch()
|
||||||
batch.Delete(bluge.NewDocument(folderUID).ID())
|
batch.Delete(bluge.NewDocument(folderUID).ID())
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
batch.Delete(bluge.NewDocument(id).ID())
|
batch.Delete(bluge.NewDocument(id).ID())
|
||||||
}
|
}
|
||||||
err = writer.Batch(batch)
|
writer := index.writerForIndex(indexTypeDashboard)
|
||||||
if err != nil {
|
return writer.Batch(batch)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return writer.Reader()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringInSlice(str string, slice []string) bool {
|
func stringInSlice(str string, slice []string) bool {
|
||||||
@ -622,67 +629,65 @@ func stringInSlice(str string, slice []string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *dashboardIndex) updateDashboard(ctx context.Context, orgID int64, writer *bluge.Writer, reader *bluge.Reader, dash dashboard) (*bluge.Reader, error) {
|
func (i *searchIndex) updateDashboard(ctx context.Context, orgID int64, index *orgIndex, dash dashboard) error {
|
||||||
batch := bluge.NewBatch()
|
|
||||||
|
|
||||||
extendDoc := i.extender.GetDashboardExtender(orgID, dash.uid)
|
extendDoc := i.extender.GetDashboardExtender(orgID, dash.uid)
|
||||||
|
|
||||||
|
writer := index.writerForIndex(indexTypeDashboard)
|
||||||
|
|
||||||
var doc *bluge.Document
|
var doc *bluge.Document
|
||||||
if dash.isFolder {
|
if dash.isFolder {
|
||||||
doc = getFolderDashboardDoc(dash)
|
doc = getFolderDashboardDoc(dash)
|
||||||
if err := extendDoc(dash.uid, doc); err != nil {
|
if err := extendDoc(dash.uid, doc); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
return writer.Update(doc.ID(), doc)
|
||||||
|
}
|
||||||
|
|
||||||
|
batch := bluge.NewBatch()
|
||||||
|
|
||||||
|
var folderUID string
|
||||||
|
if dash.folderID == 0 {
|
||||||
|
folderUID = "general"
|
||||||
} else {
|
} else {
|
||||||
var folderUID string
|
var err error
|
||||||
if dash.folderID == 0 {
|
folderUID, err = i.folderIdLookup(ctx, dash.folderID)
|
||||||
folderUID = "general"
|
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
folderUID, err = i.folderIdLookup(ctx, dash.folderID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
location := folderUID
|
|
||||||
doc = getNonFolderDashboardDoc(dash, location)
|
|
||||||
if err := extendDoc(dash.uid, doc); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var actualPanelIDs []string
|
|
||||||
|
|
||||||
if location != "" {
|
|
||||||
location += "/"
|
|
||||||
}
|
|
||||||
location += dash.uid
|
|
||||||
panelDocs := getDashboardPanelDocs(dash, location)
|
|
||||||
for _, panelDoc := range panelDocs {
|
|
||||||
actualPanelIDs = append(actualPanelIDs, string(panelDoc.ID().Term()))
|
|
||||||
batch.Update(panelDoc.ID(), panelDoc)
|
|
||||||
}
|
|
||||||
|
|
||||||
indexedPanelIDs, err := getDashboardPanelIDs(reader, location)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, panelID := range indexedPanelIDs {
|
location := folderUID
|
||||||
if !stringInSlice(panelID, actualPanelIDs) {
|
doc = getNonFolderDashboardDoc(dash, location)
|
||||||
batch.Delete(bluge.NewDocument(panelID).ID())
|
if err := extendDoc(dash.uid, doc); err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var actualPanelIDs []string
|
||||||
|
|
||||||
|
if location != "" {
|
||||||
|
location += "/"
|
||||||
|
}
|
||||||
|
location += dash.uid
|
||||||
|
panelDocs := getDashboardPanelDocs(dash, location)
|
||||||
|
for _, panelDoc := range panelDocs {
|
||||||
|
actualPanelIDs = append(actualPanelIDs, string(panelDoc.ID().Term()))
|
||||||
|
batch.Update(panelDoc.ID(), panelDoc)
|
||||||
|
}
|
||||||
|
|
||||||
|
indexedPanelIDs, err := getDashboardPanelIDs(index, location)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, panelID := range indexedPanelIDs {
|
||||||
|
if !stringInSlice(panelID, actualPanelIDs) {
|
||||||
|
batch.Delete(bluge.NewDocument(panelID).ID())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.Update(doc.ID(), doc)
|
batch.Update(doc.ID(), doc)
|
||||||
|
|
||||||
err := writer.Batch(batch)
|
return writer.Batch(batch)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return writer.Reader()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type sqlDashboardLoader struct {
|
type sqlDashboardLoader struct {
|
||||||
|
@ -37,17 +37,29 @@ var testDisallowAllFilter = func(uid string) bool {
|
|||||||
|
|
||||||
var testOrgID int64 = 1
|
var testOrgID int64 = 1
|
||||||
|
|
||||||
func initTestIndexFromDashes(t *testing.T, dashboards []dashboard) (*dashboardIndex, *bluge.Reader, *bluge.Writer) {
|
func initTestOrgIndexFromDashes(t *testing.T, dashboards []dashboard) *orgIndex {
|
||||||
|
t.Helper()
|
||||||
|
searchIdx := initTestIndexFromDashesExtended(t, dashboards, &NoopDocumentExtender{})
|
||||||
|
return searchIdx.perOrgIndex[testOrgID]
|
||||||
|
}
|
||||||
|
|
||||||
|
func initTestOrgIndexFromDashesExtended(t *testing.T, dashboards []dashboard, extender DocumentExtender) *orgIndex {
|
||||||
|
t.Helper()
|
||||||
|
searchIdx := initTestIndexFromDashesExtended(t, dashboards, extender)
|
||||||
|
return searchIdx.perOrgIndex[testOrgID]
|
||||||
|
}
|
||||||
|
|
||||||
|
func initTestIndexFromDashes(t *testing.T, dashboards []dashboard) *searchIndex {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
return initTestIndexFromDashesExtended(t, dashboards, &NoopDocumentExtender{})
|
return initTestIndexFromDashesExtended(t, dashboards, &NoopDocumentExtender{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func initTestIndexFromDashesExtended(t *testing.T, dashboards []dashboard, extender DocumentExtender) (*dashboardIndex, *bluge.Reader, *bluge.Writer) {
|
func initTestIndexFromDashesExtended(t *testing.T, dashboards []dashboard, extender DocumentExtender) *searchIndex {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
dashboardLoader := &testDashboardLoader{
|
dashboardLoader := &testDashboardLoader{
|
||||||
dashboards: dashboards,
|
dashboards: dashboards,
|
||||||
}
|
}
|
||||||
index := newDashboardIndex(
|
index := newSearchIndex(
|
||||||
dashboardLoader,
|
dashboardLoader,
|
||||||
&store.MockEntityEventsService{},
|
&store.MockEntityEventsService{},
|
||||||
extender,
|
extender,
|
||||||
@ -56,21 +68,17 @@ func initTestIndexFromDashesExtended(t *testing.T, dashboards []dashboard, exten
|
|||||||
numDashboards, err := index.buildOrgIndex(context.Background(), testOrgID)
|
numDashboards, err := index.buildOrgIndex(context.Background(), testOrgID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(dashboardLoader.dashboards), numDashboards)
|
require.Equal(t, len(dashboardLoader.dashboards), numDashboards)
|
||||||
reader, ok := index.getOrgReader(testOrgID)
|
return index
|
||||||
require.True(t, ok)
|
|
||||||
writer, ok := index.getOrgWriter(testOrgID)
|
|
||||||
require.True(t, ok)
|
|
||||||
return index, reader, writer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkSearchResponse(t *testing.T, fileName string, reader *bluge.Reader, filter ResourceFilter, query DashboardQuery) {
|
func checkSearchResponse(t *testing.T, fileName string, index *orgIndex, filter ResourceFilter, query DashboardQuery) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
checkSearchResponseExtended(t, fileName, reader, filter, query, &NoopQueryExtender{})
|
checkSearchResponseExtended(t, fileName, index, filter, query, &NoopQueryExtender{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkSearchResponseExtended(t *testing.T, fileName string, reader *bluge.Reader, filter ResourceFilter, query DashboardQuery, extender QueryExtender) {
|
func checkSearchResponseExtended(t *testing.T, fileName string, index *orgIndex, filter ResourceFilter, query DashboardQuery, extender QueryExtender) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
resp := doSearchQuery(context.Background(), testLogger, reader, filter, query, extender, "/pfix")
|
resp := doSearchQuery(context.Background(), testLogger, index, filter, query, extender, "/pfix")
|
||||||
experimental.CheckGoldenJSONResponse(t, "testdata", fileName, resp, true)
|
experimental.CheckGoldenJSONResponse(t, "testdata", fileName, resp, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,15 +101,15 @@ var testDashboards = []dashboard{
|
|||||||
|
|
||||||
func TestDashboardIndex(t *testing.T) {
|
func TestDashboardIndex(t *testing.T) {
|
||||||
t.Run("basic-search", func(t *testing.T) {
|
t.Run("basic-search", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, testDashboards)
|
index := initTestOrgIndexFromDashes(t, testDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "boom"},
|
DashboardQuery{Query: "boom"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("basic-filter", func(t *testing.T) {
|
t.Run("basic-filter", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, testDashboards)
|
index := initTestOrgIndexFromDashes(t, testDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testDisallowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testDisallowAllFilter,
|
||||||
DashboardQuery{Query: "boom"},
|
DashboardQuery{Query: "boom"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -109,20 +117,22 @@ func TestDashboardIndex(t *testing.T) {
|
|||||||
|
|
||||||
func TestDashboardIndexUpdates(t *testing.T) {
|
func TestDashboardIndexUpdates(t *testing.T) {
|
||||||
t.Run("dashboard-delete", func(t *testing.T) {
|
t.Run("dashboard-delete", func(t *testing.T) {
|
||||||
index, reader, writer := initTestIndexFromDashes(t, testDashboards)
|
index := initTestIndexFromDashes(t, testDashboards)
|
||||||
|
orgIdx, ok := index.getOrgIndex(testOrgID)
|
||||||
newReader, err := index.removeDashboard(context.Background(), writer, reader, "2")
|
require.True(t, ok)
|
||||||
|
err := index.removeDashboard(context.Background(), orgIdx, "2")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
checkSearchResponse(t, filepath.Base(t.Name()), orgIdx, testAllowAllFilter,
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), newReader, testAllowAllFilter,
|
|
||||||
DashboardQuery{Query: "boom"},
|
DashboardQuery{Query: "boom"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("dashboard-create", func(t *testing.T) {
|
t.Run("dashboard-create", func(t *testing.T) {
|
||||||
index, reader, writer := initTestIndexFromDashes(t, testDashboards)
|
index := initTestIndexFromDashes(t, testDashboards)
|
||||||
|
orgIdx, ok := index.getOrgIndex(testOrgID)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
newReader, err := index.updateDashboard(context.Background(), testOrgID, writer, reader, dashboard{
|
err := index.updateDashboard(context.Background(), testOrgID, orgIdx, dashboard{
|
||||||
id: 3,
|
id: 3,
|
||||||
uid: "3",
|
uid: "3",
|
||||||
info: &extract.DashboardInfo{
|
info: &extract.DashboardInfo{
|
||||||
@ -131,15 +141,17 @@ func TestDashboardIndexUpdates(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), newReader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), orgIdx, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "created"},
|
DashboardQuery{Query: "created"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("dashboard-update", func(t *testing.T) {
|
t.Run("dashboard-update", func(t *testing.T) {
|
||||||
index, reader, writer := initTestIndexFromDashes(t, testDashboards)
|
index := initTestIndexFromDashes(t, testDashboards)
|
||||||
|
orgIdx, ok := index.getOrgIndex(testOrgID)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
newReader, err := index.updateDashboard(context.Background(), testOrgID, writer, reader, dashboard{
|
err := index.updateDashboard(context.Background(), testOrgID, orgIdx, dashboard{
|
||||||
id: 2,
|
id: 2,
|
||||||
uid: "2",
|
uid: "2",
|
||||||
info: &extract.DashboardInfo{
|
info: &extract.DashboardInfo{
|
||||||
@ -148,7 +160,7 @@ func TestDashboardIndexUpdates(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), newReader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), orgIdx, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "nginx"},
|
DashboardQuery{Query: "nginx"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -231,15 +243,15 @@ func TestDashboardIndexSort(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Run("sort-asc", func(t *testing.T) {
|
t.Run("sort-asc", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashesExtended(t, testSortDashboards, extender.GetDocumentExtender())
|
index := initTestOrgIndexFromDashesExtended(t, testSortDashboards, extender.GetDocumentExtender())
|
||||||
checkSearchResponseExtended(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponseExtended(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "*", Sort: "test"}, extender.GetQueryExtender(),
|
DashboardQuery{Query: "*", Sort: "test"}, extender.GetQueryExtender(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("sort-desc", func(t *testing.T) {
|
t.Run("sort-desc", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashesExtended(t, testSortDashboards, extender.GetDocumentExtender())
|
index := initTestOrgIndexFromDashesExtended(t, testSortDashboards, extender.GetDocumentExtender())
|
||||||
checkSearchResponseExtended(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponseExtended(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "*", Sort: "-test"}, extender.GetQueryExtender(),
|
DashboardQuery{Query: "*", Sort: "-test"}, extender.GetQueryExtender(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -264,29 +276,29 @@ var testPrefixDashboards = []dashboard{
|
|||||||
|
|
||||||
func TestDashboardIndex_PrefixSearch(t *testing.T) {
|
func TestDashboardIndex_PrefixSearch(t *testing.T) {
|
||||||
t.Run("prefix-search-beginning", func(t *testing.T) {
|
t.Run("prefix-search-beginning", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, testPrefixDashboards)
|
index := initTestOrgIndexFromDashes(t, testPrefixDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "Arch"},
|
DashboardQuery{Query: "Arch"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("prefix-search-middle", func(t *testing.T) {
|
t.Run("prefix-search-middle", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, testPrefixDashboards)
|
index := initTestOrgIndexFromDashes(t, testPrefixDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "Syn"},
|
DashboardQuery{Query: "Syn"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("prefix-search-beginning-lower", func(t *testing.T) {
|
t.Run("prefix-search-beginning-lower", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, testPrefixDashboards)
|
index := initTestOrgIndexFromDashes(t, testPrefixDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "arch"},
|
DashboardQuery{Query: "arch"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("prefix-search-middle-lower", func(t *testing.T) {
|
t.Run("prefix-search-middle-lower", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, testPrefixDashboards)
|
index := initTestOrgIndexFromDashes(t, testPrefixDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "syn"},
|
DashboardQuery{Query: "syn"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -294,30 +306,30 @@ func TestDashboardIndex_PrefixSearch(t *testing.T) {
|
|||||||
|
|
||||||
func TestDashboardIndex_MultipleTokensInRow(t *testing.T) {
|
func TestDashboardIndex_MultipleTokensInRow(t *testing.T) {
|
||||||
t.Run("multiple-tokens-beginning", func(t *testing.T) {
|
t.Run("multiple-tokens-beginning", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, testPrefixDashboards)
|
index := initTestOrgIndexFromDashes(t, testPrefixDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "Archer da"},
|
DashboardQuery{Query: "Archer da"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("multiple-tokens-beginning-lower", func(t *testing.T) {
|
t.Run("multiple-tokens-beginning-lower", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, testPrefixDashboards)
|
index := initTestOrgIndexFromDashes(t, testPrefixDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "da archer"},
|
DashboardQuery{Query: "da archer"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Not sure it is great this matches, but
|
// Not sure it is great this matches, but
|
||||||
t.Run("multiple-tokens-middle", func(t *testing.T) {
|
t.Run("multiple-tokens-middle", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, testPrefixDashboards)
|
index := initTestOrgIndexFromDashes(t, testPrefixDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "ar Da"},
|
DashboardQuery{Query: "ar Da"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("multiple-tokens-middle-lower", func(t *testing.T) {
|
t.Run("multiple-tokens-middle-lower", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, testPrefixDashboards)
|
index := initTestOrgIndexFromDashes(t, testPrefixDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "doc sy"},
|
DashboardQuery{Query: "doc sy"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -335,8 +347,8 @@ var longPrefixDashboards = []dashboard{
|
|||||||
|
|
||||||
func TestDashboardIndex_PrefixNgramExceeded(t *testing.T) {
|
func TestDashboardIndex_PrefixNgramExceeded(t *testing.T) {
|
||||||
t.Run("prefix-search-ngram-exceeded", func(t *testing.T) {
|
t.Run("prefix-search-ngram-exceeded", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, longPrefixDashboards)
|
index := initTestOrgIndexFromDashes(t, longPrefixDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "Eyjafjallajöku"},
|
DashboardQuery{Query: "Eyjafjallajöku"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -361,14 +373,14 @@ var scatteredTokensDashboards = []dashboard{
|
|||||||
|
|
||||||
func TestDashboardIndex_MultipleTokensScattered(t *testing.T) {
|
func TestDashboardIndex_MultipleTokensScattered(t *testing.T) {
|
||||||
t.Run("scattered-tokens-match", func(t *testing.T) {
|
t.Run("scattered-tokens-match", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, scatteredTokensDashboards)
|
index := initTestOrgIndexFromDashes(t, scatteredTokensDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "dead secret"},
|
DashboardQuery{Query: "dead secret"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
t.Run("scattered-tokens-match-reversed", func(t *testing.T) {
|
t.Run("scattered-tokens-match-reversed", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, scatteredTokensDashboards)
|
index := initTestOrgIndexFromDashes(t, scatteredTokensDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "powerful secret"},
|
DashboardQuery{Query: "powerful secret"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -432,15 +444,15 @@ var dashboardsWithFolders = []dashboard{
|
|||||||
|
|
||||||
func TestDashboardIndex_Folders(t *testing.T) {
|
func TestDashboardIndex_Folders(t *testing.T) {
|
||||||
t.Run("folders-indexed", func(t *testing.T) {
|
t.Run("folders-indexed", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, dashboardsWithFolders)
|
index := initTestOrgIndexFromDashes(t, dashboardsWithFolders)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "My folder", Kind: []string{string(entityKindFolder)}},
|
DashboardQuery{Query: "My folder", Kind: []string{string(entityKindFolder)}},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
t.Run("folders-dashboard-has-folder", func(t *testing.T) {
|
t.Run("folders-dashboard-has-folder", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, dashboardsWithFolders)
|
index := initTestOrgIndexFromDashes(t, dashboardsWithFolders)
|
||||||
// TODO: golden file compare does not work here.
|
// TODO: golden file compare does not work here.
|
||||||
resp := doSearchQuery(context.Background(), testLogger, reader, testAllowAllFilter,
|
resp := doSearchQuery(context.Background(), testLogger, index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "Dashboard in folder", Kind: []string{string(entityKindDashboard)}},
|
DashboardQuery{Query: "Dashboard in folder", Kind: []string{string(entityKindDashboard)}},
|
||||||
&NoopQueryExtender{}, "")
|
&NoopQueryExtender{}, "")
|
||||||
custom, ok := resp.Frames[0].Meta.Custom.(*customMeta)
|
custom, ok := resp.Frames[0].Meta.Custom.(*customMeta)
|
||||||
@ -449,19 +461,23 @@ func TestDashboardIndex_Folders(t *testing.T) {
|
|||||||
require.Equal(t, "/dashboards/f/1/", custom.Locations["1"].URL)
|
require.Equal(t, "/dashboards/f/1/", custom.Locations["1"].URL)
|
||||||
})
|
})
|
||||||
t.Run("folders-dashboard-removed-on-folder-removed", func(t *testing.T) {
|
t.Run("folders-dashboard-removed-on-folder-removed", func(t *testing.T) {
|
||||||
index, reader, writer := initTestIndexFromDashes(t, dashboardsWithFolders)
|
index := initTestIndexFromDashes(t, dashboardsWithFolders)
|
||||||
newReader, err := index.removeFolder(context.Background(), writer, reader, "1")
|
orgIdx, ok := index.getOrgIndex(testOrgID)
|
||||||
|
require.True(t, ok)
|
||||||
|
err := index.removeFolder(context.Background(), orgIdx, "1")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// In response we expect one dashboard which does not belong to removed folder.
|
// In response we expect one dashboard which does not belong to removed folder.
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), newReader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), orgIdx, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "dash", Kind: []string{string(entityKindDashboard)}},
|
DashboardQuery{Query: "dash", Kind: []string{string(entityKindDashboard)}},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
t.Run("folders-panels-removed-on-folder-removed", func(t *testing.T) {
|
t.Run("folders-panels-removed-on-folder-removed", func(t *testing.T) {
|
||||||
index, reader, writer := initTestIndexFromDashes(t, dashboardsWithFolders)
|
index := initTestIndexFromDashes(t, dashboardsWithFolders)
|
||||||
newReader, err := index.removeFolder(context.Background(), writer, reader, "1")
|
orgIdx, ok := index.getOrgIndex(testOrgID)
|
||||||
|
require.True(t, ok)
|
||||||
|
err := index.removeFolder(context.Background(), orgIdx, "1")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
resp := doSearchQuery(context.Background(), testLogger, newReader, testAllowAllFilter,
|
resp := doSearchQuery(context.Background(), testLogger, orgIdx, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "Panel", Kind: []string{string(entityKindPanel)}},
|
DashboardQuery{Query: "Panel", Kind: []string{string(entityKindPanel)}},
|
||||||
&NoopQueryExtender{}, "")
|
&NoopQueryExtender{}, "")
|
||||||
custom, ok := resp.Frames[0].Meta.Custom.(*customMeta)
|
custom, ok := resp.Frames[0].Meta.Custom.(*customMeta)
|
||||||
@ -492,10 +508,10 @@ var dashboardsWithPanels = []dashboard{
|
|||||||
|
|
||||||
func TestDashboardIndex_Panels(t *testing.T) {
|
func TestDashboardIndex_Panels(t *testing.T) {
|
||||||
t.Run("panels-indexed", func(t *testing.T) {
|
t.Run("panels-indexed", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, dashboardsWithPanels)
|
index := initTestOrgIndexFromDashes(t, dashboardsWithPanels)
|
||||||
// TODO: golden file compare does not work here.
|
// TODO: golden file compare does not work here.
|
||||||
resp := doSearchQuery(
|
resp := doSearchQuery(
|
||||||
context.Background(), testLogger, reader, testAllowAllFilter,
|
context.Background(), testLogger, index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "Panel", Kind: []string{string(entityKindPanel)}},
|
DashboardQuery{Query: "Panel", Kind: []string{string(entityKindPanel)}},
|
||||||
&NoopQueryExtender{}, "")
|
&NoopQueryExtender{}, "")
|
||||||
custom, ok := resp.Frames[0].Meta.Custom.(*customMeta)
|
custom, ok := resp.Frames[0].Meta.Custom.(*customMeta)
|
||||||
@ -504,10 +520,12 @@ func TestDashboardIndex_Panels(t *testing.T) {
|
|||||||
require.Equal(t, "/d/1/", custom.Locations["1"].URL)
|
require.Equal(t, "/d/1/", custom.Locations["1"].URL)
|
||||||
})
|
})
|
||||||
t.Run("panels-panel-removed-on-dashboard-removed", func(t *testing.T) {
|
t.Run("panels-panel-removed-on-dashboard-removed", func(t *testing.T) {
|
||||||
index, reader, writer := initTestIndexFromDashes(t, dashboardsWithPanels)
|
index := initTestIndexFromDashes(t, dashboardsWithPanels)
|
||||||
newReader, err := index.removeDashboard(context.Background(), writer, reader, "1")
|
orgIdx, ok := index.getOrgIndex(testOrgID)
|
||||||
|
require.True(t, ok)
|
||||||
|
err := index.removeDashboard(context.Background(), orgIdx, "1")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), newReader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), orgIdx, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "Panel", Kind: []string{string(entityKindPanel)}},
|
DashboardQuery{Query: "Panel", Kind: []string{string(entityKindPanel)}},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -532,15 +550,15 @@ var punctuationSplitNgramDashboards = []dashboard{
|
|||||||
|
|
||||||
func TestDashboardIndex_PunctuationNgram(t *testing.T) {
|
func TestDashboardIndex_PunctuationNgram(t *testing.T) {
|
||||||
t.Run("ngram-punctuation-split", func(t *testing.T) {
|
t.Run("ngram-punctuation-split", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, punctuationSplitNgramDashboards)
|
index := initTestOrgIndexFromDashes(t, punctuationSplitNgramDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "tork he"},
|
DashboardQuery{Query: "tork he"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ngram-simple", func(t *testing.T) {
|
t.Run("ngram-simple", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, punctuationSplitNgramDashboards)
|
index := initTestOrgIndexFromDashes(t, punctuationSplitNgramDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "hea"},
|
DashboardQuery{Query: "hea"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -558,8 +576,8 @@ var camelCaseNgramDashboards = []dashboard{
|
|||||||
|
|
||||||
func TestDashboardIndex_CamelCaseNgram(t *testing.T) {
|
func TestDashboardIndex_CamelCaseNgram(t *testing.T) {
|
||||||
t.Run("ngram-camel-case-split", func(t *testing.T) {
|
t.Run("ngram-camel-case-split", func(t *testing.T) {
|
||||||
_, reader, _ := initTestIndexFromDashes(t, camelCaseNgramDashboards)
|
index := initTestOrgIndexFromDashes(t, camelCaseNgramDashboards)
|
||||||
checkSearchResponse(t, filepath.Base(t.Name()), reader, testAllowAllFilter,
|
checkSearchResponse(t, filepath.Base(t.Name()), index, testAllowAllFilter,
|
||||||
DashboardQuery{Query: "tork"},
|
DashboardQuery{Query: "tork"},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -26,7 +26,7 @@ type StandardSearchService struct {
|
|||||||
ac accesscontrol.AccessControl
|
ac accesscontrol.AccessControl
|
||||||
|
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
dashboardIndex *dashboardIndex
|
dashboardIndex *searchIndex
|
||||||
extender DashboardIndexExtender
|
extender DashboardIndexExtender
|
||||||
reIndexCh chan struct{}
|
reIndexCh chan struct{}
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ func ProvideService(cfg *setting.Cfg, sql *sqlstore.SQLStore, entityEventStore s
|
|||||||
sql: sql,
|
sql: sql,
|
||||||
ac: ac,
|
ac: ac,
|
||||||
},
|
},
|
||||||
dashboardIndex: newDashboardIndex(
|
dashboardIndex: newSearchIndex(
|
||||||
newSQLDashboardLoader(sql),
|
newSQLDashboardLoader(sql),
|
||||||
entityEventStore,
|
entityEventStore,
|
||||||
extender.GetDocumentExtender(),
|
extender.GetDocumentExtender(),
|
||||||
@ -163,7 +163,7 @@ func (s *StandardSearchService) DoDashboardQuery(ctx context.Context, user *back
|
|||||||
return rsp
|
return rsp
|
||||||
}
|
}
|
||||||
|
|
||||||
reader, err := s.dashboardIndex.getOrCreateReader(ctx, orgID)
|
index, err := s.dashboardIndex.getOrCreateOrgIndex(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rsp.Error = err
|
rsp.Error = err
|
||||||
return rsp
|
return rsp
|
||||||
@ -175,5 +175,5 @@ func (s *StandardSearchService) DoDashboardQuery(ctx context.Context, user *back
|
|||||||
return rsp
|
return rsp
|
||||||
}
|
}
|
||||||
|
|
||||||
return doSearchQuery(ctx, s.logger, reader, filter, q, s.extender.GetQueryExtender(q), s.cfg.AppSubURL)
|
return doSearchQuery(ctx, s.logger, index, filter, q, s.extender.GetQueryExtender(q), s.cfg.AppSubURL)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user