Unified storage search: Introduce min index update interval (#111978)
* Don't update index more often than specified index_min_update_interval. * Add artificial sleep at the end of write operations. * Improve test: check for number of update calls, make diff check less flaky. * Make test less flaky by allowing for higher diff variance. * Make test less flaky by allowing for expected update calls variance.
This commit is contained in:
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/dskit/backoff"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/validation"
|
||||
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
@@ -194,6 +195,10 @@ type SearchOptions struct {
|
||||
|
||||
// Number of workers to use for index rebuilds.
|
||||
IndexRebuildWorkers int
|
||||
|
||||
// Minimum time between index updates. This is also used as a delay after a successful write operation, to guarantee
|
||||
// that subsequent search will observe the effect of the writing.
|
||||
IndexMinUpdateInterval time.Duration
|
||||
}
|
||||
|
||||
type ResourceServerOptions struct {
|
||||
@@ -336,6 +341,8 @@ func NewResourceServer(opts ResourceServerOptions) (*server, error) {
|
||||
reg: opts.Reg,
|
||||
queue: opts.QOSQueue,
|
||||
queueConfig: opts.QOSConfig,
|
||||
|
||||
artificialSuccessfulWriteDelay: opts.Search.IndexMinUpdateInterval,
|
||||
}
|
||||
|
||||
if opts.Search.Resources != nil {
|
||||
@@ -386,6 +393,11 @@ type server struct {
|
||||
reg prometheus.Registerer
|
||||
queue QOSEnqueuer
|
||||
queueConfig QueueConfig
|
||||
|
||||
// This value is used by storage server to artificially delay returning response after successful
|
||||
// write operations to make sure that subsequent search by the same client will return up-to-date results.
|
||||
// Set from SearchOptions.IndexMinUpdateInterval.
|
||||
artificialSuccessfulWriteDelay time.Duration
|
||||
}
|
||||
|
||||
// Init implements ResourceServer.
|
||||
@@ -661,6 +673,8 @@ func (s *server) Create(ctx context.Context, req *resourcepb.CreateRequest) (*re
|
||||
})
|
||||
}
|
||||
|
||||
s.sleepAfterSuccessfulWriteOperation(res, err)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
@@ -684,6 +698,37 @@ func (s *server) create(ctx context.Context, user claims.AuthInfo, req *resource
|
||||
return rsp, nil
|
||||
}
|
||||
|
||||
type responseWithErrorResult interface {
|
||||
GetError() *resourcepb.ErrorResult
|
||||
}
|
||||
|
||||
// sleepAfterSuccessfulWriteOperation will sleep for a specified time if the operation was successful.
|
||||
// Returns boolean indicating whether the sleep was performed or not (used in testing).
|
||||
//
|
||||
// This sleep is performed to guarantee search-after-write consistency, when rate-limiting updates to search index.
|
||||
func (s *server) sleepAfterSuccessfulWriteOperation(res responseWithErrorResult, err error) bool {
|
||||
if s.artificialSuccessfulWriteDelay <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// No sleep necessary if operation failed.
|
||||
return false
|
||||
}
|
||||
|
||||
// We expect that non-nil interface values with typed nils can still handle GetError() call.
|
||||
if res != nil {
|
||||
errRes := res.GetError()
|
||||
if errRes != nil {
|
||||
// No sleep necessary if operation failed.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(s.artificialSuccessfulWriteDelay)
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *server) Update(ctx context.Context, req *resourcepb.UpdateRequest) (*resourcepb.UpdateResponse, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "storage_server.Update")
|
||||
defer span.End()
|
||||
@@ -715,6 +760,8 @@ func (s *server) Update(ctx context.Context, req *resourcepb.UpdateRequest) (*re
|
||||
})
|
||||
}
|
||||
|
||||
s.sleepAfterSuccessfulWriteOperation(res, err)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
@@ -787,6 +834,8 @@ func (s *server) Delete(ctx context.Context, req *resourcepb.DeleteRequest) (*re
|
||||
})
|
||||
}
|
||||
|
||||
s.sleepAfterSuccessfulWriteOperation(res, err)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user