1c30414a6c
Core changes: * avoid package-colliding variable naming * avoid using pointers to IDs where unnecessary * avoid using `idSDK` import alias pattern * use `EncodeToString` for protocol string calculation and `String` for printing Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
177 lines
5.2 KiB
Go
177 lines
5.2 KiB
Go
package container
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"errors"
|
|
"fmt"
|
|
|
|
v2refs "github.com/nspcc-dev/neofs-api-go/v2/refs"
|
|
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
|
)
|
|
|
|
// AnnounceLoadPrm groups parameters of AnnounceLoad operation.
|
|
type AnnounceLoadPrm struct {
|
|
a container.UsedSpaceAnnouncement
|
|
key []byte
|
|
|
|
client.InvokePrmOptional
|
|
}
|
|
|
|
// SetAnnouncement sets announcement.
|
|
func (a2 *AnnounceLoadPrm) SetAnnouncement(a container.UsedSpaceAnnouncement) {
|
|
a2.a = a
|
|
}
|
|
|
|
// SetReporter sets public key of the reporter.
|
|
func (a2 *AnnounceLoadPrm) SetReporter(key []byte) {
|
|
a2.key = key
|
|
}
|
|
|
|
// AnnounceLoad saves container size estimation calculated by storage node
|
|
// with key in NeoFS system through Container contract call.
|
|
//
|
|
// Returns any error encountered that caused the saving to interrupt.
|
|
func (c *Client) AnnounceLoad(p AnnounceLoadPrm) error {
|
|
cnr, ok := p.a.ContainerID()
|
|
if !ok {
|
|
return errors.New("missing container for load announcement")
|
|
}
|
|
|
|
binCnr := make([]byte, sha256.Size)
|
|
cnr.Encode(binCnr)
|
|
|
|
prm := client.InvokePrm{}
|
|
prm.SetMethod(putSizeMethod)
|
|
prm.SetArgs(p.a.Epoch(), binCnr, p.a.UsedSpace(), p.key)
|
|
prm.InvokePrmOptional = p.InvokePrmOptional
|
|
|
|
err := c.client.Invoke(prm)
|
|
if err != nil {
|
|
return fmt.Errorf("could not invoke method (%s): %w", putSizeMethod, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// EstimationID is an identity of container load estimation inside Container contract.
|
|
type EstimationID []byte
|
|
|
|
// ListLoadEstimationsByEpoch returns a list of container load estimations for to the specified epoch.
|
|
// The list is composed through Container contract call.
|
|
func (c *Client) ListLoadEstimationsByEpoch(epoch uint64) ([]EstimationID, error) {
|
|
invokePrm := client.TestInvokePrm{}
|
|
invokePrm.SetMethod(listSizesMethod)
|
|
invokePrm.SetArgs(epoch)
|
|
|
|
prms, err := c.client.TestInvoke(invokePrm)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not perform test invocation (%s): %w", listSizesMethod, err)
|
|
} else if ln := len(prms); ln != 1 {
|
|
return nil, fmt.Errorf("unexpected stack item count (%s): %d", listSizesMethod, ln)
|
|
}
|
|
|
|
prms, err = client.ArrayFromStackItem(prms[0])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get stack item array from stack item (%s): %w", listSizesMethod, err)
|
|
}
|
|
|
|
res := make([]EstimationID, 0, len(prms))
|
|
for i := range prms {
|
|
id, err := client.BytesFromStackItem(prms[i])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get ID byte array from stack item (%s): %w", listSizesMethod, err)
|
|
}
|
|
|
|
res = append(res, id)
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
// Estimation is a structure of single container load estimation
|
|
// reported by storage node.
|
|
type Estimation struct {
|
|
Size uint64
|
|
|
|
Reporter []byte
|
|
}
|
|
|
|
// Estimations is a structure of grouped container load estimation inside Container contract.
|
|
type Estimations struct {
|
|
ContainerID cid.ID
|
|
|
|
Values []Estimation
|
|
}
|
|
|
|
// GetUsedSpaceEstimations returns a list of container load estimations by ID.
|
|
// The list is composed through Container contract call.
|
|
func (c *Client) GetUsedSpaceEstimations(id EstimationID) (*Estimations, error) {
|
|
prm := client.TestInvokePrm{}
|
|
prm.SetMethod(getSizeMethod)
|
|
prm.SetArgs([]byte(id))
|
|
|
|
prms, err := c.client.TestInvoke(prm)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not perform test invocation (%s): %w", getSizeMethod, err)
|
|
} else if ln := len(prms); ln != 1 {
|
|
return nil, fmt.Errorf("unexpected stack item count (%s): %d", getSizeMethod, ln)
|
|
}
|
|
|
|
prms, err = client.ArrayFromStackItem(prms[0])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get stack items of estimation fields from stack item (%s): %w", getSizeMethod, err)
|
|
} else if ln := len(prms); ln != 2 {
|
|
return nil, fmt.Errorf("unexpected stack item count of estimations fields (%s)", getSizeMethod)
|
|
}
|
|
|
|
rawCnr, err := client.BytesFromStackItem(prms[0])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get container ID byte array from stack item (%s): %w", getSizeMethod, err)
|
|
}
|
|
|
|
prms, err = client.ArrayFromStackItem(prms[1])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get estimation list array from stack item (%s): %w", getSizeMethod, err)
|
|
}
|
|
|
|
var cnr cid.ID
|
|
|
|
err = cnr.Decode(rawCnr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decode container ID: %w", err)
|
|
}
|
|
|
|
v2 := new(v2refs.ContainerID)
|
|
v2.SetValue(rawCnr)
|
|
res := &Estimations{
|
|
ContainerID: cnr,
|
|
Values: make([]Estimation, 0, len(prms)),
|
|
}
|
|
|
|
for i := range prms {
|
|
arr, err := client.ArrayFromStackItem(prms[i])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get estimation struct from stack item (%s): %w", getSizeMethod, err)
|
|
} else if ln := len(arr); ln != 2 {
|
|
return nil, fmt.Errorf("unexpected stack item count of estimation fields (%s)", getSizeMethod)
|
|
}
|
|
|
|
reporter, err := client.BytesFromStackItem(arr[0])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get reporter byte array from stack item (%s): %w", getSizeMethod, err)
|
|
}
|
|
|
|
sz, err := client.IntFromStackItem(arr[1])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get estimation size from stack item (%s): %w", getSizeMethod, err)
|
|
}
|
|
|
|
res.Values = append(res.Values, Estimation{
|
|
Reporter: reporter,
|
|
Size: uint64(sz),
|
|
})
|
|
}
|
|
|
|
return res, nil
|
|
}
|