frostfs-node/pkg/morph/client/container/containers_of.go
Evgenii Stratonikov 357287c267
All checks were successful
DCO action / DCO (pull_request) Successful in 4m40s
Vulncheck / Vulncheck (pull_request) Successful in 6m44s
Build / Build Components (1.20) (pull_request) Successful in 10m13s
Build / Build Components (1.21) (pull_request) Successful in 10m7s
Tests and linters / Staticcheck (pull_request) Successful in 11m7s
Tests and linters / Tests (1.20) (pull_request) Successful in 11m53s
Tests and linters / Tests (1.21) (pull_request) Successful in 12m3s
Tests and linters / Lint (pull_request) Successful in 12m23s
Tests and linters / Tests with -race (pull_request) Successful in 12m41s
[#965] morph: Get rid of container.List invocations
ContainersOf() is better in almost every aspect, besides creating a
session when the containers number is between 1024 and 2048 (prefetch
script does limited unwrapping). Making List() private helps to ensure
it is no longer used and can be safely removed in future.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2024-02-06 20:36:16 +03:00

62 lines
1.8 KiB
Go

package container
import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
// ContainersOf returns a list of container identifiers belonging
// to the specified user of FrostFS system. If idUser is nil, returns the list of all containers.
//
// If remote RPC does not support neo-go session API, fallback to List() method.
func (c *Client) ContainersOf(idUser *user.ID) ([]cid.ID, error) {
var rawID []byte
if idUser != nil {
rawID = idUser.WalletBytes()
}
var cidList []cid.ID
cb := func(item stackitem.Item) error {
rawID, err := client.BytesFromStackItem(item)
if err != nil {
return fmt.Errorf("could not get byte array from stack item (%s): %w", containersOfMethod, err)
}
var id cid.ID
err = id.Decode(rawID)
if err != nil {
return fmt.Errorf("decode container ID: %w", err)
}
cidList = append(cidList, id)
return nil
}
// We would like to have batch size as big as possible,
// to reduce the number of round-trips and avoid creating sessions.
// The limit depends on 2 things:
// 1. VM limits: max 2048 items on stack.
// 2. JSON encoded size for the item with type = 128k.
// It turns out, that for container ID the second limit is hit first,
// 512 is big enough value and it is beautiful.
const batchSize = 512
cnrHash := c.client.ContractAddress()
err := c.client.Morph().TestInvokeIterator(cb, batchSize, cnrHash, containersOfMethod, rawID)
if err != nil {
if errors.Is(err, unwrap.ErrNoSessionID) {
return c.list(idUser)
}
return nil, err
}
return cidList, nil
}