1
0
mirror of https://github.com/rancher/steve.git synced 2025-09-12 04:39:05 +00:00

Fix race condition with database reset (#804)

* Wait for garbage collection to be finished before creating a new DB

* Prevent DB reset while inflight List requests

* Rename cacheFor to cacheForLocked

* Rename Reset to Stop

* Mention DoneWithCache in README

* Add RunGC to ByOptionsLister interface
This commit is contained in:
Tom Lebreux
2025-09-05 11:30:56 -04:00
committed by GitHub
parent 0adae191dd
commit 4bd760b22d
13 changed files with 311 additions and 79 deletions

View File

@@ -289,7 +289,7 @@ type Store struct {
notifier RelationshipNotifier
cacheFactory CacheFactory
cfInitializer CacheFactoryInitializer
namespaceCache Cache
namespaceCache *factory.Cache
lock sync.Mutex
columnSetter SchemaColumnSetter
transformBuilder TransformBuilder
@@ -300,8 +300,9 @@ type Store struct {
type CacheFactoryInitializer func() (CacheFactory, error)
type CacheFactory interface {
CacheFor(ctx context.Context, fields [][]string, externalUpdateInfo *sqltypes.ExternalGVKUpdates, selfUpdateInfo *sqltypes.ExternalGVKUpdates, transform cache.TransformFunc, client dynamic.ResourceInterface, gvk schema.GroupVersionKind, namespaced bool, watchable bool) (factory.Cache, error)
Reset() error
CacheFor(ctx context.Context, fields [][]string, externalUpdateInfo *sqltypes.ExternalGVKUpdates, selfUpdateInfo *sqltypes.ExternalGVKUpdates, transform cache.TransformFunc, client dynamic.ResourceInterface, gvk schema.GroupVersionKind, namespaced bool, watchable bool) (*factory.Cache, error)
DoneWithCache(*factory.Cache)
Stop() error
}
// NewProxyStore returns a Store implemented directly on top of kubernetes.
@@ -336,7 +337,10 @@ func NewProxyStore(ctx context.Context, c SchemaColumnSetter, clientGetter Clien
func (s *Store) Reset() error {
s.lock.Lock()
defer s.lock.Unlock()
if err := s.cacheFactory.Reset(); err != nil {
if s.namespaceCache != nil {
s.cacheFactory.DoneWithCache(s.namespaceCache)
}
if err := s.cacheFactory.Stop(); err != nil {
return fmt.Errorf("reset: %w", err)
}
@@ -595,6 +599,10 @@ func (s *Store) watch(apiOp *types.APIRequest, schema *types.APISchema, w types.
if err != nil {
return nil, err
}
// FIXME: This needs to be called when the watch ends, not at the end of
// this func. However, there's currently a bug where we don't correctly
// shutdown watches, so for now, we do this.
defer s.cacheFactory.DoneWithCache(inf)
var selector labels.Selector
if w.Selector != "" {
@@ -803,6 +811,7 @@ func (s *Store) ListByPartitions(apiOp *types.APIRequest, apiSchema *types.APISc
if err != nil {
return nil, 0, "", fmt.Errorf("cachefor %v: %w", gvk, err)
}
defer s.cacheFactory.DoneWithCache(inf)
opts, err := listprocessor.ParseQuery(apiOp, gvk.Kind)
if err != nil {