frostfs-node/pkg/local_object_storage/engine/container.go
Dmitrii Stepanov 3a441f072f
[#1709] shard: Check if context canceled for shard iteration
If context has already been canceled, then there is no need to check other shards.
At the same time, it is necessary to avoid handling context cancellation
in each handler. Therefore, the context check has been moved to the shard
iteration method, which now returns an error.

Change-Id: I70030ace36593ce7d2b8376bee39fe82e9dbf88f
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2025-04-21 15:20:50 +03:00

151 lines
3.9 KiB
Go

package engine
import (
"context"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"go.uber.org/zap"
)
// ContainerSizePrm groups parameters of ContainerSize operation.
type ContainerSizePrm struct {
cnr cid.ID
}
// ContainerSizeRes resulting values of ContainerSize operation.
type ContainerSizeRes struct {
size uint64
}
// ListContainersPrm groups parameters of ListContainers operation.
type ListContainersPrm struct{}
// ListContainersRes groups the resulting values of ListContainers operation.
type ListContainersRes struct {
containers []cid.ID
}
// SetContainerID sets the identifier of the container to estimate the size.
func (p *ContainerSizePrm) SetContainerID(cnr cid.ID) {
p.cnr = cnr
}
// Size returns calculated estimation of the container size.
func (r ContainerSizeRes) Size() uint64 {
return r.size
}
// Containers returns a list of identifiers of the containers in which local objects are stored.
func (r ListContainersRes) Containers() []cid.ID {
return r.containers
}
// ContainerSize returns the sum of estimation container sizes among all shards.
//
// Returns an error if executions are blocked (see BlockExecution).
func (e *StorageEngine) ContainerSize(ctx context.Context, prm ContainerSizePrm) (res ContainerSizeRes, err error) {
defer elapsed("ContainerSize", e.metrics.AddMethodDuration)()
err = e.execIfNotBlocked(func() error {
var csErr error
res, csErr = e.containerSize(ctx, prm)
return csErr
})
return
}
// ContainerSize calls ContainerSize method on engine to calculate sum of estimation container sizes among all shards.
func ContainerSize(ctx context.Context, e *StorageEngine, id cid.ID) (uint64, error) {
var prm ContainerSizePrm
prm.SetContainerID(id)
res, err := e.ContainerSize(ctx, prm)
if err != nil {
return 0, err
}
return res.Size(), nil
}
func (e *StorageEngine) containerSize(ctx context.Context, prm ContainerSizePrm) (ContainerSizeRes, error) {
var res ContainerSizeRes
err := e.iterateOverUnsortedShards(ctx, func(sh hashedShard) (stop bool) {
var csPrm shard.ContainerSizePrm
csPrm.SetContainerID(prm.cnr)
csRes, err := sh.ContainerSize(ctx, csPrm)
if err != nil {
e.reportShardError(ctx, sh, "can't get container size", err,
zap.Stringer("container_id", prm.cnr))
return false
}
res.size += csRes.Size()
return false
})
return res, err
}
// ListContainers returns a unique container IDs presented in the engine objects.
//
// Returns an error if executions are blocked (see BlockExecution).
func (e *StorageEngine) ListContainers(ctx context.Context, _ ListContainersPrm) (res ListContainersRes, err error) {
defer elapsed("ListContainers", e.metrics.AddMethodDuration)()
err = e.execIfNotBlocked(func() error {
var lcErr error
res, lcErr = e.listContainers(ctx)
return lcErr
})
return
}
// ListContainers calls ListContainers method on engine to get a unique container IDs presented in the engine objects.
func ListContainers(ctx context.Context, e *StorageEngine) ([]cid.ID, error) {
var prm ListContainersPrm
res, err := e.ListContainers(ctx, prm)
if err != nil {
return nil, err
}
return res.Containers(), nil
}
func (e *StorageEngine) listContainers(ctx context.Context) (ListContainersRes, error) {
uniqueIDs := make(map[string]cid.ID)
if err := e.iterateOverUnsortedShards(ctx, func(sh hashedShard) (stop bool) {
res, err := sh.ListContainers(ctx, shard.ListContainersPrm{})
if err != nil {
e.reportShardError(ctx, sh, "can't get list of containers", err)
return false
}
for _, cnr := range res.Containers() {
id := cnr.EncodeToString()
if _, ok := uniqueIDs[id]; !ok {
uniqueIDs[id] = cnr
}
}
return false
}); err != nil {
return ListContainersRes{}, err
}
result := make([]cid.ID, 0, len(uniqueIDs))
for _, v := range uniqueIDs {
result = append(result, v)
}
return ListContainersRes{
containers: result,
}, nil
}