forked from TrueCloudLab/frostfs-sdk-go
[#308] object/relations: List relations in split order
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
b4b07a3c4e
commit
9964a83083
2 changed files with 55 additions and 65 deletions
|
@ -19,8 +19,9 @@ type Tokens struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Relations interface {
|
type Relations interface {
|
||||||
// GetSplitInfo tries to get split info by root object id.
|
// GetSplitInfo tries to get split info by some object id.
|
||||||
// If object isn't virtual it returns ErrNoSplitInfo.
|
// This method must return split info on any object from split chain as well as on parent/linking object.
|
||||||
|
// If object doesn't have any split information returns ErrNoSplitInfo.
|
||||||
GetSplitInfo(ctx context.Context, cnrID cid.ID, rootID oid.ID, tokens Tokens) (*object.SplitInfo, error)
|
GetSplitInfo(ctx context.Context, cnrID cid.ID, rootID oid.ID, tokens Tokens) (*object.SplitInfo, error)
|
||||||
|
|
||||||
// ListChildrenByLinker returns list of children for link object.
|
// ListChildrenByLinker returns list of children for link object.
|
||||||
|
@ -31,9 +32,6 @@ type Relations interface {
|
||||||
// If no previous object it returns ErrNoLeftSibling.
|
// If no previous object it returns ErrNoLeftSibling.
|
||||||
GetLeftSibling(ctx context.Context, cnrID cid.ID, objID oid.ID, tokens Tokens) (oid.ID, error)
|
GetLeftSibling(ctx context.Context, cnrID cid.ID, objID oid.ID, tokens Tokens) (oid.ID, error)
|
||||||
|
|
||||||
// FindSiblingBySplitID returns all objects that relates to the provided split id.
|
|
||||||
FindSiblingBySplitID(ctx context.Context, cnrID cid.ID, splitID *object.SplitID, tokens Tokens) ([]oid.ID, error)
|
|
||||||
|
|
||||||
// FindSiblingByParentID returns all object that relates to the provided parent id.
|
// FindSiblingByParentID returns all object that relates to the provided parent id.
|
||||||
FindSiblingByParentID(ctx context.Context, cnrID cid.ID, parentID oid.ID, tokens Tokens) ([]oid.ID, error)
|
FindSiblingByParentID(ctx context.Context, cnrID cid.ID, parentID oid.ID, tokens Tokens) ([]oid.ID, error)
|
||||||
}
|
}
|
||||||
|
@ -46,9 +44,15 @@ var (
|
||||||
ErrNoSplitInfo = errors.New("no split info")
|
ErrNoSplitInfo = errors.New("no split info")
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListAllRelations return all related phy objects for provided root object ID.
|
// ListAllRelations return all related phy objects for provided root object ID in split-chain order.
|
||||||
// Result doesn't include root object ID itself.
|
// Result doesn't include root object ID itself. If linking object is found its id will be the last one.
|
||||||
func ListAllRelations(ctx context.Context, rels Relations, cnrID cid.ID, rootObjID oid.ID, tokens Tokens) ([]oid.ID, error) {
|
func ListAllRelations(ctx context.Context, rels Relations, cnrID cid.ID, rootObjID oid.ID, tokens Tokens) ([]oid.ID, error) {
|
||||||
|
return ListRelations(ctx, rels, cnrID, rootObjID, tokens, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRelations return all related phy objects for provided root object ID in split-chain order.
|
||||||
|
// Result doesn't include root object ID itself.
|
||||||
|
func ListRelations(ctx context.Context, rels Relations, cnrID cid.ID, rootObjID oid.ID, tokens Tokens, includeLinking bool) ([]oid.ID, error) {
|
||||||
splitInfo, err := rels.GetSplitInfo(ctx, cnrID, rootObjID, tokens)
|
splitInfo, err := rels.GetSplitInfo(ctx, cnrID, rootObjID, tokens)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ErrNoSplitInfo) {
|
if errors.Is(err, ErrNoSplitInfo) {
|
||||||
|
@ -59,22 +63,40 @@ func ListAllRelations(ctx context.Context, rels Relations, cnrID cid.ID, rootObj
|
||||||
|
|
||||||
// collect split chain by the descending ease of operations (ease is evaluated heuristically).
|
// collect split chain by the descending ease of operations (ease is evaluated heuristically).
|
||||||
// If any approach fails, we don't try the next since we assume that it will fail too.
|
// If any approach fails, we don't try the next since we assume that it will fail too.
|
||||||
|
if _, ok := splitInfo.Link(); !ok {
|
||||||
|
// the list is expected to contain last part and (probably) split info
|
||||||
|
list, err := rels.FindSiblingByParentID(ctx, cnrID, rootObjID, tokens)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find object children: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, id := range list {
|
||||||
|
split, err := rels.GetSplitInfo(ctx, cnrID, id, tokens)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, ErrNoSplitInfo) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("failed to get split info: %w", err)
|
||||||
|
}
|
||||||
|
if link, ok := split.Link(); ok {
|
||||||
|
splitInfo.SetLink(link)
|
||||||
|
}
|
||||||
|
if last, ok := split.LastPart(); ok {
|
||||||
|
splitInfo.SetLastPart(last)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if idLinking, ok := splitInfo.Link(); ok {
|
if idLinking, ok := splitInfo.Link(); ok {
|
||||||
children, err := rels.ListChildrenByLinker(ctx, cnrID, idLinking, tokens)
|
children, err := rels.ListChildrenByLinker(ctx, cnrID, idLinking, tokens)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get linking object's header: %w", err)
|
return nil, fmt.Errorf("failed to get linking object's header: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// include linking object
|
if includeLinking {
|
||||||
return append(children, idLinking), nil
|
children = append(children, idLinking)
|
||||||
}
|
}
|
||||||
|
return children, nil
|
||||||
if idSplit := splitInfo.SplitID(); idSplit != nil {
|
|
||||||
members, err := rels.FindSiblingBySplitID(ctx, cnrID, idSplit, tokens)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to search objects by split ID: %w", err)
|
|
||||||
}
|
|
||||||
return members, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
idMember, ok := splitInfo.LastPart()
|
idMember, ok := splitInfo.LastPart()
|
||||||
|
@ -85,9 +107,6 @@ func ListAllRelations(ctx context.Context, rels Relations, cnrID cid.ID, rootObj
|
||||||
chain := []oid.ID{idMember}
|
chain := []oid.ID{idMember}
|
||||||
chainSet := map[oid.ID]struct{}{idMember: {}}
|
chainSet := map[oid.ID]struct{}{idMember: {}}
|
||||||
|
|
||||||
// prmHead.SetRawFlag(false)
|
|
||||||
// split members are almost definitely singular, but don't get hung up on it
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
idMember, err = rels.GetLeftSibling(ctx, cnrID, idMember, tokens)
|
idMember, err = rels.GetLeftSibling(ctx, cnrID, idMember, tokens)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -101,20 +120,9 @@ func ListAllRelations(ctx context.Context, rels Relations, cnrID cid.ID, rootObj
|
||||||
return nil, fmt.Errorf("duplicated member in the split chain %s", idMember)
|
return nil, fmt.Errorf("duplicated member in the split chain %s", idMember)
|
||||||
}
|
}
|
||||||
|
|
||||||
chain = append(chain, idMember)
|
chain = append([]oid.ID{idMember}, chain...)
|
||||||
chainSet[idMember] = struct{}{}
|
chainSet[idMember] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := rels.FindSiblingByParentID(ctx, cnrID, rootObjID, tokens)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to find object children: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range list {
|
|
||||||
if _, ok = chainSet[list[i]]; !ok {
|
|
||||||
chain = append(chain, list[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return chain, nil
|
return chain, nil
|
||||||
}
|
}
|
||||||
|
|
48
pool/pool.go
48
pool/pool.go
|
@ -2510,7 +2510,7 @@ func (p *Pool) GetSplitInfo(ctx context.Context, cnrID cid.ID, objID oid.ID, tok
|
||||||
}
|
}
|
||||||
prm.MarkRaw()
|
prm.MarkRaw()
|
||||||
|
|
||||||
_, err := p.HeadObject(ctx, prm)
|
res, err := p.HeadObject(ctx, prm)
|
||||||
|
|
||||||
var errSplit *object.SplitInfoError
|
var errSplit *object.SplitInfoError
|
||||||
|
|
||||||
|
@ -2518,7 +2518,21 @@ func (p *Pool) GetSplitInfo(ctx context.Context, cnrID cid.ID, objID oid.ID, tok
|
||||||
case errors.As(err, &errSplit):
|
case errors.As(err, &errSplit):
|
||||||
return errSplit.SplitInfo(), nil
|
return errSplit.SplitInfo(), nil
|
||||||
case err == nil:
|
case err == nil:
|
||||||
|
if res.SplitID() == nil {
|
||||||
return nil, relations.ErrNoSplitInfo
|
return nil, relations.ErrNoSplitInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
splitInfo := object.NewSplitInfo()
|
||||||
|
splitInfo.SetSplitID(res.SplitID())
|
||||||
|
if res.HasParent() {
|
||||||
|
if len(res.Children()) > 0 {
|
||||||
|
splitInfo.SetLink(objID)
|
||||||
|
} else {
|
||||||
|
splitInfo.SetLastPart(objID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return splitInfo, nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("failed to get raw object header: %w", err)
|
return nil, fmt.Errorf("failed to get raw object header: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -2574,38 +2588,6 @@ func (p *Pool) GetLeftSibling(ctx context.Context, cnrID cid.ID, objID oid.ID, t
|
||||||
return idMember, nil
|
return idMember, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindSiblingBySplitID implements relations.Relations.
|
|
||||||
func (p *Pool) FindSiblingBySplitID(ctx context.Context, cnrID cid.ID, splitID *object.SplitID, tokens relations.Tokens) ([]oid.ID, error) {
|
|
||||||
var query object.SearchFilters
|
|
||||||
query.AddSplitIDFilter(object.MatchStringEqual, splitID)
|
|
||||||
|
|
||||||
var prm PrmObjectSearch
|
|
||||||
prm.SetContainerID(cnrID)
|
|
||||||
prm.SetFilters(query)
|
|
||||||
if tokens.Bearer != nil {
|
|
||||||
prm.UseBearer(*tokens.Bearer)
|
|
||||||
}
|
|
||||||
if tokens.Session != nil {
|
|
||||||
prm.UseSession(*tokens.Session)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := p.SearchObjects(ctx, prm)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to search objects by split ID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var members []oid.ID
|
|
||||||
err = res.Iterate(func(id oid.ID) bool {
|
|
||||||
members = append(members, id)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to iterate found objects: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return members, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindSiblingByParentID implements relations.Relations.
|
// FindSiblingByParentID implements relations.Relations.
|
||||||
func (p *Pool) FindSiblingByParentID(ctx context.Context, cnrID cid.ID, objID oid.ID, tokens relations.Tokens) ([]oid.ID, error) {
|
func (p *Pool) FindSiblingByParentID(ctx context.Context, cnrID cid.ID, objID oid.ID, tokens relations.Tokens) ([]oid.ID, error) {
|
||||||
var query object.SearchFilters
|
var query object.SearchFilters
|
||||||
|
|
Loading…
Reference in a new issue