[#1564] cli: Fix output of object nodes
command
All checks were successful
Pre-commit hooks / Pre-commit (push) Successful in 1m26s
Vulncheck / Vulncheck (push) Successful in 1m30s
Build / Build Components (push) Successful in 1m59s
Tests and linters / Run gofumpt (push) Successful in 2m48s
Tests and linters / gopls check (push) Successful in 3m29s
Tests and linters / Tests (push) Successful in 3m51s
Tests and linters / Staticcheck (push) Successful in 4m7s
Tests and linters / Tests with -race (push) Successful in 4m8s
Tests and linters / Lint (push) Successful in 4m32s
OCI image / Build container images (push) Successful in 5m8s
All checks were successful
Pre-commit hooks / Pre-commit (push) Successful in 1m26s
Vulncheck / Vulncheck (push) Successful in 1m30s
Build / Build Components (push) Successful in 1m59s
Tests and linters / Run gofumpt (push) Successful in 2m48s
Tests and linters / gopls check (push) Successful in 3m29s
Tests and linters / Tests (push) Successful in 3m51s
Tests and linters / Staticcheck (push) Successful in 4m7s
Tests and linters / Tests with -race (push) Successful in 4m8s
Tests and linters / Lint (push) Successful in 4m32s
OCI image / Build container images (push) Successful in 5m8s
The object nodes command misleadingly reported the number of "found data objects" as if it matched the actual expected amount, which could be incorrect for EC objects. Updated the output wording to explicitly distinguish between currently available data objects and total objects per the EC schema. Change-Id: Ib36b89db58ae66d8978baf5a16b59435db9a068d Signed-off-by: Ekaterina Lebedeva <ekaterina.lebedeva@yadro.com>
This commit is contained in:
parent
9b5c1da40f
commit
923f0acf8f
1 changed files with 42 additions and 17 deletions
|
@ -48,6 +48,12 @@ type ecHeader struct {
|
|||
parent oid.ID
|
||||
}
|
||||
|
||||
type objectCounter struct {
|
||||
sync.Mutex
|
||||
total uint32
|
||||
isECcounted bool
|
||||
}
|
||||
|
||||
type objectPlacement struct {
|
||||
requiredNodes []netmapSDK.NodeInfo
|
||||
confirmedNodes []netmapSDK.NodeInfo
|
||||
|
@ -56,6 +62,7 @@ type objectPlacement struct {
|
|||
type objectNodesResult struct {
|
||||
errors []error
|
||||
placements map[oid.ID]objectPlacement
|
||||
total uint32
|
||||
}
|
||||
|
||||
type ObjNodesDataObject struct {
|
||||
|
@ -106,18 +113,18 @@ func objectNodes(cmd *cobra.Command, _ []string) {
|
|||
pk := key.GetOrGenerate(cmd)
|
||||
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)
|
||||
|
||||
objects := getPhyObjects(cmd, cnrID, objID, cli, pk)
|
||||
objects, count := getPhyObjects(cmd, cnrID, objID, cli, pk)
|
||||
|
||||
placementPolicy, netmap := getPlacementPolicyAndNetmap(cmd, cnrID, cli)
|
||||
|
||||
result := getRequiredPlacement(cmd, objects, placementPolicy, netmap)
|
||||
|
||||
getActualPlacement(cmd, netmap, pk, objects, result)
|
||||
getActualPlacement(cmd, netmap, pk, objects, count, result)
|
||||
|
||||
printPlacement(cmd, objID, objects, result)
|
||||
}
|
||||
|
||||
func getPhyObjects(cmd *cobra.Command, cnrID cid.ID, objID oid.ID, cli *client.Client, pk *ecdsa.PrivateKey) []phyObject {
|
||||
func getPhyObjects(cmd *cobra.Command, cnrID cid.ID, objID oid.ID, cli *client.Client, pk *ecdsa.PrivateKey) ([]phyObject, int) {
|
||||
var addrObj oid.Address
|
||||
addrObj.SetContainer(cnrID)
|
||||
addrObj.SetObject(objID)
|
||||
|
@ -145,7 +152,7 @@ func getPhyObjects(cmd *cobra.Command, cnrID cid.ID, objID oid.ID, cli *client.C
|
|||
parent: res.Header().ECHeader().Parent(),
|
||||
}
|
||||
}
|
||||
return []phyObject{obj}
|
||||
return []phyObject{obj}, 1
|
||||
}
|
||||
|
||||
var errSplitInfo *objectSDK.SplitInfoError
|
||||
|
@ -155,29 +162,34 @@ func getPhyObjects(cmd *cobra.Command, cnrID cid.ID, objID oid.ID, cli *client.C
|
|||
|
||||
var ecInfoError *objectSDK.ECInfoError
|
||||
if errors.As(err, &ecInfoError) {
|
||||
return getECObjectChunks(cmd, cnrID, objID, ecInfoError)
|
||||
return getECObjectChunks(cmd, cnrID, objID, ecInfoError), 1
|
||||
}
|
||||
commonCmd.ExitOnErr(cmd, "failed to get object info: %w", err)
|
||||
return nil
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
func getComplexObjectParts(cmd *cobra.Command, cnrID cid.ID, objID oid.ID, cli *client.Client, prmHead internalclient.HeadObjectPrm, errSplitInfo *objectSDK.SplitInfoError) []phyObject {
|
||||
members := getCompexObjectMembers(cmd, cnrID, objID, cli, prmHead, errSplitInfo)
|
||||
return flattenComplexMembersIfECContainer(cmd, cnrID, members, prmHead)
|
||||
func getComplexObjectParts(cmd *cobra.Command, cnrID cid.ID, objID oid.ID, cli *client.Client, prmHead internalclient.HeadObjectPrm, errSplitInfo *objectSDK.SplitInfoError) ([]phyObject, int) {
|
||||
members, total := getCompexObjectMembers(cmd, cnrID, objID, cli, prmHead, errSplitInfo)
|
||||
return flattenComplexMembersIfECContainer(cmd, cnrID, members, prmHead), total
|
||||
}
|
||||
|
||||
func getCompexObjectMembers(cmd *cobra.Command, cnrID cid.ID, objID oid.ID, cli *client.Client, prmHead internalclient.HeadObjectPrm, errSplitInfo *objectSDK.SplitInfoError) []oid.ID {
|
||||
func getCompexObjectMembers(cmd *cobra.Command, cnrID cid.ID, objID oid.ID, cli *client.Client, prmHead internalclient.HeadObjectPrm, errSplitInfo *objectSDK.SplitInfoError) ([]oid.ID, int) {
|
||||
var total int
|
||||
splitInfo := errSplitInfo.SplitInfo()
|
||||
|
||||
if members, ok := tryGetSplitMembersByLinkingObject(cmd, splitInfo, prmHead, cnrID); ok {
|
||||
return members
|
||||
if total = len(members); total > 0 {
|
||||
total-- // linking object is not data object
|
||||
}
|
||||
return members, total
|
||||
}
|
||||
|
||||
if members, ok := tryGetSplitMembersBySplitID(cmd, splitInfo, cli, cnrID); ok {
|
||||
return members
|
||||
return members, len(members)
|
||||
}
|
||||
|
||||
return tryRestoreChainInReverse(cmd, splitInfo, prmHead, cli, cnrID, objID)
|
||||
members := tryRestoreChainInReverse(cmd, splitInfo, prmHead, cli, cnrID, objID)
|
||||
return members, len(members)
|
||||
}
|
||||
|
||||
func flattenComplexMembersIfECContainer(cmd *cobra.Command, cnrID cid.ID, members []oid.ID, prmHead internalclient.HeadObjectPrm) []phyObject {
|
||||
|
@ -383,8 +395,11 @@ func getECRequiredPlacementInternal(cmd *cobra.Command, object phyObject, placem
|
|||
}
|
||||
}
|
||||
|
||||
func getActualPlacement(cmd *cobra.Command, netmap *netmapSDK.NetMap, pk *ecdsa.PrivateKey, objects []phyObject, result *objectNodesResult) {
|
||||
func getActualPlacement(cmd *cobra.Command, netmap *netmapSDK.NetMap, pk *ecdsa.PrivateKey, objects []phyObject, count int, result *objectNodesResult) {
|
||||
resultMtx := &sync.Mutex{}
|
||||
counter := &objectCounter{
|
||||
total: uint32(count),
|
||||
}
|
||||
|
||||
candidates := getNodesToCheckObjectExistance(cmd, netmap, result)
|
||||
|
||||
|
@ -401,7 +416,7 @@ func getActualPlacement(cmd *cobra.Command, netmap *netmapSDK.NetMap, pk *ecdsa.
|
|||
|
||||
for _, object := range objects {
|
||||
eg.Go(func() error {
|
||||
stored, err := isObjectStoredOnNode(egCtx, cmd, object.containerID, object.objectID, cli, pk)
|
||||
stored, err := isObjectStoredOnNode(egCtx, cmd, object.containerID, object.objectID, cli, pk, counter)
|
||||
resultMtx.Lock()
|
||||
defer resultMtx.Unlock()
|
||||
if err == nil && stored {
|
||||
|
@ -420,6 +435,7 @@ func getActualPlacement(cmd *cobra.Command, netmap *netmapSDK.NetMap, pk *ecdsa.
|
|||
}
|
||||
|
||||
commonCmd.ExitOnErr(cmd, "failed to get actual placement: %w", eg.Wait())
|
||||
result.total = counter.total
|
||||
}
|
||||
|
||||
func getNodesToCheckObjectExistance(cmd *cobra.Command, netmap *netmapSDK.NetMap, result *objectNodesResult) []netmapSDK.NodeInfo {
|
||||
|
@ -478,7 +494,7 @@ func createClient(ctx context.Context, cmd *cobra.Command, candidate netmapSDK.N
|
|||
return cli, nil
|
||||
}
|
||||
|
||||
func isObjectStoredOnNode(ctx context.Context, cmd *cobra.Command, cnrID cid.ID, objID oid.ID, cli *client.Client, pk *ecdsa.PrivateKey) (bool, error) {
|
||||
func isObjectStoredOnNode(ctx context.Context, cmd *cobra.Command, cnrID cid.ID, objID oid.ID, cli *client.Client, pk *ecdsa.PrivateKey, counter *objectCounter) (bool, error) {
|
||||
var addrObj oid.Address
|
||||
addrObj.SetContainer(cnrID)
|
||||
addrObj.SetObject(objID)
|
||||
|
@ -493,6 +509,14 @@ func isObjectStoredOnNode(ctx context.Context, cmd *cobra.Command, cnrID cid.ID,
|
|||
|
||||
res, err := internalclient.HeadObject(ctx, prmHead)
|
||||
if err == nil && res != nil {
|
||||
if res.Header().ECHeader() != nil {
|
||||
counter.Lock()
|
||||
defer counter.Unlock()
|
||||
if !counter.isECcounted {
|
||||
counter.total *= res.Header().ECHeader().Total()
|
||||
}
|
||||
counter.isECcounted = true
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
var notFound *apistatus.ObjectNotFound
|
||||
|
@ -512,7 +536,8 @@ func printPlacement(cmd *cobra.Command, objID oid.ID, objects []phyObject, resul
|
|||
}
|
||||
|
||||
func printObjectNodesAsText(cmd *cobra.Command, objID oid.ID, objects []phyObject, result *objectNodesResult) {
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Object %s stores payload in %d data objects:\n", objID.EncodeToString(), len(objects))
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Object %s stores payload in %d data objects\n", objID.EncodeToString(), result.total)
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Found %d:\n", len(objects))
|
||||
|
||||
for _, object := range objects {
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "- %s\n", object.objectID)
|
||||
|
|
Loading…
Add table
Reference in a new issue