diff --git a/cmd/frostfs-node/tree.go b/cmd/frostfs-node/tree.go index 1f73b795..175748ac 100644 --- a/cmd/frostfs-node/tree.go +++ b/cmd/frostfs-node/tree.go @@ -31,6 +31,10 @@ func (c cnrSource) Get(id cid.ID) (*container.Container, error) { return c.src.Get(id) } +func (c cnrSource) DeletionInfo(cid cid.ID) (*container.DelInfo, error) { + return c.cli.DeletionInfo(cid) +} + func (c cnrSource) List() ([]cid.ID, error) { return c.cli.ContainersOf(nil) } diff --git a/internal/logs/logs.go b/internal/logs/logs.go index 6c261785..3f0a3f56 100644 --- a/internal/logs/logs.go +++ b/internal/logs/logs.go @@ -70,6 +70,7 @@ const ( TreeContainerTreesHaveBeenSynced = "container trees have been synced" TreeCouldNotQueryTreesForSynchronization = "could not query trees for synchronization" TreeRemovingRedundantTrees = "removing redundant trees..." + TreeCouldNotCheckIfContainerExisted = "could not check if the container ever existed" TreeCouldNotRemoveRedundantTree = "could not remove redundant tree" TreeCouldNotCalculateContainerNodes = "could not calculate container nodes" TreeFailedToApplyReplicatedOperation = "failed to apply replicated operation" diff --git a/pkg/services/tree/options.go b/pkg/services/tree/options.go index a6e23c62..043e12cb 100644 --- a/pkg/services/tree/options.go +++ b/pkg/services/tree/options.go @@ -14,6 +14,9 @@ import ( type ContainerSource interface { container.Source + + DeletionInfo(cid.ID) (*container.DelInfo, error) + // List must return list of all the containers in the FrostFS network // at the moment of a call and any error that does not allow fetching // container information. diff --git a/pkg/services/tree/signature_test.go b/pkg/services/tree/signature_test.go index 482c1615..9d4776ba 100644 --- a/pkg/services/tree/signature_test.go +++ b/pkg/services/tree/signature_test.go @@ -53,6 +53,10 @@ func (s dummyContainerSource) Get(id cid.ID) (*containercore.Container, error) { return cnt, nil } +func (s dummyContainerSource) DeletionInfo(id cid.ID) (*containercore.DelInfo, error) { + return &containercore.DelInfo{}, nil +} + type dummyEACLSource map[string]*containercore.EACL func (s dummyEACLSource) GetEACL(id cid.ID) (*containercore.EACL, error) { diff --git a/pkg/services/tree/sync.go b/pkg/services/tree/sync.go index e44e8dbb..62a127c6 100644 --- a/pkg/services/tree/sync.go +++ b/pkg/services/tree/sync.go @@ -18,6 +18,7 @@ import ( metrics "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics/grpc" tracing "git.frostfs.info/TrueCloudLab/frostfs-observability/tracing" tracing_grpc "git.frostfs.info/TrueCloudLab/frostfs-observability/tracing/grpc" + apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" netmapSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "github.com/panjf2000/ants/v2" @@ -440,6 +441,18 @@ func (s *Service) syncContainers(ctx context.Context, cnrs []cid.ID) { wg.Wait() } +func (s *Service) containerEverExisted(cid cid.ID) (bool, error) { + _, err := s.cnrSource.DeletionInfo(cid) + if err == nil { + return true, nil + } + var errContainerNotFound *apistatus.ContainerNotFound + if errors.As(err, &errContainerNotFound) { + return false, nil + } + return false, err +} + func (s *Service) removeContainers(ctx context.Context, newContainers map[cid.ID]struct{}) { ctx, span := tracing.StartSpanFromContext(ctx, "TreeService.removeContainers") defer span.End() @@ -452,7 +465,15 @@ func (s *Service) removeContainers(ctx context.Context, newContainers map[cid.ID if _, ok := newContainers[cnr]; ok { continue } - removed = append(removed, cnr) + + existed, err := s.containerEverExisted(cnr) + if err != nil { + s.log.Error(logs.TreeCouldNotCheckIfContainerExisted, + zap.Stringer("cid", cnr), + zap.Error(err)) + } else if existed { + removed = append(removed, cnr) + } } for i := range removed { delete(s.cnrMap, removed[i])