[#607] object/search: Make client constructor to work with group address

Make Object Search service to work with `AddressGroup` instead of `Address`
in order to support multiple addresses of the storage node.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-06-22 15:19:30 +03:00 committed by Leonard Lyubich
parent ad14df07f6
commit d0e48c949b
9 changed files with 54 additions and 28 deletions

View file

@ -286,7 +286,7 @@ func initObjectService(c *cfg) {
sSearch := searchsvc.New( sSearch := searchsvc.New(
searchsvc.WithLogger(c.log), searchsvc.WithLogger(c.log),
searchsvc.WithLocalStorageEngine(ls), searchsvc.WithLocalStorageEngine(ls),
searchsvc.WithClientConstructor(coreConstructor), searchsvc.WithClientConstructor(groupConstructor),
searchsvc.WithTraverserGenerator( searchsvc.WithTraverserGenerator(
traverseGen.WithTraverseOptions( traverseGen.WithTraverseOptions(
placement.WithoutSuccessTracking(), placement.WithoutSuccessTracking(),

View file

@ -3,6 +3,7 @@ package searchsvc
import ( import (
"context" "context"
"github.com/nspcc-dev/neofs-node/pkg/network"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -76,7 +77,7 @@ func (exec *execCtx) processCurrentEpoch() bool {
} }
// TODO: consider parallel execution // TODO: consider parallel execution
exec.processNode(ctx, addrs[i]) exec.processNode(ctx, network.GroupFromAddress(addrs[i]))
} }
} }

View file

@ -117,16 +117,14 @@ func (exec *execCtx) generateTraverser(cid *cid.ID) (*placement.Traverser, bool)
} }
} }
func (exec execCtx) remoteClient(node network.Address) (searchClient, bool) { func (exec execCtx) remoteClient(node network.AddressGroup) (searchClient, bool) {
log := exec.log.With(zap.Stringer("node", node))
c, err := exec.svc.clientConstructor.get(node) c, err := exec.svc.clientConstructor.get(node)
switch { switch {
default: default:
exec.status = statusUndefined exec.status = statusUndefined
exec.err = err exec.err = err
log.Debug("could not construct remote node client") exec.log.Debug("could not construct remote node client")
case err == nil: case err == nil:
return c, true return c, true
} }

View file

@ -27,7 +27,7 @@ type IDListWriter interface {
// RequestForwarder is a callback for forwarding of the // RequestForwarder is a callback for forwarding of the
// original Search requests. // original Search requests.
type RequestForwarder func(network.Address, coreclient.Client) ([]*objectSDK.ID, error) type RequestForwarder func(network.AddressGroup, coreclient.Client) ([]*objectSDK.ID, error)
// SetCommonParameters sets common parameters of the operation. // SetCommonParameters sets common parameters of the operation.
func (p *Prm) SetCommonParameters(common *util.CommonPrm) { func (p *Prm) SetCommonParameters(common *util.CommonPrm) {

View file

@ -7,10 +7,8 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
func (exec *execCtx) processNode(ctx context.Context, addr network.Address) { func (exec *execCtx) processNode(ctx context.Context, addr network.AddressGroup) {
log := exec.log.With(zap.Stringer("remote node", addr)) exec.log.Debug("processing node...")
log.Debug("processing node...")
client, ok := exec.remoteClient(addr) client, ok := exec.remoteClient(addr)
if !ok { if !ok {

View file

@ -84,8 +84,8 @@ func (p *testPlacementBuilder) BuildPlacement(addr *objectSDK.Address, _ *netmap
return res, nil return res, nil
} }
func (c *testClientCache) get(mAddr network.Address) (searchClient, error) { func (c *testClientCache) get(mAddr network.AddressGroup) (searchClient, error) {
v, ok := c.clients[mAddr.HostAddr()] v, ok := c.clients[network.StringifyGroup(mAddr)]
if !ok { if !ok {
return nil, errors.New("could not construct client") return nil, errors.New("could not construct client")
} }
@ -102,7 +102,7 @@ func (s *testStorage) search(exec *execCtx) ([]*objectSDK.ID, error) {
return v.ids, v.err return v.ids, v.err
} }
func (c *testStorage) searchObjects(exec *execCtx, _ network.Address) ([]*objectSDK.ID, error) { func (c *testStorage) searchObjects(exec *execCtx, _ network.AddressGroup) ([]*objectSDK.ID, error) {
v, ok := c.items[exec.containerID().String()] v, ok := c.items[exec.containerID().String()]
if !ok { if !ok {
return nil, nil return nil, nil
@ -200,16 +200,16 @@ func testNodeMatrix(t testing.TB, dim []int) ([]netmap.Nodes, [][]string) {
strconv.Itoa(60000+j), strconv.Itoa(60000+j),
) )
var na network.Address
err := na.FromString(a)
require.NoError(t, err)
as[j] = na.HostAddr()
ni := netmap.NewNodeInfo() ni := netmap.NewNodeInfo()
ni.SetAddress(a) ni.SetAddress(a)
var na network.AddressGroup
err := na.FromIterator(ni)
require.NoError(t, err)
as[j] = network.StringifyGroup(na)
ns[j] = *ni ns[j] = *ni
} }

View file

@ -23,11 +23,11 @@ type Service struct {
type Option func(*cfg) type Option func(*cfg)
type searchClient interface { type searchClient interface {
searchObjects(*execCtx, network.Address) ([]*object.ID, error) searchObjects(*execCtx, network.AddressGroup) ([]*object.ID, error)
} }
type ClientConstructor interface { type ClientConstructor interface {
Get(network.Address) (client.Client, error) Get(network.AddressGroup) (client.Client, error)
} }
type cfg struct { type cfg struct {
@ -38,7 +38,7 @@ type cfg struct {
} }
clientConstructor interface { clientConstructor interface {
get(network.Address) (searchClient, error) get(network.AddressGroup) (searchClient, error)
} }
traverserGenerator interface { traverserGenerator interface {

View file

@ -68,7 +68,7 @@ func (w *uniqueIDWriter) WriteIDs(list []*objectSDK.ID) error {
return w.writer.WriteIDs(list) return w.writer.WriteIDs(list)
} }
func (c *clientConstructorWrapper) get(addr network.Address) (searchClient, error) { func (c *clientConstructorWrapper) get(addr network.AddressGroup) (searchClient, error) {
clt, err := c.constructor.Get(addr) clt, err := c.constructor.Get(addr)
return &clientWrapper{ return &clientWrapper{
@ -76,7 +76,7 @@ func (c *clientConstructorWrapper) get(addr network.Address) (searchClient, erro
}, err }, err
} }
func (c *clientWrapper) searchObjects(exec *execCtx, addr network.Address) ([]*objectSDK.ID, error) { func (c *clientWrapper) searchObjects(exec *execCtx, addr network.AddressGroup) ([]*objectSDK.ID, error) {
if exec.prm.forwarder != nil { if exec.prm.forwarder != nil {
return exec.prm.forwarder(addr, c.client) return exec.prm.forwarder(addr, c.client)
} }

View file

@ -46,7 +46,7 @@ func (s *Service) toPrm(req *objectV2.SearchRequest, stream objectSvc.SearchStre
if !commonPrm.LocalOnly() { if !commonPrm.LocalOnly() {
var onceResign sync.Once var onceResign sync.Once
p.SetRequestForwarder(func(addr network.Address, c client.Client) ([]*objectSDK.ID, error) { p.SetRequestForwarder(groupAddressRequestForwarder(func(addr network.Address, c client.Client) ([]*objectSDK.ID, error) {
var err error var err error
// once compose and resign forwarding request // once compose and resign forwarding request
@ -101,7 +101,7 @@ func (s *Service) toPrm(req *objectV2.SearchRequest, stream objectSvc.SearchStre
} }
return searchResult, nil return searchResult, nil
}) }))
} }
body := req.GetBody() body := req.GetBody()
@ -110,3 +110,32 @@ func (s *Service) toPrm(req *objectV2.SearchRequest, stream objectSvc.SearchStre
return p, nil return p, nil
} }
func groupAddressRequestForwarder(f func(network.Address, client.Client) ([]*objectSDK.ID, error)) searchsvc.RequestForwarder {
return func(addrGroup network.AddressGroup, c client.Client) ([]*objectSDK.ID, error) {
var (
firstErr error
res []*objectSDK.ID
)
addrGroup.IterateAddresses(func(addr network.Address) (stop bool) {
var err error
defer func() {
stop = err == nil
if stop || firstErr == nil {
firstErr = err
}
// would be nice to log otherwise
}()
res, err = f(addr, c)
return
})
return res, firstErr
}
}