Improve search index eviction (#111542)
* Modify index eviction mechanism such that unowned indexes are also evicted. * Propagate OwnsIndex function to bleve backend Fix tests. Stop eviction goroutine when stopping backend. Make linter happy. Make sure we stop backend created by tests. Review suggestion. Removed newline.
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"cmp"
|
||||
"context"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"log/slog"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -20,7 +19,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/grafana/authlib/types"
|
||||
"github.com/grafana/dskit/ring"
|
||||
|
||||
dashboardv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||
folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||
@@ -130,8 +128,7 @@ type searchSupport struct {
|
||||
initWorkers int
|
||||
initMinSize int
|
||||
|
||||
ring *ring.Ring
|
||||
ringLifecycler *ring.BasicLifecycler
|
||||
ownsIndexFn func(key NamespacedResource) (bool, error)
|
||||
|
||||
buildIndex singleflight.Group
|
||||
|
||||
@@ -144,7 +141,7 @@ var (
|
||||
_ resourcepb.ManagedObjectIndexServer = (*searchSupport)(nil)
|
||||
)
|
||||
|
||||
func newSearchSupport(opts SearchOptions, storage StorageBackend, access types.AccessClient, blob BlobSupport, tracer trace.Tracer, indexMetrics *BleveIndexMetrics, ring *ring.Ring, ringLifecycler *ring.BasicLifecycler) (support *searchSupport, err error) {
|
||||
func newSearchSupport(opts SearchOptions, storage StorageBackend, access types.AccessClient, blob BlobSupport, tracer trace.Tracer, indexMetrics *BleveIndexMetrics, ownsIndexFn func(key NamespacedResource) (bool, error)) (support *searchSupport, err error) {
|
||||
// No backend search support
|
||||
if opts.Backend == nil {
|
||||
return nil, nil
|
||||
@@ -157,6 +154,12 @@ func newSearchSupport(opts SearchOptions, storage StorageBackend, access types.A
|
||||
opts.WorkerThreads = 1
|
||||
}
|
||||
|
||||
if ownsIndexFn == nil {
|
||||
ownsIndexFn = func(key NamespacedResource) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
support = &searchSupport{
|
||||
access: access,
|
||||
tracer: tracer,
|
||||
@@ -167,8 +170,7 @@ func newSearchSupport(opts SearchOptions, storage StorageBackend, access types.A
|
||||
initMinSize: opts.InitMinCount,
|
||||
indexMetrics: indexMetrics,
|
||||
rebuildInterval: opts.RebuildInterval,
|
||||
ring: ring,
|
||||
ringLifecycler: ringLifecycler,
|
||||
ownsIndexFn: ownsIndexFn,
|
||||
}
|
||||
|
||||
info, err := opts.Resources.GetDocumentBuilders()
|
||||
@@ -399,33 +401,6 @@ func (s *searchSupport) GetStats(ctx context.Context, req *resourcepb.ResourceSt
|
||||
return rsp, nil
|
||||
}
|
||||
|
||||
func (s *searchSupport) shouldBuildIndex(info ResourceStats) bool {
|
||||
if s.ring == nil {
|
||||
s.log.Debug("ring is not setup. Will proceed to build index")
|
||||
return true
|
||||
}
|
||||
|
||||
if s.ringLifecycler == nil {
|
||||
s.log.Error("missing ring lifecycler")
|
||||
return true
|
||||
}
|
||||
|
||||
ringHasher := fnv.New32a()
|
||||
_, err := ringHasher.Write([]byte(info.Namespace))
|
||||
if err != nil {
|
||||
s.log.Error("error hashing namespace", "namespace", info.Namespace, "err", err)
|
||||
return true
|
||||
}
|
||||
|
||||
rs, err := s.ring.GetWithOptions(ringHasher.Sum32(), searchOwnerRead, ring.WithReplicationFactor(s.ring.ReplicationFactor()))
|
||||
if err != nil {
|
||||
s.log.Error("error getting replicaset from ring", "namespace", info.Namespace, "err", err)
|
||||
return true
|
||||
}
|
||||
|
||||
return rs.Includes(s.ringLifecycler.GetInstanceAddr())
|
||||
}
|
||||
|
||||
func (s *searchSupport) buildIndexes(ctx context.Context, rebuild bool) (int, error) {
|
||||
totalBatchesIndexed := 0
|
||||
group := errgroup.Group{}
|
||||
@@ -442,7 +417,10 @@ func (s *searchSupport) buildIndexes(ctx context.Context, rebuild bool) (int, er
|
||||
continue
|
||||
}
|
||||
|
||||
if !s.shouldBuildIndex(info) {
|
||||
own, err := s.ownsIndexFn(info.NamespacedResource)
|
||||
if err != nil {
|
||||
s.log.Warn("failed to check index ownership, building index", "namespace", info.Namespace, "group", info.Group, "resource", info.Resource, "error", err)
|
||||
} else if !own {
|
||||
s.log.Debug("skip building index", "namespace", info.Namespace, "group", info.Group, "resource", info.Resource)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -90,8 +90,6 @@ var (
|
||||
searchRingRead = ring.NewOp([]ring.InstanceState{ring.ACTIVE}, func(s ring.InstanceState) bool {
|
||||
return s != ring.ACTIVE
|
||||
})
|
||||
// operation used by the search-servers to check if they own the namespace
|
||||
searchOwnerRead = ring.NewOp([]ring.InstanceState{ring.JOINING, ring.ACTIVE, ring.LEAVING}, nil)
|
||||
)
|
||||
|
||||
func (ds *distributorServer) Search(ctx context.Context, r *resourcepb.ResourceSearchRequest) (*resourcepb.ResourceSearchResponse, error) {
|
||||
|
||||
@@ -213,7 +213,7 @@ func TestSearchGetOrCreateIndex(t *testing.T) {
|
||||
InitMinCount: 1, // set min count to default for this test
|
||||
}
|
||||
|
||||
support, err := newSearchSupport(opts, storage, nil, nil, noop.NewTracerProvider().Tracer("test"), nil, nil, nil)
|
||||
support, err := newSearchSupport(opts, storage, nil, nil, noop.NewTracerProvider().Tracer("test"), nil, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, support)
|
||||
|
||||
@@ -274,7 +274,7 @@ func TestSearchGetOrCreateIndexWithIndexUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
// Enable searchAfterWrite
|
||||
support, err := newSearchSupport(opts, storage, nil, nil, noop.NewTracerProvider().Tracer("test"), nil, nil, nil)
|
||||
support, err := newSearchSupport(opts, storage, nil, nil, noop.NewTracerProvider().Tracer("test"), nil, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, support)
|
||||
|
||||
@@ -325,7 +325,7 @@ func TestSearchGetOrCreateIndexWithCancellation(t *testing.T) {
|
||||
InitMinCount: 1, // set min count to default for this test
|
||||
}
|
||||
|
||||
support, err := newSearchSupport(opts, storage, nil, nil, noop.NewTracerProvider().Tracer("test"), nil, nil, nil)
|
||||
support, err := newSearchSupport(opts, storage, nil, nil, noop.NewTracerProvider().Tracer("test"), nil, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, support)
|
||||
|
||||
|
||||
@@ -235,8 +235,7 @@ type ResourceServerOptions struct {
|
||||
QOSQueue QOSEnqueuer
|
||||
QOSConfig QueueConfig
|
||||
|
||||
Ring *ring.Ring
|
||||
RingLifecycler *ring.BasicLifecycler
|
||||
OwnsIndexFn func(key NamespacedResource) (bool, error)
|
||||
}
|
||||
|
||||
func NewResourceServer(opts ResourceServerOptions) (*server, error) {
|
||||
@@ -334,7 +333,7 @@ func NewResourceServer(opts ResourceServerOptions) (*server, error) {
|
||||
|
||||
if opts.Search.Resources != nil {
|
||||
var err error
|
||||
s.search, err = newSearchSupport(opts.Search, s.backend, s.access, s.blob, opts.Tracer, opts.IndexMetrics, opts.Ring, opts.RingLifecycler)
|
||||
s.search, err = newSearchSupport(opts.Search, s.backend, s.access, s.blob, opts.Tracer, opts.IndexMetrics, opts.OwnsIndexFn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user