git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/object/relations/relations.go (about) 1 package relations 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 8 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" 9 cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" 10 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" 11 oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" 12 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session" 13 ) 14 15 // Tokens contains different tokens to perform requests in Relations implementations. 16 type Tokens struct { 17 Session *session.Object 18 Bearer *bearer.Token 19 } 20 21 type Relations interface { 22 // GetSplitInfo tries to get split info by root object id. 23 // If object isn't virtual it returns ErrNoSplitInfo. 24 GetSplitInfo(ctx context.Context, cnrID cid.ID, rootID oid.ID, tokens Tokens) (*object.SplitInfo, error) 25 26 // ListChildrenByLinker returns list of children for link object. 27 // Result doesn't include link object itself. 28 ListChildrenByLinker(ctx context.Context, cnrID cid.ID, linkerID oid.ID, tokens Tokens) ([]oid.ID, error) 29 30 // GetLeftSibling return previous object id in object chain. 31 // If no previous object it returns ErrNoLeftSibling. 32 GetLeftSibling(ctx context.Context, cnrID cid.ID, objID oid.ID, tokens Tokens) (oid.ID, error) 33 34 // FindSiblingBySplitID returns all objects that relates to the provided split id. 35 FindSiblingBySplitID(ctx context.Context, cnrID cid.ID, splitID *object.SplitID, tokens Tokens) ([]oid.ID, error) 36 37 // FindSiblingByParentID returns all object that relates to the provided parent id. 38 FindSiblingByParentID(ctx context.Context, cnrID cid.ID, parentID oid.ID, tokens Tokens) ([]oid.ID, error) 39 } 40 41 var ( 42 // ErrNoLeftSibling is an error that must be returned if object doesn't have left sibling in objects chain. 43 ErrNoLeftSibling = errors.New("no left siblings") 44 45 // ErrNoSplitInfo is an error that must be returned if requested object isn't virtual. 46 ErrNoSplitInfo = errors.New("no split info") 47 ) 48 49 // ListAllRelations return all related phy objects for provided root object ID. 50 // Result doesn't include root object ID itself. 51 func ListAllRelations(ctx context.Context, rels Relations, cnrID cid.ID, rootObjID oid.ID, tokens Tokens) ([]oid.ID, error) { 52 splitInfo, err := rels.GetSplitInfo(ctx, cnrID, rootObjID, tokens) 53 if err != nil { 54 if errors.Is(err, ErrNoSplitInfo) { 55 return []oid.ID{}, nil 56 } 57 return nil, err 58 } 59 60 // collect split chain by the descending ease of operations (ease is evaluated heuristically). 61 // If any approach fails, we don't try the next since we assume that it will fail too. 62 if idLinking, ok := splitInfo.Link(); ok { 63 children, err := rels.ListChildrenByLinker(ctx, cnrID, idLinking, tokens) 64 if err != nil { 65 return nil, fmt.Errorf("failed to get linking object's header: %w", err) 66 } 67 68 // include linking object 69 return append(children, idLinking), nil 70 } 71 72 if idSplit := splitInfo.SplitID(); idSplit != nil { 73 members, err := rels.FindSiblingBySplitID(ctx, cnrID, idSplit, tokens) 74 if err != nil { 75 return nil, fmt.Errorf("failed to search objects by split ID: %w", err) 76 } 77 return members, nil 78 } 79 80 idMember, ok := splitInfo.LastPart() 81 if !ok { 82 return nil, errors.New("missing any data in received object split information") 83 } 84 85 chain := []oid.ID{idMember} 86 chainSet := map[oid.ID]struct{}{idMember: {}} 87 88 // prmHead.SetRawFlag(false) 89 // split members are almost definitely singular, but don't get hung up on it 90 91 for { 92 idMember, err = rels.GetLeftSibling(ctx, cnrID, idMember, tokens) 93 if err != nil { 94 if errors.Is(err, ErrNoLeftSibling) { 95 break 96 } 97 return nil, fmt.Errorf("failed to read split chain member's header: %w", err) 98 } 99 100 if _, ok = chainSet[idMember]; ok { 101 return nil, fmt.Errorf("duplicated member in the split chain %s", idMember) 102 } 103 104 chain = append(chain, idMember) 105 chainSet[idMember] = struct{}{} 106 } 107 108 list, err := rels.FindSiblingByParentID(ctx, cnrID, rootObjID, tokens) 109 if err != nil { 110 return nil, fmt.Errorf("failed to find object children: %w", err) 111 } 112 113 for i := range list { 114 if _, ok = chainSet[list[i]]; !ok { 115 chain = append(chain, list[i]) 116 } 117 } 118 119 return chain, nil 120 }