diff --git a/checksum/checksum.go b/checksum/checksum.go index f400acab..d6876b57 100644 --- a/checksum/checksum.go +++ b/checksum/checksum.go @@ -24,7 +24,7 @@ type Checksum struct { // Type represents the enumeration // of checksum types. -type Type uint32 +type Type int32 const ( Unknown Type = iota // Deprecated: use 0 instead. @@ -99,6 +99,9 @@ func NewFromData(typ Type, data []byte) (Checksum, error) { // // See also [Checksum.ProtoMessage]. func (c *Checksum) FromProtoMessage(m *refs.Checksum) error { + if m.Type < 0 { + return fmt.Errorf("negative type %d", m.Type) + } if len(m.Sum) == 0 { return errors.New("missing value") } diff --git a/checksum/checksum_test.go b/checksum/checksum_test.go index 999e10ae..4d7d78d4 100644 --- a/checksum/checksum_test.go +++ b/checksum/checksum_test.go @@ -63,7 +63,7 @@ func TestChecksumDecodingFailures(t *testing.T) { } func TestNew(t *testing.T) { - typ := checksum.Type(rand.Uint32()) + typ := checksum.Type(rand.Int31()) val := make([]byte, 128) //nolint:staticcheck rand.Read(val) @@ -71,7 +71,7 @@ func TestNew(t *testing.T) { require.Equal(t, typ, cs.Type()) require.Equal(t, val, cs.Value()) - otherTyp := checksum.Type(rand.Uint32()) + otherTyp := checksum.Type(rand.Int31()) otherVal := make([]byte, 128) //nolint:staticcheck rand.Read(otherVal) @@ -155,7 +155,7 @@ func TestNewFromHash(t *testing.T) { h.Write([]byte("Hello, world!")) hb := []byte{32, 94, 4, 138} - typ := checksum.Type(rand.Uint32()) + typ := checksum.Type(rand.Int31()) cs := checksum.NewFromHash(typ, h) require.Equal(t, typ, cs.Type()) require.Equal(t, hb, cs.Value()) diff --git a/netmap/context.go b/netmap/context.go index bb280b1f..7a0e04d0 100644 --- a/netmap/context.go +++ b/netmap/context.go @@ -4,7 +4,6 @@ import ( "errors" "github.com/nspcc-dev/hrw/v2" - "github.com/nspcc-dev/neofs-api-go/v2/netmap" ) // context of a placement build process. @@ -13,10 +12,10 @@ type context struct { netMap NetMap // cache of processed filters - processedFilters map[string]*netmap.Filter + processedFilters map[string]*Filter // cache of processed selectors - processedSelectors map[string]*netmap.Selector + processedSelectors map[string]*Selector // stores results of selector processing selections map[string][]nodes @@ -55,8 +54,8 @@ var ( func newContext(nm NetMap) *context { return &context{ netMap: nm, - processedFilters: make(map[string]*netmap.Filter), - processedSelectors: make(map[string]*netmap.Selector), + processedFilters: make(map[string]*Filter), + processedSelectors: make(map[string]*Selector), selections: make(map[string][]nodes), numCache: make(map[string]uint64), diff --git a/netmap/filter.go b/netmap/filter.go index bd229cad..778dd11b 100644 --- a/netmap/filter.go +++ b/netmap/filter.go @@ -3,8 +3,6 @@ package netmap import ( "fmt" "strconv" - - "github.com/nspcc-dev/neofs-api-go/v2/netmap" ) // mainFilterName is a name of the filter @@ -15,15 +13,15 @@ const mainFilterName = "*" func (c *context) processFilters(p PlacementPolicy) error { for i := range p.filters { if err := c.processFilter(p.filters[i], true); err != nil { - return fmt.Errorf("process filter #%d (%s): %w", i, p.filters[i].GetName(), err) + return fmt.Errorf("process filter #%d (%s): %w", i, p.filters[i].Name(), err) } } return nil } -func (c *context) processFilter(f netmap.Filter, top bool) error { - fName := f.GetName() +func (c *context) processFilter(f Filter, top bool) error { + fName := f.Name() if fName == mainFilterName { return fmt.Errorf("%w: '%s' is reserved", errInvalidFilterName, mainFilterName) } @@ -36,10 +34,10 @@ func (c *context) processFilter(f netmap.Filter, top bool) error { return errFilterNotFound } - inner := f.GetFilters() + inner := f.SubFilters() - switch op := f.GetOp(); op { - case netmap.AND, netmap.OR: + switch op := f.Op(); op { + case FilterOpAND, FilterOpOR: for i := range inner { if err := c.processFilter(inner[i], false); err != nil { return fmt.Errorf("process inner filter #%d: %w", i, err) @@ -53,12 +51,12 @@ func (c *context) processFilter(f netmap.Filter, top bool) error { } switch op { - case netmap.EQ, netmap.NE: - case netmap.GT, netmap.GE, netmap.LT, netmap.LE: - val := f.GetValue() + case FilterOpEQ, FilterOpNE: + case FilterOpGT, FilterOpGE, FilterOpLT, FilterOpLE: + val := f.Value() n, err := strconv.ParseUint(val, 10, 64) if err != nil { - return fmt.Errorf("%w: '%s'", errInvalidNumber, f.GetValue()) + return fmt.Errorf("%w: '%s'", errInvalidNumber, val) } c.numCache[val] = n @@ -77,38 +75,41 @@ func (c *context) processFilter(f netmap.Filter, top bool) error { // match matches f against b. It returns no errors because // filter should have been parsed during context creation // and missing node properties are considered as a regular fail. -func (c *context) match(f *netmap.Filter, b NodeInfo) bool { - switch f.GetOp() { - case netmap.AND, netmap.OR: - inner := f.GetFilters() +func (c *context) match(f *Filter, b NodeInfo) bool { + if f == nil { + return false + } + switch f.Op() { + case FilterOpAND, FilterOpOR: + inner := f.SubFilters() for i := range inner { fSub := &inner[i] - if name := inner[i].GetName(); name != "" { + if name := inner[i].Name(); name != "" { fSub = c.processedFilters[name] } ok := c.match(fSub, b) - if ok == (f.GetOp() == netmap.OR) { + if ok == (f.Op() == FilterOpOR) { return ok } } - return f.GetOp() == netmap.AND + return f.Op() == FilterOpAND default: return c.matchKeyValue(f, b) } } -func (c *context) matchKeyValue(f *netmap.Filter, b NodeInfo) bool { - switch op := f.GetOp(); op { - case netmap.EQ: - return b.Attribute(f.GetKey()) == f.GetValue() - case netmap.NE: - return b.Attribute(f.GetKey()) != f.GetValue() +func (c *context) matchKeyValue(f *Filter, b NodeInfo) bool { + switch op := f.Op(); op { + case FilterOpEQ: + return b.Attribute(f.Key()) == f.Value() + case FilterOpNE: + return b.Attribute(f.Key()) != f.Value() default: var attr uint64 - switch f.GetKey() { + switch f.Key() { case attrPrice: attr = b.Price() case attrCapacity: @@ -116,7 +117,7 @@ func (c *context) matchKeyValue(f *netmap.Filter, b NodeInfo) bool { default: var err error - attr, err = strconv.ParseUint(b.Attribute(f.GetKey()), 10, 64) + attr, err = strconv.ParseUint(b.Attribute(f.Key()), 10, 64) if err != nil { // Note: because filters are somewhat independent from nodes attributes, // We don't report an error here, and fail filter instead. @@ -125,14 +126,14 @@ func (c *context) matchKeyValue(f *netmap.Filter, b NodeInfo) bool { } switch op { - case netmap.GT: - return attr > c.numCache[f.GetValue()] - case netmap.GE: - return attr >= c.numCache[f.GetValue()] - case netmap.LT: - return attr < c.numCache[f.GetValue()] - case netmap.LE: - return attr <= c.numCache[f.GetValue()] + case FilterOpGT: + return attr > c.numCache[f.Value()] + case FilterOpGE: + return attr >= c.numCache[f.Value()] + case FilterOpLT: + return attr < c.numCache[f.Value()] + case FilterOpLE: + return attr <= c.numCache[f.Value()] default: // do nothing and return false } diff --git a/netmap/filter_test.go b/netmap/filter_test.go index fc300737..bb057d08 100644 --- a/netmap/filter_test.go +++ b/netmap/filter_test.go @@ -4,17 +4,16 @@ import ( "errors" "testing" - "github.com/nspcc-dev/neofs-api-go/v2/netmap" "github.com/stretchr/testify/require" ) func TestContext_ProcessFilters(t *testing.T) { fs := []Filter{ - newFilter("StorageSSD", "Storage", "SSD", netmap.EQ), - newFilter("GoodRating", "Rating", "4", netmap.GE), - newFilter("Main", "", "", netmap.AND, + newFilter("StorageSSD", "Storage", "SSD", FilterOpEQ), + newFilter("GoodRating", "Rating", "4", FilterOpGE), + newFilter("Main", "", "", FilterOpAND, newFilter("StorageSSD", "", "", 0), - newFilter("", "IntField", "123", netmap.LT), + newFilter("", "IntField", "123", FilterOpLT), newFilter("GoodRating", "", "", 0)), } @@ -23,11 +22,11 @@ func TestContext_ProcessFilters(t *testing.T) { require.NoError(t, c.processFilters(p)) require.Equal(t, 3, len(c.processedFilters)) for _, f := range fs { - require.Equal(t, f.m, *c.processedFilters[f.m.GetName()]) + require.Equal(t, f, *c.processedFilters[f.Name()]) } - require.Equal(t, uint64(4), c.numCache[fs[1].m.GetValue()]) - require.Equal(t, uint64(123), c.numCache[fs[2].m.GetFilters()[1].GetValue()]) + require.Equal(t, uint64(4), c.numCache[fs[1].Value()]) + require.Equal(t, uint64(123), c.numCache[fs[2].SubFilters()[1].Value()]) } func TestContext_ProcessFiltersInvalid(t *testing.T) { @@ -38,24 +37,24 @@ func TestContext_ProcessFiltersInvalid(t *testing.T) { }{ { "UnnamedTop", - newFilter("", "Storage", "SSD", netmap.EQ), + newFilter("", "Storage", "SSD", FilterOpEQ), errUnnamedTopFilter, }, { "InvalidReference", - newFilter("Main", "", "", netmap.AND, + newFilter("Main", "", "", FilterOpAND, newFilter("StorageSSD", "", "", 0)), errFilterNotFound, }, { "NonEmptyKeyed", - newFilter("Main", "Storage", "SSD", netmap.EQ, + newFilter("Main", "Storage", "SSD", FilterOpEQ, newFilter("StorageSSD", "", "", 0)), errNonEmptyFilters, }, { "InvalidNumber", - newFilter("Main", "Rating", "three", netmap.GE), + newFilter("Main", "Rating", "three", FilterOpGE), errInvalidNumber, }, { @@ -65,7 +64,7 @@ func TestContext_ProcessFiltersInvalid(t *testing.T) { }, { "InvalidName", - newFilter("*", "Rating", "3", netmap.GE), + newFilter("*", "Rating", "3", FilterOpGE), errInvalidFilterName, }, } @@ -84,12 +83,12 @@ func TestFilter_MatchSimple_InvalidOp(t *testing.T) { b.SetAttribute("Rating", "4") b.SetAttribute("Country", "Germany") - f := newFilter("Main", "Rating", "5", netmap.EQ) + f := newFilter("Main", "Rating", "5", FilterOpEQ) c := newContext(NetMap{}) p := newPlacementPolicy(1, nil, nil, []Filter{f}) require.NoError(t, c.processFilters(p)) // just for the coverage - f.m.SetOp(0) - require.False(t, c.match(&f.m, b)) + f.op = 0 + require.False(t, c.match(&f, b)) } diff --git a/netmap/helper_test.go b/netmap/helper_test.go index 0eff22af..e84ff3db 100644 --- a/netmap/helper_test.go +++ b/netmap/helper_test.go @@ -1,19 +1,11 @@ package netmap -import ( - "github.com/nspcc-dev/neofs-api-go/v2/netmap" -) - -func newFilter(name string, k, v string, op netmap.Operation, fs ...Filter) (f Filter) { +func newFilter(name string, k, v string, op FilterOp, fs ...Filter) (f Filter) { f.SetName(name) - f.m.SetKey(k) - f.m.SetOp(op) - f.m.SetValue(v) - inner := make([]netmap.Filter, len(fs)) - for i := range fs { - inner[i] = fs[i].m - } - f.m.SetFilters(inner) + f.key = k + f.op = op + f.val = v + f.subs = fs return f } diff --git a/netmap/netmap.go b/netmap/netmap.go index 0f3249a2..e791568c 100644 --- a/netmap/netmap.go +++ b/netmap/netmap.go @@ -196,12 +196,12 @@ func (m NetMap) ContainerNodes(p PlacementPolicy, containerID cid.ID) ([][]NodeI result := make([][]NodeInfo, len(p.replicas)) for i := range p.replicas { - sName := p.replicas[i].GetSelector() + sName := p.replicas[i].SelectorName() if sName == "" { if len(p.selectors) == 0 { - var s netmap.Selector - s.SetCount(p.replicas[i].GetCount()) - s.SetFilter(mainFilterName) + var s Selector + s.SetNumberOfNodes(p.replicas[i].NumberOfObjects()) + s.SetFilterName(mainFilterName) nodes, err := c.getSelection(p, s) if err != nil { @@ -212,7 +212,7 @@ func (m NetMap) ContainerNodes(p PlacementPolicy, containerID cid.ID) ([][]NodeI } for i := range p.selectors { - result[i] = append(result[i], flattenNodes(c.selections[p.selectors[i].GetName()])...) + result[i] = append(result[i], flattenNodes(c.selections[p.selectors[i].Name()])...) } continue diff --git a/netmap/network_info.go b/netmap/network_info.go index 762e1c36..5aed3f39 100644 --- a/netmap/network_info.go +++ b/netmap/network_info.go @@ -1,50 +1,54 @@ package netmap import ( - "bytes" "encoding/binary" "errors" "fmt" "math" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "github.com/nspcc-dev/neofs-api-go/v2/netmap" + neofsproto "github.com/nspcc-dev/neofs-sdk-go/internal/proto" + protonetmap "github.com/nspcc-dev/neofs-sdk-go/proto/netmap" + "google.golang.org/protobuf/encoding/protojson" ) // NetworkInfo groups information about the NeoFS network state. Mainly used to // describe the current state of the network. // -// NetworkInfo is mutually compatible with github.com/nspcc-dev/neofs-api-go/v2/netmap.NetworkInfo -// message. See ReadFromV2 / WriteToV2 methods. +// NetworkInfo is mutually compatible with [protonetmap.NetworkInfo] +// message. See [NetworkInfo.FromProtoMessage] / [NetworkInfo.ProtoMessage] methods. // // Instances can be created using built-in var declaration. type NetworkInfo struct { - m netmap.NetworkInfo + curEpoch uint64 + netMagic uint64 + msPerBlock int64 + prms [][2][]byte } // reads NetworkInfo from netmap.NetworkInfo message. If checkFieldPresence is set, // returns an error on absence of any protocol-required field. Verifies format of any // presented field according to NeoFS API V2 protocol. -func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool) error { +func (x *NetworkInfo) fromProtoMessage(m *protonetmap.NetworkInfo, checkFieldPresence bool) error { c := m.GetNetworkConfig() if checkFieldPresence && c == nil { return errors.New("missing network config") } - if checkFieldPresence && c.NumberOfParameters() <= 0 { + if checkFieldPresence && len(c.Parameters) == 0 { return errors.New("missing network parameters") } var err error - mNames := make(map[string]struct{}, c.NumberOfParameters()) + mNames := make(map[string]struct{}, len(c.Parameters)) + prms := make([][2][]byte, len(c.Parameters)) - c.IterateParameters(func(prm *netmap.NetworkParameter) bool { + for _, prm := range c.Parameters { name := string(prm.GetKey()) _, was := mNames[name] if was { - err = fmt.Errorf("duplicated parameter name: %s", name) - return true + return fmt.Errorf("duplicated parameter name: %s", name) } mNames[name] = struct{}{} @@ -52,8 +56,7 @@ func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool) switch name { default: if len(prm.GetValue()) == 0 { - err = fmt.Errorf("empty attribute value %s", name) - return true + return fmt.Errorf("empty attribute value %s", name) } case configEigenTrustAlpha: var num uint64 @@ -61,7 +64,7 @@ func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool) num, err = decodeConfigValueUint64(prm.GetValue()) if err == nil { if alpha := math.Float64frombits(num); alpha < 0 || alpha > 1 { - err = fmt.Errorf("EigenTrust alpha value %0.2f is out of range [0, 1]", alpha) + return fmt.Errorf("EigenTrust alpha value %0.2f is out of range [0, 1]", alpha) } } case @@ -81,35 +84,47 @@ func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool) } if err != nil { - err = fmt.Errorf("invalid %s parameter: %w", name, err) + return fmt.Errorf("invalid %s parameter: %w", name, err) } - return err != nil - }) - - if err != nil { - return err + prms = append(prms, [2][]byte{prm.Key, prm.Value}) } - x.m = m + x.curEpoch = m.CurrentEpoch + x.netMagic = m.MagicNumber + x.msPerBlock = m.MsPerBlock + x.prms = prms return nil } -// ReadFromV2 reads NetworkInfo from the netmap.NetworkInfo message. Checks if the -// message conforms to NeoFS API V2 protocol. +// FromProtoMessage validates m according to the NeoFS API protocol and restores +// x from it. // -// See also WriteToV2. -func (x *NetworkInfo) ReadFromV2(m netmap.NetworkInfo) error { - return x.readFromV2(m, true) +// See also [NetworkInfo.ProtoMessage]. +func (x *NetworkInfo) FromProtoMessage(m *protonetmap.NetworkInfo) error { + return x.fromProtoMessage(m, true) } -// WriteToV2 writes NetworkInfo to the netmap.NetworkInfo message. The message -// MUST NOT be nil. +// ProtoMessage converts x into message to transmit using the NeoFS API +// protocol. // -// See also ReadFromV2. -func (x NetworkInfo) WriteToV2(m *netmap.NetworkInfo) { - *m = x.m +// See also [NetworkInfo.FromProtoMessage]. +func (x NetworkInfo) ProtoMessage() *protonetmap.NetworkInfo { + m := &protonetmap.NetworkInfo{ + CurrentEpoch: x.curEpoch, + MagicNumber: x.netMagic, + MsPerBlock: x.msPerBlock, + } + if len(x.prms) > 0 { + m.NetworkConfig = &protonetmap.NetworkConfig{ + Parameters: make([]*protonetmap.NetworkConfig_Parameter, len(x.prms)), + } + for i := range x.prms { + m.NetworkConfig.Parameters[i] = &protonetmap.NetworkConfig_Parameter{Key: x.prms[i][0], Value: x.prms[i][1]} + } + } + return m } // Marshal encodes NetworkInfo into a binary format of the NeoFS API protocol @@ -117,10 +132,7 @@ func (x NetworkInfo) WriteToV2(m *netmap.NetworkInfo) { // // See also Unmarshal. func (x NetworkInfo) Marshal() []byte { - var m netmap.NetworkInfo - x.WriteToV2(&m) - - return m.StableMarshal(nil) + return neofsproto.MarshalMessage(x.ProtoMessage()) } // Unmarshal decodes NeoFS API protocol binary format into the NetworkInfo @@ -129,105 +141,72 @@ func (x NetworkInfo) Marshal() []byte { // // See also Marshal. func (x *NetworkInfo) Unmarshal(data []byte) error { - var m netmap.NetworkInfo + var m protonetmap.NetworkInfo - err := m.Unmarshal(data) + err := protojson.Unmarshal(data, &m) if err != nil { return err } - return x.readFromV2(m, false) + return x.fromProtoMessage(&m, false) } // CurrentEpoch returns epoch set using SetCurrentEpoch. // // Zero NetworkInfo has zero current epoch. func (x NetworkInfo) CurrentEpoch() uint64 { - return x.m.GetCurrentEpoch() + return x.curEpoch } // SetCurrentEpoch sets current epoch of the NeoFS network. func (x *NetworkInfo) SetCurrentEpoch(epoch uint64) { - x.m.SetCurrentEpoch(epoch) + x.curEpoch = epoch } // MagicNumber returns magic number set using SetMagicNumber. // // Zero NetworkInfo has zero magic. func (x NetworkInfo) MagicNumber() uint64 { - return x.m.GetMagicNumber() + return x.netMagic } // SetMagicNumber sets magic number of the NeoFS Sidechain. // // See also MagicNumber. func (x *NetworkInfo) SetMagicNumber(epoch uint64) { - x.m.SetMagicNumber(epoch) + x.netMagic = epoch } // MsPerBlock returns network parameter set using SetMsPerBlock. func (x NetworkInfo) MsPerBlock() int64 { - return x.m.GetMsPerBlock() + return x.msPerBlock } // SetMsPerBlock sets MillisecondsPerBlock network parameter of the NeoFS Sidechain. // // See also MsPerBlock. func (x *NetworkInfo) SetMsPerBlock(v int64) { - x.m.SetMsPerBlock(v) + x.msPerBlock = v } func (x *NetworkInfo) setConfig(name string, val []byte) { - c := x.m.GetNetworkConfig() - if c == nil { - c = new(netmap.NetworkConfig) - - var prm netmap.NetworkParameter - prm.SetKey([]byte(name)) - prm.SetValue(val) - - c.SetParameters(prm) - - x.m.SetNetworkConfig(c) - - return - } - - found := false - prms := make([]netmap.NetworkParameter, 0, c.NumberOfParameters()) - - c.IterateParameters(func(prm *netmap.NetworkParameter) bool { - found = bytes.Equal(prm.GetKey(), []byte(name)) - if found { - prm.SetValue(val) - } else { - prms = append(prms, *prm) + for i := range x.prms { + if string(x.prms[i][0]) == name { + x.prms[i][1] = val + return } - - return found - }) - - if !found { - prms = append(prms, netmap.NetworkParameter{}) - prms[len(prms)-1].SetKey([]byte(name)) - prms[len(prms)-1].SetValue(val) - - c.SetParameters(prms...) } -} -func (x NetworkInfo) configValue(name string) (res []byte) { - x.m.GetNetworkConfig().IterateParameters(func(prm *netmap.NetworkParameter) bool { - if string(prm.GetKey()) == name { - res = prm.GetValue() + x.prms = append(x.prms, [2][]byte{[]byte(name), val}) +} - return true +func (x NetworkInfo) configValue(name string) []byte { + for i := range x.prms { + if string(x.prms[i][0]) == name { + return x.prms[i][1] } - - return false - }) - - return + } + return nil } // SetRawNetworkParameter sets named NeoFS network parameter whose value is @@ -258,13 +237,11 @@ func (x *NetworkInfo) RawNetworkParameter(name string) []byte { // // Zero NetworkInfo has no network parameters. func (x *NetworkInfo) IterateRawNetworkParameters(f func(name string, value []byte)) { - c := x.m.GetNetworkConfig() - - c.IterateParameters(func(prm *netmap.NetworkParameter) bool { - name := string(prm.GetKey()) + for i := range x.prms { + name := string(x.prms[i][0]) switch name { default: - f(name, prm.GetValue()) + f(name, x.prms[i][1]) case configEigenTrustAlpha, configAuditFee, @@ -279,9 +256,7 @@ func (x *NetworkInfo) IterateRawNetworkParameters(f func(name string, value []by configHomomorphicHashingDisabled, configMaintenanceModeAllowed: } - - return false - }) + } } func (x *NetworkInfo) setConfigUint64(name string, num uint64) { @@ -332,7 +307,7 @@ func (x NetworkInfo) configUint64(name string) uint64 { res, err := decodeConfigValueUint64(val) if err != nil { // potential panic is OK since value MUST be correct since it is - // verified in ReadFromV2 or set by provided method. + // verified in FromProtoMessage or set by provided method. panic(err) } @@ -348,7 +323,7 @@ func (x NetworkInfo) configBool(name string) bool { res, err := decodeConfigValueBool(val) if err != nil { // potential panic is OK since value MUST be correct since it is - // verified in ReadFromV2 or set by provided method. + // verified in FromProtoMessage or set by provided method. panic(err) } diff --git a/netmap/node_info.go b/netmap/node_info.go index d852cb88..078a5183 100644 --- a/netmap/node_info.go +++ b/netmap/node_info.go @@ -8,8 +8,11 @@ import ( "strings" "github.com/nspcc-dev/hrw/v2" - "github.com/nspcc-dev/neofs-api-go/v2/netmap" neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto" + neofsproto "github.com/nspcc-dev/neofs-sdk-go/internal/proto" + protonetmap "github.com/nspcc-dev/neofs-sdk-go/proto/netmap" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) // NodeInfo groups information about NeoFS storage node which is reflected @@ -18,18 +21,24 @@ import ( // about the nodes is available to all network participants to work with the network // map (mainly to comply with container storage policies). // -// NodeInfo is mutually compatible with github.com/nspcc-dev/neofs-api-go/v2/netmap.NodeInfo -// message. See ReadFromV2 / WriteToV2 methods. +// NodeInfo is mutually compatible with [protonetmap.NodeInfo] message. See +// [NodeInfo.FromProtoMessage] / [NodeInfo.ProtoMessage] methods. // // Instances can be created using built-in var declaration. type NodeInfo struct { - m netmap.NodeInfo + state protonetmap.NodeInfo_State + pub []byte + addrs []string + attrs [][2]string } // reads NodeInfo from netmap.NodeInfo message. If checkFieldPresence is set, // returns an error on absence of any protocol-required field. Verifies format of any // presented field according to NeoFS API V2 protocol. -func (x *NodeInfo) readFromV2(m netmap.NodeInfo, checkFieldPresence bool) error { +func (x *NodeInfo) fromProtoMessage(m *protonetmap.NodeInfo, checkFieldPresence bool) error { + if m.State < 0 { + return fmt.Errorf("negative state %d", m.State) + } var err error binPublicKey := m.GetPublicKey() @@ -37,12 +46,13 @@ func (x *NodeInfo) readFromV2(m netmap.NodeInfo, checkFieldPresence bool) error return errors.New("missing public key") } - if checkFieldPresence && m.NumberOfAddresses() <= 0 { + if checkFieldPresence && len(m.Addresses) == 0 { return errors.New("missing network endpoints") } attributes := m.GetAttributes() mAttr := make(map[string]struct{}, len(attributes)) + attrs := make([][2]string, len(attributes)) for i := range attributes { key := attributes[i].GetKey() if key == "" { @@ -51,46 +61,62 @@ func (x *NodeInfo) readFromV2(m netmap.NodeInfo, checkFieldPresence bool) error return fmt.Errorf("duplicated attribute %s", key) } + val := attributes[i].GetValue() switch { case key == attrCapacity: - _, err = strconv.ParseUint(attributes[i].GetValue(), 10, 64) + _, err = strconv.ParseUint(val, 10, 64) if err != nil { return fmt.Errorf("invalid %s attribute: %w", attrCapacity, err) } case key == attrPrice: var err error - _, err = strconv.ParseUint(attributes[i].GetValue(), 10, 64) + _, err = strconv.ParseUint(val, 10, 64) if err != nil { return fmt.Errorf("invalid %s attribute: %w", attrPrice, err) } default: - if attributes[i].GetValue() == "" { + if val == "" { return fmt.Errorf("empty value of the attribute %s", key) } } mAttr[key] = struct{}{} + attrs[i][0], attrs[i][1] = key, val } - x.m = m + x.state = m.State + x.pub = m.PublicKey + x.addrs = m.Addresses + x.attrs = attrs return nil } -// ReadFromV2 reads NodeInfo from the netmap.NodeInfo message. Checks if the -// message conforms to NeoFS API V2 protocol. +// FromProtoMessage validates m according to the NeoFS API protocol and restores +// x from it. // -// See also WriteToV2. -func (x *NodeInfo) ReadFromV2(m netmap.NodeInfo) error { - return x.readFromV2(m, true) +// See also [NodeInfo.ProtoMessage]. +func (x *NodeInfo) FromProtoMessage(m *protonetmap.NodeInfo) error { + return x.fromProtoMessage(m, true) } -// WriteToV2 writes NodeInfo to the netmap.NodeInfo message. The message MUST NOT -// be nil. +// ProtoMessage converts x into message to transmit using the NeoFS API +// protocol. // -// See also ReadFromV2. -func (x NodeInfo) WriteToV2(m *netmap.NodeInfo) { - *m = x.m +// See also [NodeInfo.FromProtoMessage]. +func (x NodeInfo) ProtoMessage() *protonetmap.NodeInfo { + m := &protonetmap.NodeInfo{ + PublicKey: x.pub, + Addresses: x.addrs, + State: x.state, + } + if len(x.attrs) > 0 { + m.Attributes = make([]*protonetmap.NodeInfo_Attribute, len(x.attrs)) + for i := range x.attrs { + m.Attributes[i] = &protonetmap.NodeInfo_Attribute{Key: x.attrs[i][0], Value: x.attrs[i][1]} + } + } + return m } // Marshal encodes NodeInfo into a binary format of the NeoFS API protocol @@ -98,10 +124,7 @@ func (x NodeInfo) WriteToV2(m *netmap.NodeInfo) { // // See also Unmarshal. func (x NodeInfo) Marshal() []byte { - var m netmap.NodeInfo - x.WriteToV2(&m) - - return m.StableMarshal(nil) + return neofsproto.MarshalMessage(x.ProtoMessage()) } // Unmarshal decodes NeoFS API protocol binary format into the NodeInfo @@ -110,14 +133,14 @@ func (x NodeInfo) Marshal() []byte { // // See also Marshal. func (x *NodeInfo) Unmarshal(data []byte) error { - var m netmap.NodeInfo + var m protonetmap.NodeInfo - err := m.Unmarshal(data) + err := proto.Unmarshal(data, &m) if err != nil { return err } - return x.readFromV2(m, false) + return x.fromProtoMessage(&m, false) } // MarshalJSON encodes NodeInfo into a JSON format of the NeoFS API protocol @@ -125,10 +148,7 @@ func (x *NodeInfo) Unmarshal(data []byte) error { // // See also UnmarshalJSON. func (x NodeInfo) MarshalJSON() ([]byte, error) { - var m netmap.NodeInfo - x.WriteToV2(&m) - - return m.MarshalJSON() + return neofsproto.MarshalMessageJSON(x.ProtoMessage()) } // UnmarshalJSON decodes NeoFS API protocol JSON format into the NodeInfo @@ -136,14 +156,14 @@ func (x NodeInfo) MarshalJSON() ([]byte, error) { // // See also MarshalJSON. func (x *NodeInfo) UnmarshalJSON(data []byte) error { - var m netmap.NodeInfo + var m protonetmap.NodeInfo - err := m.UnmarshalJSON(data) + err := protojson.Unmarshal(data, &m) if err != nil { return err } - return x.readFromV2(m, false) + return x.fromProtoMessage(&m, false) } // SetPublicKey sets binary-encoded public key bound to the node. The key @@ -155,7 +175,7 @@ func (x *NodeInfo) UnmarshalJSON(data []byte) error { // // See also [NodeInfo.PublicKey]. func (x *NodeInfo) SetPublicKey(key []byte) { - x.m.SetPublicKey(key) + x.pub = key } // PublicKey returns value set using [NodeInfo.SetPublicKey]. @@ -169,7 +189,7 @@ func (x *NodeInfo) SetPublicKey(key []byte) { // The value returned shares memory with the structure itself, so changing it can lead to data corruption. // Make a copy if you need to change it. func (x NodeInfo) PublicKey() []byte { - return x.m.GetPublicKey() + return x.pub } // StringifyPublicKey returns HEX representation of PublicKey. @@ -187,14 +207,14 @@ func StringifyPublicKey(node NodeInfo) string { // // See also IterateNetworkEndpoints. func (x *NodeInfo) SetNetworkEndpoints(v ...string) { - x.m.SetAddresses(v...) + x.addrs = v } // NumberOfNetworkEndpoints returns number of network endpoints announced by the node. // // See also SetNetworkEndpoints. func (x NodeInfo) NumberOfNetworkEndpoints() int { - return x.m.NumberOfAddresses() + return len(x.addrs) } // IterateNetworkEndpoints iterates over network endpoints announced by the @@ -206,7 +226,11 @@ func (x NodeInfo) NumberOfNetworkEndpoints() int { // // See also SetNetworkEndpoints. func (x NodeInfo) IterateNetworkEndpoints(f func(string) bool) { - x.m.IterateAddresses(f) + for i := range x.addrs { + if f(x.addrs[i]) { + return + } + } } // IterateNetworkEndpoints is an extra-sugared function over IterateNetworkEndpoints @@ -226,7 +250,7 @@ var _ hrw.Hashable = NodeInfo{} // Hash is needed to support weighted HRW therefore sort function sorts nodes // based on their public key. Hash isn't expected to be used directly. func (x NodeInfo) Hash() uint64 { - return hrw.Hash(x.m.GetPublicKey()) + return hrw.Hash(x.PublicKey()) } // less declares "less than" comparison between two NodeInfo instances: @@ -448,15 +472,14 @@ func (x NodeInfo) ExternalAddresses() []string { // // See also SetAttribute. func (x NodeInfo) NumberOfAttributes() int { - return len(x.m.GetAttributes()) + return len(x.attrs) } // IterateAttributes iterates over all node attributes and passes the into f. // Handler MUST NOT be nil. func (x NodeInfo) IterateAttributes(f func(key, value string)) { - a := x.m.GetAttributes() - for i := range a { - f(a[i].GetKey(), a[i].GetValue()) + for i := range x.attrs { + f(x.attrs[i][0], x.attrs[i][1]) } } @@ -465,11 +488,7 @@ func (x NodeInfo) IterateAttributes(f func(key, value string)) { // // See also Attribute, IterateAttributes. func (x NodeInfo) GetAttributes() [][2]string { - attrs := make([][2]string, len(x.m.GetAttributes())) - for i, attr := range x.m.GetAttributes() { - attrs[i] = [2]string{attr.GetKey(), attr.GetValue()} - } - return attrs + return x.attrs } // SetAttributes sets list of node attributes. @@ -478,7 +497,6 @@ func (x NodeInfo) GetAttributes() [][2]string { // // See also SetAttribute. func (x *NodeInfo) SetAttributes(attrs [][2]string) { - netmapAttrs := make([]netmap.Attribute, 0, len(attrs)) for _, attr := range attrs { if attr[0] == "" { panic("empty key in SetAttributes") @@ -486,13 +504,9 @@ func (x *NodeInfo) SetAttributes(attrs [][2]string) { if attr[1] == "" { panic(fmt.Errorf("empty value in SetAttributes for key: %s", attr[0])) } - - netmapAttrs = append(netmapAttrs, netmap.Attribute{}) - netmapAttrs[len(netmapAttrs)-1].SetKey(attr[0]) - netmapAttrs[len(netmapAttrs)-1].SetValue(attr[1]) } - x.m.SetAttributes(netmapAttrs) + x.attrs = attrs } // SetAttribute sets value of the node attribute value by the given key. @@ -504,28 +518,22 @@ func (x *NodeInfo) SetAttribute(key, value string) { panic("empty value in SetAttribute") } - a := x.m.GetAttributes() - for i := range a { - if a[i].GetKey() == key { - a[i].SetValue(value) + for i := range x.attrs { + if x.attrs[i][0] == key { + x.attrs[i][1] = value return } } - a = append(a, netmap.Attribute{}) - a[len(a)-1].SetKey(key) - a[len(a)-1].SetValue(value) - - x.m.SetAttributes(a) + x.attrs = append(x.attrs, [2]string{key, value}) } // Attribute returns value of the node attribute set using SetAttribute by the // given key. Returns empty string if attribute is missing. func (x NodeInfo) Attribute(key string) string { - a := x.m.GetAttributes() - for i := range a { - if a[i].GetKey() == key { - return a[i].GetValue() + for i := range x.attrs { + if x.attrs[i][0] == key { + return x.attrs[i][0] } } @@ -535,30 +543,27 @@ func (x NodeInfo) Attribute(key string) string { // SortAttributes sorts node attributes set using SetAttribute lexicographically. // The method is only needed to make NodeInfo consistent, e.g. for signing. func (x *NodeInfo) SortAttributes() { - as := x.m.GetAttributes() - if len(as) == 0 { + if len(x.attrs) == 0 { return } - sort.Slice(as, func(i, j int) bool { - switch strings.Compare(as[i].GetKey(), as[j].GetKey()) { + sort.Slice(x.attrs, func(i, j int) bool { + switch strings.Compare(x.attrs[i][0], x.attrs[j][0]) { case -1: return true case 1: return false default: - return as[i].GetValue() < as[j].GetValue() + return x.attrs[i][1] < x.attrs[j][1] } }) - - x.m.SetAttributes(as) } // SetOffline sets the state of the node to "offline". When a node updates // information about itself in the network map, this action is interpreted as // an intention to leave the network. func (x *NodeInfo) SetOffline() { - x.m.SetState(netmap.Offline) + x.state = protonetmap.NodeInfo_OFFLINE } // IsOffline checks if the node is in the "offline" state. @@ -568,7 +573,7 @@ func (x *NodeInfo) SetOffline() { // // See also SetOffline. func (x NodeInfo) IsOffline() bool { - return x.m.GetState() == netmap.Offline + return x.state == protonetmap.NodeInfo_OFFLINE } // SetOnline sets the state of the node to "online". When a node updates @@ -577,7 +582,7 @@ func (x NodeInfo) IsOffline() bool { // // See also IsOnline. func (x *NodeInfo) SetOnline() { - x.m.SetState(netmap.Online) + x.state = protonetmap.NodeInfo_ONLINE } // IsOnline checks if the node is in the "online" state. @@ -587,7 +592,7 @@ func (x *NodeInfo) SetOnline() { // // See also SetOnline. func (x NodeInfo) IsOnline() bool { - return x.m.GetState() == netmap.Online + return x.state == protonetmap.NodeInfo_ONLINE } // SetMaintenance sets the state of the node to "maintenance". When a node updates @@ -596,7 +601,7 @@ func (x NodeInfo) IsOnline() bool { // // See also IsMaintenance. func (x *NodeInfo) SetMaintenance() { - x.m.SetState(netmap.Maintenance) + x.state = protonetmap.NodeInfo_MAINTENANCE } // IsMaintenance checks if the node is in the "maintenance" state. @@ -605,7 +610,7 @@ func (x *NodeInfo) SetMaintenance() { // // See also SetMaintenance. func (x NodeInfo) IsMaintenance() bool { - return x.m.GetState() == netmap.Maintenance + return x.state == protonetmap.NodeInfo_MAINTENANCE } const attrVerifiedNodesDomain = "VerifiedNodesDomain" diff --git a/netmap/policy.go b/netmap/policy.go index a2e6b773..e231998b 100644 --- a/netmap/policy.go +++ b/netmap/policy.go @@ -6,33 +6,35 @@ import ( "io" "slices" "strconv" - "strings" "github.com/antlr4-go/antlr/v4" - "github.com/nspcc-dev/neofs-api-go/v2/netmap" + neofsproto "github.com/nspcc-dev/neofs-sdk-go/internal/proto" "github.com/nspcc-dev/neofs-sdk-go/netmap/parser" + protonetmap "github.com/nspcc-dev/neofs-sdk-go/proto/netmap" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) // PlacementPolicy declares policy to store objects in the NeoFS container. // Within itself, PlacementPolicy represents a set of rules to select a subset // of nodes from NeoFS network map - node-candidates for object storage. // -// PlacementPolicy is mutually compatible with github.com/nspcc-dev/neofs-api-go/v2/netmap.PlacementPolicy -// message. See ReadFromV2 / WriteToV2 methods. +// PlacementPolicy is mutually compatible with [protonetmap.PlacementPolicy] +// message. See [PlacementPolicy.FromProtoMessage] / [PlacementPolicy.ProtoMessage] methods. // // Instances can be created using built-in var declaration. type PlacementPolicy struct { backupFactor uint32 - filters []netmap.Filter + filters []Filter - selectors []netmap.Selector + selectors []Selector - replicas []netmap.Replica + replicas []ReplicaDescriptor } // FilterOp defines the matching property. -type FilterOp uint32 +type FilterOp int32 // Supported FilterOp values. const ( @@ -71,24 +73,15 @@ func (x FilterOp) String() string { } } -func copyFilter(f netmap.Filter) netmap.Filter { - var filter netmap.Filter +func copyFilter(f Filter) Filter { + filter := f - filter.SetName(f.GetName()) - filter.SetKey(f.GetKey()) - filter.SetOp(f.GetOp()) - filter.SetValue(f.GetValue()) + if len(f.subs) > 0 { + filter.subs = make([]Filter, len(f.subs)) - if f.GetFilters() != nil { - filters := make([]netmap.Filter, len(f.GetFilters())) - - for i, internalFilter := range f.GetFilters() { - filters[i] = copyFilter(internalFilter) + for i := range f.subs { + filter.subs[i] = copyFilter(f.subs[i]) } - - filter.SetFilters(filters) - } else { - filter.SetFilters(nil) } return filter @@ -98,27 +91,52 @@ func copyFilter(f netmap.Filter) netmap.Filter { func (p PlacementPolicy) CopyTo(dst *PlacementPolicy) { dst.SetContainerBackupFactor(p.backupFactor) - dst.filters = make([]netmap.Filter, len(p.filters)) - for i, f := range p.filters { - dst.filters[i] = copyFilter(f) + dst.filters = make([]Filter, len(p.filters)) + for i := range p.filters { + dst.filters[i] = copyFilter(p.filters[i]) } - // netmap.Selector is a struct with simple types, no links inside. Just create a new slice and copy all items inside. + // protonetmap.Selector is a struct with simple types, no links inside. Just create a new slice and copy all items inside. dst.selectors = slices.Clone(p.selectors) - // netmap.Replica is a struct with simple types, no links inside. Just create a new slice and copy all items inside. + // protonetmap.Replica is a struct with simple types, no links inside. Just create a new slice and copy all items inside. dst.replicas = slices.Clone(p.replicas) } -func (p *PlacementPolicy) readFromV2(m netmap.PlacementPolicy, checkFieldPresence bool) error { - p.replicas = m.GetReplicas() - if checkFieldPresence && len(p.replicas) == 0 { +func (p *PlacementPolicy) readFromV2(m *protonetmap.PlacementPolicy, checkFieldPresence bool) error { + if checkFieldPresence && len(m.Replicas) == 0 { return errors.New("missing replicas") } + p.replicas = make([]ReplicaDescriptor, len(m.Replicas)) + for i, r := range m.Replicas { + if r == nil { + return fmt.Errorf("nil replica #%d", i) + } + p.replicas[i].fromProtoMessage(r) + } + + p.selectors = make([]Selector, len(m.Selectors)) + for i, s := range m.Selectors { + if s == nil { + return fmt.Errorf("nil selector #%d", i) + } + if err := p.selectors[i].fromProtoMessage(s); err != nil { + return fmt.Errorf("invalid selector #%d: %w", i, err) + } + } + + p.filters = make([]Filter, len(m.Filters)) + for i, f := range m.Filters { + if f == nil { + return fmt.Errorf("nil filter #%d", i) + } + if err := p.filters[i].fromProtoMessage(f); err != nil { + return fmt.Errorf("invalid filter #%d: %w", i, err) + } + } + p.backupFactor = m.GetContainerBackupFactor() - p.selectors = m.GetSelectors() - p.filters = m.GetFilters() return nil } @@ -128,10 +146,7 @@ func (p *PlacementPolicy) readFromV2(m netmap.PlacementPolicy, checkFieldPresenc // // See also Unmarshal. func (p PlacementPolicy) Marshal() []byte { - var m netmap.PlacementPolicy - p.WriteToV2(&m) - - return m.StableMarshal(nil) + return neofsproto.MarshalMessage(p.ProtoMessage()) } // Unmarshal decodes NeoFS API protocol binary format into the PlacementPolicy @@ -140,14 +155,14 @@ func (p PlacementPolicy) Marshal() []byte { // // See also Marshal. func (p *PlacementPolicy) Unmarshal(data []byte) error { - var m netmap.PlacementPolicy + var m protonetmap.PlacementPolicy - err := m.Unmarshal(data) + err := proto.Unmarshal(data, &m) if err != nil { return err } - return p.readFromV2(m, false) + return p.readFromV2(&m, false) } // MarshalJSON encodes PlacementPolicy into a JSON format of the NeoFS API @@ -155,10 +170,7 @@ func (p *PlacementPolicy) Unmarshal(data []byte) error { // // See also UnmarshalJSON. func (p PlacementPolicy) MarshalJSON() ([]byte, error) { - var m netmap.PlacementPolicy - p.WriteToV2(&m) - - return m.MarshalJSON() + return neofsproto.MarshalMessageJSON(p.ProtoMessage()) } // UnmarshalJSON decodes NeoFS API protocol JSON format into the PlacementPolicy @@ -166,51 +178,86 @@ func (p PlacementPolicy) MarshalJSON() ([]byte, error) { // // See also MarshalJSON. func (p *PlacementPolicy) UnmarshalJSON(data []byte) error { - var m netmap.PlacementPolicy + var m protonetmap.PlacementPolicy - err := m.UnmarshalJSON(data) + err := protojson.Unmarshal(data, &m) if err != nil { return err } - return p.readFromV2(m, false) + return p.readFromV2(&m, false) } -// ReadFromV2 reads PlacementPolicy from the netmap.PlacementPolicy message. -// Checks if the message conforms to NeoFS API V2 protocol. +// FromProtoMessage validates m according to the NeoFS API protocol and restores +// p from it. // -// See also WriteToV2. -func (p *PlacementPolicy) ReadFromV2(m netmap.PlacementPolicy) error { +// See also [PlacementPolicy.ProtoMessage]. +func (p *PlacementPolicy) FromProtoMessage(m *protonetmap.PlacementPolicy) error { return p.readFromV2(m, true) } -// WriteToV2 writes PlacementPolicy to the netmap.PlacementPolicy message. -// The message must not be nil. +// ProtoMessage converts p into message to transmit using the NeoFS API +// protocol. // -// See also ReadFromV2. -func (p PlacementPolicy) WriteToV2(m *netmap.PlacementPolicy) { - m.SetContainerBackupFactor(p.backupFactor) - m.SetFilters(p.filters) - m.SetSelectors(p.selectors) - m.SetReplicas(p.replicas) +// See also [PlacementPolicy.FromProtoMessage]. +func (p PlacementPolicy) ProtoMessage() *protonetmap.PlacementPolicy { + m := &protonetmap.PlacementPolicy{ + ContainerBackupFactor: p.backupFactor, + } + if len(p.replicas) > 0 { + m.Replicas = make([]*protonetmap.Replica, len(p.replicas)) + for i := range p.replicas { + m.Replicas[i] = p.replicas[i].protoMessage() + } + } + if len(p.selectors) > 0 { + m.Selectors = make([]*protonetmap.Selector, len(p.selectors)) + for i := range p.selectors { + m.Selectors[i] = p.selectors[i].protoMessage() + } + } + if len(p.filters) > 0 { + m.Filters = make([]*protonetmap.Filter, len(p.filters)) + for i := range p.filters { + m.Filters[i] = p.filters[i].protoMessage() + } + } + return m } // ReplicaDescriptor replica descriptor characterizes replicas of objects from // the subset selected by a particular Selector. type ReplicaDescriptor struct { - m netmap.Replica + count uint32 + selector string +} + +// fromProtoMessage validates m according to the NeoFS API protocol and restores +// r from it. +func (r *ReplicaDescriptor) fromProtoMessage(m *protonetmap.Replica) { + r.count = m.Count + r.selector = m.Selector +} + +// protoMessage converts r into message to transmit using the NeoFS API +// protocol. +func (r ReplicaDescriptor) protoMessage() *protonetmap.Replica { + return &protonetmap.Replica{ + Count: r.count, + Selector: r.selector, + } } // SetNumberOfObjects sets number of object replicas. func (r *ReplicaDescriptor) SetNumberOfObjects(c uint32) { - r.m.SetCount(c) + r.count = c } // NumberOfObjects returns number set using SetNumberOfObjects. // // Zero ReplicaDescriptor has zero number of objects. func (r ReplicaDescriptor) NumberOfObjects() uint32 { - return r.m.GetCount() + return r.count } // SetSelectorName sets name of the related Selector. @@ -220,7 +267,7 @@ func (r ReplicaDescriptor) NumberOfObjects() uint32 { // // See also [ReplicaDescriptor.SelectorName]. func (r *ReplicaDescriptor) SetSelectorName(s string) { - r.m.SetSelector(s) + r.selector = s } // SelectorName returns name of the related Selector. @@ -230,7 +277,7 @@ func (r *ReplicaDescriptor) SetSelectorName(s string) { // // See also [ReplicaDescriptor.SetSelectorName]. func (r ReplicaDescriptor) SelectorName() string { - return r.m.GetSelector() + return r.selector } // SetReplicas sets list of object replica's characteristics. @@ -238,11 +285,7 @@ func (r ReplicaDescriptor) SelectorName() string { // See also [PlacementPolicy.Replicas], [PlacementPolicy.NumberOfReplicas], // [PlacementPolicy.ReplicaNumberByIndex]. func (p *PlacementPolicy) SetReplicas(rs []ReplicaDescriptor) { - p.replicas = make([]netmap.Replica, len(rs)) - - for i := range rs { - p.replicas[i] = rs[i].m - } + p.replicas = rs } // Replicas returns list of object replica characteristics. @@ -250,11 +293,7 @@ func (p *PlacementPolicy) SetReplicas(rs []ReplicaDescriptor) { // See also [PlacementPolicy.SetReplicas], [PlacementPolicy.NumberOfReplicas], // [PlacementPolicy.ReplicaNumberByIndex]. func (p PlacementPolicy) Replicas() []ReplicaDescriptor { - rs := make([]ReplicaDescriptor, len(p.replicas)) - for i := range p.replicas { - rs[i].m = p.replicas[i] - } - return rs + return p.replicas } // NumberOfReplicas returns number of replica descriptors set using SetReplicas. @@ -270,7 +309,7 @@ func (p PlacementPolicy) NumberOfReplicas() int { // // Zero PlacementPolicy has no replicas. func (p PlacementPolicy) ReplicaNumberByIndex(i int) uint32 { - return p.replicas[i].GetCount() + return p.replicas[i].NumberOfObjects() } // SetContainerBackupFactor sets container backup factor: it controls how deep @@ -296,14 +335,44 @@ func (p *PlacementPolicy) ContainerBackupFactor() uint32 { // Selector describes the bucket selection operator: choose a number of nodes // from the bucket taking the nearest nodes to the related container by hash distance. type Selector struct { - m netmap.Selector + name string + count uint32 + clause protonetmap.Clause + attr string + filter string +} + +// fromProtoMessage validates m according to the NeoFS API protocol and restores +// s from it. +func (s *Selector) fromProtoMessage(m *protonetmap.Selector) error { + if m.Clause < 0 { + return fmt.Errorf("negative clause %d", m.Clause) + } + s.name = m.Name + s.count = m.Count + s.clause = m.Clause + s.attr = m.Attribute + s.filter = m.Filter + return nil +} + +// protoMessage converts s into message to transmit using the NeoFS API +// protocol. +func (s Selector) protoMessage() *protonetmap.Selector { + return &protonetmap.Selector{ + Name: s.name, + Count: s.count, + Clause: s.clause, + Attribute: s.attr, + Filter: s.filter, + } } // SetName sets name with which the Selector can be referenced. // // Zero Selector is unnamed. func (s *Selector) SetName(name string) { - s.m.SetName(name) + s.name = name } // Name returns name with which the Selector can be referenced. @@ -312,7 +381,7 @@ func (s *Selector) SetName(name string) { // // See also [Selector.Name]. func (s Selector) Name() string { - return s.m.GetName() + return s.name } // SetNumberOfNodes sets number of nodes to select from the bucket. @@ -321,7 +390,7 @@ func (s Selector) Name() string { // // See also [Selector.NumberOfNodes]. func (s *Selector) SetNumberOfNodes(num uint32) { - s.m.SetCount(num) + s.count = num } // NumberOfNodes returns number of nodes to select from the bucket. @@ -330,7 +399,7 @@ func (s *Selector) SetNumberOfNodes(num uint32) { // // See also [Selector.SetNumberOfNodes]. func (s Selector) NumberOfNodes() uint32 { - return s.m.GetCount() + return s.count } // SelectByBucketAttribute sets attribute of the bucket to select nodes from. @@ -339,7 +408,7 @@ func (s Selector) NumberOfNodes() uint32 { // // See also [Selector.BucketAttribute]. func (s *Selector) SelectByBucketAttribute(bucket string) { - s.m.SetAttribute(bucket) + s.attr = bucket } // BucketAttribute returns attribute of the bucket to select nodes from. @@ -348,7 +417,7 @@ func (s *Selector) SelectByBucketAttribute(bucket string) { // // See also [Selector.SelectByBucketAttribute]. func (s *Selector) BucketAttribute() string { - return s.m.GetAttribute() + return s.attr } // SelectSame makes selection algorithm to select only nodes having the same values @@ -358,7 +427,7 @@ func (s *Selector) BucketAttribute() string { // // See also [Selector.SelectByBucketAttribute], [Selector.IsSame]. func (s *Selector) SelectSame() { - s.m.SetClause(netmap.Same) + s.clause = protonetmap.Clause_SAME } // IsSame checks whether selection algorithm is set to select only nodes having @@ -366,7 +435,7 @@ func (s *Selector) SelectSame() { // // See also [Selector.SelectSame]. func (s *Selector) IsSame() bool { - return s.m.GetClause() == netmap.Same + return s.clause == protonetmap.Clause_SAME } // SelectDistinct makes selection algorithm to select only nodes having the different values @@ -376,7 +445,7 @@ func (s *Selector) IsSame() bool { // // See also [Selector.SelectByBucketAttribute], [Selector.IsDistinct]. func (s *Selector) SelectDistinct() { - s.m.SetClause(netmap.Distinct) + s.clause = protonetmap.Clause_DISTINCT } // IsDistinct checks whether selection algorithm is set to select only nodes @@ -384,7 +453,7 @@ func (s *Selector) SelectDistinct() { // // See also [Selector.SelectByBucketAttribute], [Selector.SelectDistinct]. func (s *Selector) IsDistinct() bool { - return s.m.GetClause() == netmap.Distinct + return s.clause == protonetmap.Clause_DISTINCT } // SetFilterName sets reference to pre-filtering nodes for selection. @@ -393,7 +462,7 @@ func (s *Selector) IsDistinct() bool { // // See also Filter.SetName. func (s *Selector) SetFilterName(f string) { - s.m.SetFilter(f) + s.filter = f } // FilterName returns reference to pre-filtering nodes for selection. @@ -402,7 +471,7 @@ func (s *Selector) SetFilterName(f string) { // // See also [Filter.SetName], [Selector.SetFilterName]. func (s *Selector) FilterName() string { - return s.m.GetFilter() + return s.filter } // SetSelectors sets list of Selector to form the subset of the nodes to store @@ -412,11 +481,7 @@ func (s *Selector) FilterName() string { // // See also [PlacementPolicy.Selectors]. func (p *PlacementPolicy) SetSelectors(ss []Selector) { - p.selectors = make([]netmap.Selector, len(ss)) - - for i := range ss { - p.selectors[i] = ss[i].m - } + p.selectors = ss } // Selectors returns list of Selector to form the subset of the nodes to store @@ -426,16 +491,55 @@ func (p *PlacementPolicy) SetSelectors(ss []Selector) { // // See also [PlacementPolicy.SetSelectors]. func (p PlacementPolicy) Selectors() []Selector { - ss := make([]Selector, len(p.selectors)) - for i := range p.selectors { - ss[i].m = p.selectors[i] - } - return ss + return p.selectors } // Filter contains rules for filtering the node sets. type Filter struct { - m netmap.Filter + name string + key string + op FilterOp + val string + subs []Filter +} + +// fromProtoMessage validates m according to the NeoFS API protocol and restores +// x from it. +func (x *Filter) fromProtoMessage(m *protonetmap.Filter) error { + if m.Op < 0 { + return fmt.Errorf("negative op %d", m.Op) + } + var subs []Filter + if len(m.Filters) > 0 { + subs = make([]Filter, len(m.Filters)) + for i := range m.Filters { + if err := subs[i].fromProtoMessage(m.Filters[i]); err != nil { + return fmt.Errorf("invalid sub-filter #%d: %w", i, err) + } + } + } + x.name = m.Name + x.setAttribute(m.Key, FilterOp(m.Op), m.Value) + x.subs = subs + return nil +} + +// protoMessage converts x into message to transmit using the NeoFS API +// protocol. +func (x Filter) protoMessage() *protonetmap.Filter { + m := &protonetmap.Filter{ + Name: x.name, + Key: x.key, + Op: protonetmap.Operation(x.op), + Value: x.val, + } + if len(x.subs) > 0 { + m.Filters = make([]*protonetmap.Filter, len(x.subs)) + for i := range x.subs { + m.Filters[i] = x.subs[i].protoMessage() + } + } + return m } // SetName sets name with which the Filter can be referenced or, for inner filters, @@ -446,7 +550,7 @@ type Filter struct { // // See also [Filter.Name]. func (x *Filter) SetName(name string) { - x.m.SetName(name) + x.name = name } // Name returns name with which the Filter can be referenced or, for inner @@ -457,57 +561,47 @@ func (x *Filter) SetName(name string) { // // See also [Filter.SetName]. func (x Filter) Name() string { - return x.m.GetName() + return x.name } // Key returns key to the property. func (x Filter) Key() string { - return x.m.GetKey() + return x.key } // Op returns operator to match the property. func (x Filter) Op() FilterOp { - return FilterOp(x.m.GetOp()) + return x.op } // Value returns value to check the property against. func (x Filter) Value() string { - return x.m.GetValue() + return x.val } // SubFilters returns list of sub-filters when Filter is complex. func (x Filter) SubFilters() []Filter { - fsm := x.m.GetFilters() - if len(fsm) == 0 { - return nil - } - - fs := make([]Filter, len(fsm)) - for i := range fsm { - fs[i] = Filter{m: fsm[i]} - } - - return fs + return x.subs } -func (x *Filter) setAttribute(key string, op netmap.Operation, val string) { - x.m.SetKey(key) - x.m.SetOp(op) - x.m.SetValue(val) +func (x *Filter) setAttribute(key string, op FilterOp, val string) { + x.key = key + x.op = op + x.val = val } // Equal applies the rule to accept only nodes with the same attribute value. // // Method SHOULD NOT be called along with other similar methods. func (x *Filter) Equal(key, value string) { - x.setAttribute(key, netmap.EQ, value) + x.setAttribute(key, FilterOpEQ, value) } // NotEqual applies the rule to accept only nodes with the distinct attribute value. // // Method SHOULD NOT be called along with other similar methods. func (x *Filter) NotEqual(key, value string) { - x.setAttribute(key, netmap.NE, value) + x.setAttribute(key, FilterOpNE, value) } // NumericGT applies the rule to accept only nodes with the numeric attribute @@ -515,7 +609,7 @@ func (x *Filter) NotEqual(key, value string) { // // Method SHOULD NOT be called along with other similar methods. func (x *Filter) NumericGT(key string, num int64) { - x.setAttribute(key, netmap.GT, strconv.FormatInt(num, 10)) + x.setAttribute(key, FilterOpGT, strconv.FormatInt(num, 10)) } // NumericGE applies the rule to accept only nodes with the numeric attribute @@ -523,7 +617,7 @@ func (x *Filter) NumericGT(key string, num int64) { // // Method SHOULD NOT be called along with other similar methods. func (x *Filter) NumericGE(key string, num int64) { - x.setAttribute(key, netmap.GE, strconv.FormatInt(num, 10)) + x.setAttribute(key, FilterOpGE, strconv.FormatInt(num, 10)) } // NumericLT applies the rule to accept only nodes with the numeric attribute @@ -531,7 +625,7 @@ func (x *Filter) NumericGE(key string, num int64) { // // Method SHOULD NOT be called along with other similar methods. func (x *Filter) NumericLT(key string, num int64) { - x.setAttribute(key, netmap.LT, strconv.FormatInt(num, 10)) + x.setAttribute(key, FilterOpLT, strconv.FormatInt(num, 10)) } // NumericLE applies the rule to accept only nodes with the numeric attribute @@ -539,22 +633,12 @@ func (x *Filter) NumericLT(key string, num int64) { // // Method SHOULD NOT be called along with other similar methods. func (x *Filter) NumericLE(key string, num int64) { - x.setAttribute(key, netmap.LE, strconv.FormatInt(num, 10)) + x.setAttribute(key, FilterOpLE, strconv.FormatInt(num, 10)) } -func (x *Filter) setInnerFilters(op netmap.Operation, filters []Filter) { +func (x *Filter) setInnerFilters(op FilterOp, filters []Filter) { x.setAttribute("", op, "") - - inner := x.m.GetFilters() - if rem := len(filters) - len(inner); rem > 0 { - inner = append(inner, make([]netmap.Filter, rem)...) - } - - for i := range filters { - inner[i] = filters[i].m - } - - x.m.SetFilters(inner) + x.subs = filters } // LogicalOR applies the rule to accept only nodes which satisfy at least one @@ -562,7 +646,7 @@ func (x *Filter) setInnerFilters(op netmap.Operation, filters []Filter) { // // Method SHOULD NOT be called along with other similar methods. func (x *Filter) LogicalOR(filters ...Filter) { - x.setInnerFilters(netmap.OR, filters) + x.setInnerFilters(FilterOpOR, filters) } // LogicalAND applies the rule to accept only nodes which satisfy all the given @@ -570,7 +654,7 @@ func (x *Filter) LogicalOR(filters ...Filter) { // // Method SHOULD NOT be called along with other similar methods. func (x *Filter) LogicalAND(filters ...Filter) { - x.setInnerFilters(netmap.AND, filters) + x.setInnerFilters(FilterOpAND, filters) } // Filters returns list of Filter that will be applied when selecting nodes. @@ -579,11 +663,7 @@ func (x *Filter) LogicalAND(filters ...Filter) { // // See also [PlacementPolicy.SetFilters]. func (p PlacementPolicy) Filters() []Filter { - fs := make([]Filter, len(p.filters)) - for i := range p.filters { - fs[i] = Filter{m: p.filters[i]} - } - return fs + return p.filters } // SetFilters sets list of Filter that will be applied when selecting nodes. @@ -592,11 +672,7 @@ func (p PlacementPolicy) Filters() []Filter { // // See also [PlacementPolicy.Filters]. func (p *PlacementPolicy) SetFilters(fs []Filter) { - p.filters = make([]netmap.Filter, len(fs)) - - for i := range fs { - p.filters[i] = fs[i].m - } + p.filters = fs } // WriteStringTo encodes PlacementPolicy into human-readably query and writes @@ -623,8 +699,8 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) { return err } - c := p.replicas[i].GetCount() - s := p.replicas[i].GetSelector() + c := p.replicas[i].NumberOfObjects() + s := p.replicas[i].SelectorName() if s != "" { _, err = w.WriteString(fmt.Sprintf("REP %d IN %s", c, s)) @@ -657,18 +733,18 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) { return err } - _, err = w.WriteString(fmt.Sprintf("SELECT %d", p.selectors[i].GetCount())) + _, err = w.WriteString(fmt.Sprintf("SELECT %d", p.selectors[i].NumberOfNodes())) if err != nil { return err } - if s = p.selectors[i].GetAttribute(); s != "" { + if s = p.selectors[i].BucketAttribute(); s != "" { var clause string - switch p.selectors[i].GetClause() { - case netmap.Same: + switch p.selectors[i].clause { + case protonetmap.Clause_SAME: clause = "SAME " - case netmap.Distinct: + case protonetmap.Clause_DISTINCT: clause = "DISTINCT " default: clause = "" @@ -680,14 +756,14 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) { } } - if s = p.selectors[i].GetFilter(); s != "" { + if s = p.selectors[i].FilterName(); s != "" { _, err = w.WriteString(" FROM " + s) if err != nil { return err } } - if s = p.selectors[i].GetName(); s != "" { + if s = p.selectors[i].Name(); s != "" { _, err = w.WriteString(" AS " + s) if err != nil { return err @@ -715,25 +791,25 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) { return nil } -func writeFilterStringTo(w io.StringWriter, f netmap.Filter) error { +func writeFilterStringTo(w io.StringWriter, f Filter) error { var err error var s string - op := f.GetOp() + op := f.Op() unspecified := op == 0 - if s = f.GetKey(); s != "" { - _, err = w.WriteString(fmt.Sprintf("%s %s %s", s, op, f.GetValue())) + if s = f.Key(); s != "" { + _, err = w.WriteString(fmt.Sprintf("%s %s %s", s, op, f.Value())) if err != nil { return err } - } else if s = f.GetName(); unspecified && s != "" { + } else if s = f.Name(); unspecified && s != "" { _, err = w.WriteString(fmt.Sprintf("@%s", s)) if err != nil { return err } } - inner := f.GetFilters() + inner := f.SubFilters() for i := range inner { if i != 0 { _, err = w.WriteString(" " + op.String() + " ") @@ -748,7 +824,7 @@ func writeFilterStringTo(w io.StringWriter, f netmap.Filter) error { } } - if s = f.GetName(); s != "" && !unspecified { + if s = f.Name(); s != "" && !unspecified { _, err = w.WriteString(" AS " + s) if err != nil { return err @@ -828,15 +904,14 @@ func (p *policyVisitor) VisitPolicy(ctx *parser.PolicyContext) any { pl := new(PlacementPolicy) repStmts := ctx.AllRepStmt() - pl.replicas = make([]netmap.Replica, 0, len(repStmts)) + pl.replicas = make([]ReplicaDescriptor, len(repStmts)) - for _, r := range repStmts { - res, ok := r.Accept(p).(*netmap.Replica) + for i, r := range repStmts { + res, ok := r.Accept(p).(*protonetmap.Replica) if !ok { return nil } - - pl.replicas = append(pl.replicas, *res) + pl.replicas[i].fromProtoMessage(res) } if cbfStmt := ctx.CbfStmt(); cbfStmt != nil { @@ -848,22 +923,29 @@ func (p *policyVisitor) VisitPolicy(ctx *parser.PolicyContext) any { } selStmts := ctx.AllSelectStmt() - pl.selectors = make([]netmap.Selector, 0, len(selStmts)) + pl.selectors = make([]Selector, len(selStmts)) - for _, s := range selStmts { - res, ok := s.Accept(p).(*netmap.Selector) + for i, s := range selStmts { + res, ok := s.Accept(p).(*protonetmap.Selector) if !ok { return nil } - - pl.selectors = append(pl.selectors, *res) + if err := pl.selectors[i].fromProtoMessage(res); err != nil { + return fmt.Errorf("invalid selector #%d: %w", i, err) + } } filtStmts := ctx.AllFilterStmt() - pl.filters = make([]netmap.Filter, 0, len(filtStmts)) + pl.filters = make([]Filter, len(filtStmts)) - for _, f := range filtStmts { - pl.filters = append(pl.filters, *f.Accept(p).(*netmap.Filter)) + for i, f := range filtStmts { + res, ok := f.Accept(p).(*protonetmap.Filter) + if !ok { + return nil + } + if err := pl.filters[i].fromProtoMessage(res); err != nil { + return fmt.Errorf("invalid filter #%d: %w", i, err) + } } return pl @@ -885,11 +967,11 @@ func (p *policyVisitor) VisitRepStmt(ctx *parser.RepStmtContext) any { return p.reportError(errInvalidNumber) } - rs := new(netmap.Replica) - rs.SetCount(uint32(num)) + rs := new(protonetmap.Replica) + rs.Count = uint32(num) if sel := ctx.GetSelector(); sel != nil { - rs.SetSelector(sel.GetText()) + rs.Selector = sel.GetText() } return rs @@ -902,29 +984,29 @@ func (p *policyVisitor) VisitSelectStmt(ctx *parser.SelectStmtContext) any { return p.reportError(errInvalidNumber) } - s := new(netmap.Selector) - s.SetCount(uint32(res)) + s := new(protonetmap.Selector) + s.Count = uint32(res) if clStmt := ctx.Clause(); clStmt != nil { - s.SetClause(clauseFromString(clStmt.GetText())) + s.Clause = clauseFromString(clStmt.GetText()) } if bStmt := ctx.GetBucket(); bStmt != nil { - s.SetAttribute(ctx.GetBucket().GetText()) + s.Attribute = ctx.GetBucket().GetText() } - s.SetFilter(ctx.GetFilter().GetText()) // either ident or wildcard + s.Filter = ctx.GetFilter().GetText() // either ident or wildcard if ctx.AS() != nil { - s.SetName(ctx.GetName().GetText()) + s.Name = ctx.GetName().GetText() } return s } // VisitFilterStmt implements parser.QueryVisitor interface. func (p *policyVisitor) VisitFilterStmt(ctx *parser.FilterStmtContext) any { - f := p.VisitFilterExpr(ctx.GetExpr().(*parser.FilterExprContext)).(*netmap.Filter) - f.SetName(ctx.GetName().GetText()) + f := p.VisitFilterExpr(ctx.GetExpr().(*parser.FilterExprContext)).(*protonetmap.Filter) + f.Name = ctx.GetName().GetText() return f } @@ -937,21 +1019,21 @@ func (p *policyVisitor) VisitFilterExpr(ctx *parser.FilterExprContext) any { return inner.Accept(p) } - f := new(netmap.Filter) + f := new(protonetmap.Filter) op := operationFromString(ctx.GetOp().GetText()) - f.SetOp(op) + f.Op = op - f1 := *ctx.GetF1().Accept(p).(*netmap.Filter) - f2 := *ctx.GetF2().Accept(p).(*netmap.Filter) + f1 := ctx.GetF1().Accept(p).(*protonetmap.Filter) + f2 := ctx.GetF2().Accept(p).(*protonetmap.Filter) // Consider f1=(.. AND ..) AND f2. This can be merged because our AND operation // is of arbitrary arity. ANTLR generates left-associative parse-tree by default. if f1.GetOp() == op { - f.SetFilters(append(f1.GetFilters(), f2)) + f.Filters = append(f1.GetFilters(), f2) return f } - f.SetFilters([]netmap.Filter{f1, f2}) + f.Filters = []*protonetmap.Filter{f1, f2} return f } @@ -981,9 +1063,9 @@ func (p *policyVisitor) VisitFilterValue(ctx *parser.FilterValueContext) any { // VisitExpr implements parser.QueryVisitor interface. func (p *policyVisitor) VisitExpr(ctx *parser.ExprContext) any { - f := new(netmap.Filter) + f := new(protonetmap.Filter) if flt := ctx.GetFilter(); flt != nil { - f.SetName(flt.GetText()) + f.Name = flt.GetText() return f } @@ -991,9 +1073,9 @@ func (p *policyVisitor) VisitExpr(ctx *parser.ExprContext) any { opStr := ctx.SIMPLE_OP().GetText() value := ctx.GetValue().Accept(p) - f.SetKey(key.(string)) - f.SetOp(operationFromString(opStr)) - f.SetValue(value.(string)) + f.Key = key.(string) + f.Op = operationFromString(opStr) + f.Value = value.(string) return f } @@ -1004,21 +1086,21 @@ func validatePolicy(p PlacementPolicy) error { seenFilters := map[string]bool{} for i := range p.filters { - seenFilters[p.filters[i].GetName()] = true + seenFilters[p.filters[i].Name()] = true } seenSelectors := map[string]bool{} for i := range p.selectors { - if flt := p.selectors[i].GetFilter(); flt != mainFilterName && !seenFilters[flt] { + if flt := p.selectors[i].FilterName(); flt != mainFilterName && !seenFilters[flt] { return fmt.Errorf("%w: '%s'", errUnknownFilter, flt) } - seenSelectors[p.selectors[i].GetName()] = true + seenSelectors[p.selectors[i].Name()] = true } for i := range p.replicas { - if sel := p.replicas[i].GetSelector(); sel != "" && !seenSelectors[sel] { + if sel := p.replicas[i].SelectorName(); sel != "" && !seenSelectors[sel] { return fmt.Errorf("%w: '%s'", errUnknownSelector, sel) } } @@ -1026,20 +1108,42 @@ func validatePolicy(p PlacementPolicy) error { return nil } -func clauseFromString(s string) (c netmap.Clause) { - if !c.FromString(strings.ToUpper(s)) { +func clauseFromString(s string) protonetmap.Clause { + switch s { + default: // Such errors should be handled by ANTLR code thus this panic. - panic(fmt.Errorf("BUG: invalid clause: %s", c)) + panic(fmt.Errorf("BUG: invalid clause: %s", s)) + case "CLAUSE_UNSPECIFIED": + return protonetmap.Clause_CLAUSE_UNSPECIFIED + case "SAME": + return protonetmap.Clause_SAME + case "DISTINCT": + return protonetmap.Clause_DISTINCT } - - return } -func operationFromString(s string) (op netmap.Operation) { - if !op.FromString(strings.ToUpper(s)) { +func operationFromString(s string) protonetmap.Operation { + switch s { + default: // Such errors should be handled by ANTLR code thus this panic. - panic(fmt.Errorf("BUG: invalid operation: %s", op)) + panic(fmt.Errorf("BUG: invalid operation: %s", s)) + case "OPERATION_UNSPECIFIED": + return protonetmap.Operation_OPERATION_UNSPECIFIED + case "EQ": + return protonetmap.Operation_EQ + case "NE": + return protonetmap.Operation_NE + case "GT": + return protonetmap.Operation_GT + case "GE": + return protonetmap.Operation_GE + case "LT": + return protonetmap.Operation_LT + case "LE": + return protonetmap.Operation_LE + case "OR": + return protonetmap.Operation_OR + case "AND": + return protonetmap.Operation_AND } - - return } diff --git a/netmap/policy_internal_test.go b/netmap/policy_internal_test.go index 9c48fad9..97aa622a 100644 --- a/netmap/policy_internal_test.go +++ b/netmap/policy_internal_test.go @@ -4,7 +4,6 @@ import ( "bytes" "testing" - "github.com/nspcc-dev/neofs-api-go/v2/netmap" "github.com/stretchr/testify/require" ) @@ -37,15 +36,15 @@ func TestPlacementPolicy_CopyTo(t *testing.T) { var dst PlacementPolicy pp.CopyTo(&dst) - var f2 netmap.Filter + var f2 Filter f2.SetName("filter2") - require.Equal(t, pp.filters[0].GetName(), dst.filters[0].GetName()) + require.Equal(t, pp.filters[0].Name(), dst.filters[0].Name()) dst.filters[0].SetName("f2") - require.NotEqual(t, pp.filters[0].GetName(), dst.filters[0].GetName()) + require.NotEqual(t, pp.filters[0].Name(), dst.filters[0].Name()) dst.filters[0] = f2 - require.NotEqual(t, pp.filters[0].GetName(), dst.filters[0].GetName()) + require.NotEqual(t, pp.filters[0].Name(), dst.filters[0].Name()) }) t.Run("internal filters", func(t *testing.T) { @@ -54,7 +53,7 @@ func TestPlacementPolicy_CopyTo(t *testing.T) { var topFilter Filter topFilter.SetName("topFilter") - topFilter.setInnerFilters(netmap.EQ, []Filter{includedFilter}) + topFilter.setInnerFilters(FilterOpEQ, []Filter{includedFilter}) var policy PlacementPolicy policy.SetFilters([]Filter{topFilter}) @@ -64,13 +63,13 @@ func TestPlacementPolicy_CopyTo(t *testing.T) { require.True(t, bytes.Equal(policy.Marshal(), dst.Marshal())) t.Run("change extra filter", func(t *testing.T) { - require.Equal(t, topFilter.m.GetName(), dst.filters[0].GetName()) - require.Equal(t, topFilter.m.GetFilters()[0].GetName(), dst.filters[0].GetFilters()[0].GetName()) + require.Equal(t, topFilter.Name(), dst.filters[0].Name()) + require.Equal(t, topFilter.SubFilters()[0].Name(), dst.filters[0].SubFilters()[0].Name()) - dst.filters[0].GetFilters()[0].SetName("someInternalFilterName") + dst.filters[0].SubFilters()[0].SetName("someInternalFilterName") - require.Equal(t, topFilter.m.GetName(), dst.filters[0].GetName()) - require.NotEqual(t, topFilter.m.GetFilters()[0].GetName(), dst.filters[0].GetFilters()[0].GetName()) + require.Equal(t, topFilter.Name(), dst.filters[0].Name()) + require.NotEqual(t, topFilter.SubFilters()[0].Name(), dst.filters[0].SubFilters()[0].Name()) }) }) @@ -88,23 +87,23 @@ func TestPlacementPolicy_CopyTo(t *testing.T) { var dst PlacementPolicy pp.CopyTo(&dst) - require.Equal(t, pp.selectors[0].GetName(), dst.selectors[0].GetName()) + require.Equal(t, pp.selectors[0].Name(), dst.selectors[0].Name()) dst.selectors[0].SetName("s2") - require.NotEqual(t, pp.selectors[0].GetName(), dst.selectors[0].GetName()) + require.NotEqual(t, pp.selectors[0].Name(), dst.selectors[0].Name()) - var s2 netmap.Selector + var s2 Selector s2.SetName("selector2") dst.selectors[0] = s2 - require.NotEqual(t, pp.selectors[0].GetName(), dst.selectors[0].GetName()) + require.NotEqual(t, pp.selectors[0].Name(), dst.selectors[0].Name()) }) t.Run("change replica", func(t *testing.T) { var dst PlacementPolicy pp.CopyTo(&dst) - require.Equal(t, pp.replicas[0].GetSelector(), dst.replicas[0].GetSelector()) - dst.replicas[0].SetSelector("s2") - require.NotEqual(t, pp.replicas[0].GetSelector(), dst.replicas[0].GetSelector()) + require.Equal(t, pp.replicas[0].SelectorName(), dst.replicas[0].SelectorName()) + dst.replicas[0].SetSelectorName("s2") + require.NotEqual(t, pp.replicas[0].SelectorName(), dst.replicas[0].SelectorName()) }) } diff --git a/netmap/policy_test.go b/netmap/policy_test.go index 8b67306d..60a34f48 100644 --- a/netmap/policy_test.go +++ b/netmap/policy_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" - apinetmap "github.com/nspcc-dev/neofs-api-go/v2/netmap" "github.com/nspcc-dev/neofs-sdk-go/netmap" + protonetmap "github.com/nspcc-dev/neofs-sdk-go/proto/netmap" "github.com/stretchr/testify/require" ) @@ -254,54 +254,33 @@ func TestPlacementPolicy_SetFilters(t *testing.T) { require.Equal(t, anyValidFilters, p.Filters()) } -func TestPlacementPolicy_ReadFromV2(t *testing.T) { - var m apinetmap.PlacementPolicy - m.SetContainerBackupFactor(anyValidBackupFactor) - mrs := make([]apinetmap.Replica, 2) - mrs[0].SetSelector("selector_0") - mrs[0].SetCount(2583748530) - mrs[1].SetSelector("selector_1") - mrs[1].SetCount(358755354) - m.SetReplicas(mrs) - mss := make([]apinetmap.Selector, 2) - mss[0].SetName("selector_0") - mss[0].SetCount(1814781076) - mss[0].SetClause(apinetmap.Same) - mss[0].SetFilter("filter_0") - mss[0].SetAttribute("attribute_0") - mss[1].SetName("selector_1") - mss[1].SetCount(1814781076) - mss[1].SetClause(apinetmap.Distinct) - mss[1].SetFilter("filter_1") - mss[1].SetAttribute("attribute_1") - m.SetSelectors(mss) - msubs := make([]apinetmap.Filter, 0, 2) - addSub := func(name, key string, op apinetmap.Operation, val string) { - var f apinetmap.Filter - f.SetName(name) - f.SetKey(key) - f.SetOp(op) - f.SetValue(val) - msubs = append(msubs, f) +func TestPlacementPolicy_FromProtoMessage(t *testing.T) { + m := &protonetmap.PlacementPolicy{ + Replicas: []*protonetmap.Replica{ + {Count: 2583748530, Selector: "selector_0"}, + {Count: 358755354, Selector: "selector_1"}, + }, + ContainerBackupFactor: anyValidBackupFactor, + Selectors: []*protonetmap.Selector{ + {Name: "selector_0", Count: 1814781076, Clause: protonetmap.Clause_SAME, Attribute: "attribute_0", Filter: "filter_0"}, + {Name: "selector_1", Count: 1814781076, Clause: protonetmap.Clause_DISTINCT, Attribute: "attribute_1", Filter: "filter_1"}, + }, + Filters: []*protonetmap.Filter{ + {Name: "filter_0", Op: protonetmap.Operation_AND, Filters: []*protonetmap.Filter{ + {Name: "filter_0_0", Key: "key_0_0", Op: protonetmap.Operation_EQ, Value: "val_0_0"}, + {Name: "filter_0_1", Key: "key_0_1", Op: protonetmap.Operation_NE, Value: "val_0_1"}, + }}, + {Name: "filter_1", Key: "", Op: protonetmap.Operation_OR, Value: "", Filters: []*protonetmap.Filter{ + {Name: "filter_1_0", Key: "key_1_0", Op: 0, Value: "1889407708985023116"}, + {Name: "filter_1_1", Key: "key_1_1", Op: 0, Value: "1429243097315344888"}, + {Name: "filter_1_2", Key: "key_1_2", Op: 0, Value: "3722656060317482335"}, + {Name: "filter_1_3", Key: "key_1_3", Op: 0, Value: "1950504987705284805"}, + }}, + }, } - addSub("filter_0_0", "key_0_0", apinetmap.EQ, "val_0_0") - addSub("filter_0_1", "key_0_1", apinetmap.NE, "val_0_1") - mfs := make([]apinetmap.Filter, 2) - mfs[0].SetName("filter_0") - mfs[0].SetOp(apinetmap.AND) - mfs[0].SetFilters(msubs) - msubs = make([]apinetmap.Filter, 0, 4) - addSub("filter_1_0", "key_1_0", apinetmap.GT, "1889407708985023116") - addSub("filter_1_1", "key_1_1", apinetmap.GE, "1429243097315344888") - addSub("filter_1_2", "key_1_2", apinetmap.LT, "3722656060317482335") - addSub("filter_1_3", "key_1_3", apinetmap.LE, "1950504987705284805") - mfs[1].SetName("filter_1") - mfs[1].SetOp(apinetmap.OR) - mfs[1].SetFilters(msubs) - m.SetFilters(mfs) var val netmap.PlacementPolicy - require.NoError(t, val.ReadFromV2(m)) + require.NoError(t, val.FromProtoMessage(m)) require.EqualValues(t, anyValidBackupFactor, val.ContainerBackupFactor()) rs := val.Replicas() require.Len(t, rs, 2) @@ -365,48 +344,50 @@ func TestPlacementPolicy_ReadFromV2(t *testing.T) { require.Empty(t, subs[3].SubFilters()) // reset optional fields - m.SetSelectors(nil) - m.SetFilters(nil) + m.Selectors = nil + m.Filters = nil val2 := val - require.NoError(t, val2.ReadFromV2(m)) + require.NoError(t, val2.FromProtoMessage(m)) require.Empty(t, val2.Selectors()) require.Empty(t, val2.Filters()) t.Run("invalid", func(t *testing.T) { for _, tc := range []struct { name, err string - corrupt func(*apinetmap.PlacementPolicy) + corrupt func(*protonetmap.PlacementPolicy) }{ {name: "replicas/nil", err: "missing replicas", - corrupt: func(m *apinetmap.PlacementPolicy) { m.SetReplicas(nil) }}, + corrupt: func(m *protonetmap.PlacementPolicy) { m.Replicas = nil }}, {name: "replicas/empty", err: "missing replicas", - corrupt: func(m *apinetmap.PlacementPolicy) { m.SetReplicas([]apinetmap.Replica{}) }}, + corrupt: func(m *protonetmap.PlacementPolicy) { m.Replicas = []*protonetmap.Replica{} }}, + {name: "selectors/negative clause", err: "invalid selector #1: negative clause -1", + corrupt: func(m *protonetmap.PlacementPolicy) { m.Selectors[1].Clause = -1 }}, + {name: "filters/negative op", err: "invalid filter #1: negative op -1", + corrupt: func(m *protonetmap.PlacementPolicy) { m.Filters[1].Op = -1 }}, } { t.Run(tc.name, func(t *testing.T) { st := val - var m apinetmap.PlacementPolicy - st.WriteToV2(&m) - tc.corrupt(&m) - require.EqualError(t, new(netmap.PlacementPolicy).ReadFromV2(m), tc.err) + m := st.ProtoMessage() + tc.corrupt(m) + require.EqualError(t, new(netmap.PlacementPolicy).FromProtoMessage(m), tc.err) }) } }) } -func TestPlacementPolicy_WriteToV2(t *testing.T) { +func TestPlacementPolicy_ProtoMessage(t *testing.T) { var val netmap.PlacementPolicy - var m apinetmap.PlacementPolicy // zero - val.WriteToV2(&m) + m := val.ProtoMessage() require.Zero(t, m.GetContainerBackupFactor()) require.Zero(t, m.GetReplicas()) require.Zero(t, m.GetSelectors()) require.Zero(t, m.GetFilters()) - require.Zero(t, m.GetSubnetID()) + require.Zero(t, m.GetSubnetId()) // filled - validPlacementPolicy.WriteToV2(&m) + m = validPlacementPolicy.ProtoMessage() require.EqualValues(t, anyValidBackupFactor, m.GetContainerBackupFactor()) mrs := m.GetReplicas() @@ -420,12 +401,12 @@ func TestPlacementPolicy_WriteToV2(t *testing.T) { require.Len(t, mss, 2) require.Equal(t, "selector_0", mss[0].GetName()) require.EqualValues(t, 1814781076, mss[0].GetCount()) - require.Equal(t, apinetmap.Same, mss[0].GetClause()) + require.Equal(t, protonetmap.Clause_SAME, mss[0].GetClause()) require.Equal(t, "filter_0", mss[0].GetFilter()) require.Equal(t, "attribute_0", mss[0].GetAttribute()) require.Equal(t, "selector_1", mss[1].GetName()) require.EqualValues(t, 1505136737, mss[1].GetCount()) - require.Equal(t, apinetmap.Distinct, mss[1].GetClause()) + require.Equal(t, protonetmap.Clause_DISTINCT, mss[1].GetClause()) require.Equal(t, "filter_1", mss[1].GetFilter()) require.Equal(t, "attribute_1", mss[1].GetAttribute()) @@ -434,51 +415,51 @@ func TestPlacementPolicy_WriteToV2(t *testing.T) { // filter#0 require.Equal(t, "filter_0", mfs[0].GetName()) require.Zero(t, mfs[0].GetKey()) - require.Equal(t, apinetmap.AND, mfs[0].GetOp()) + require.Equal(t, protonetmap.Operation_AND, mfs[0].GetOp()) require.Zero(t, mfs[0].GetValue()) msubs := mfs[0].GetFilters() require.Len(t, msubs, 2) // sub#0 require.Equal(t, "filter_0_0", msubs[0].GetName()) require.Equal(t, "key_0_0", msubs[0].GetKey()) - require.Equal(t, apinetmap.EQ, msubs[0].GetOp()) + require.Equal(t, protonetmap.Operation_EQ, msubs[0].GetOp()) require.Equal(t, "val_0_0", msubs[0].GetValue()) require.Zero(t, msubs[0].GetFilters()) // sub#1 require.Equal(t, "filter_0_1", msubs[1].GetName()) require.Equal(t, "key_0_1", msubs[1].GetKey()) - require.Equal(t, apinetmap.NE, msubs[1].GetOp()) + require.Equal(t, protonetmap.Operation_NE, msubs[1].GetOp()) require.Equal(t, "val_0_1", msubs[1].GetValue()) require.Zero(t, msubs[1].GetFilters()) // filter#1 require.Equal(t, "filter_1", mfs[1].GetName()) require.Zero(t, mfs[1].GetKey()) - require.Equal(t, apinetmap.OR, mfs[1].GetOp()) + require.Equal(t, protonetmap.Operation_OR, mfs[1].GetOp()) require.Zero(t, mfs[1].GetValue()) msubs = mfs[1].GetFilters() require.Len(t, msubs, 4) // sub#0 require.Equal(t, "filter_1_0", msubs[0].GetName()) require.Equal(t, "key_1_0", msubs[0].GetKey()) - require.Equal(t, apinetmap.GT, msubs[0].GetOp()) + require.Equal(t, protonetmap.Operation_GT, msubs[0].GetOp()) require.Equal(t, "1889407708985023116", msubs[0].GetValue()) require.Zero(t, msubs[0].GetFilters()) // sub#1 require.Equal(t, "filter_1_1", msubs[1].GetName()) require.Equal(t, "key_1_1", msubs[1].GetKey()) - require.Equal(t, apinetmap.GE, msubs[1].GetOp()) + require.Equal(t, protonetmap.Operation_GE, msubs[1].GetOp()) require.Equal(t, "1429243097315344888", msubs[1].GetValue()) require.Zero(t, msubs[1].GetFilters()) // sub#2 require.Equal(t, "filter_1_2", msubs[2].GetName()) require.Equal(t, "key_1_2", msubs[2].GetKey()) - require.Equal(t, apinetmap.LT, msubs[2].GetOp()) + require.Equal(t, protonetmap.Operation_LT, msubs[2].GetOp()) require.Equal(t, "3722656060317482335", msubs[2].GetValue()) require.Zero(t, msubs[2].GetFilters()) // sub#3 require.Equal(t, "filter_1_3", msubs[3].GetName()) require.Equal(t, "key_1_3", msubs[3].GetKey()) - require.Equal(t, apinetmap.LE, msubs[3].GetOp()) + require.Equal(t, protonetmap.Operation_LE, msubs[3].GetOp()) require.Equal(t, "1950504987705284805", msubs[3].GetValue()) require.Zero(t, msubs[3].GetFilters()) } diff --git a/netmap/selector.go b/netmap/selector.go index 24bd90d9..13bda6c8 100644 --- a/netmap/selector.go +++ b/netmap/selector.go @@ -5,21 +5,20 @@ import ( "sort" "github.com/nspcc-dev/hrw/v2" - "github.com/nspcc-dev/neofs-api-go/v2/netmap" ) // processSelectors processes selectors and returns error is any of them is invalid. func (c *context) processSelectors(p PlacementPolicy) error { for i := range p.selectors { - fName := p.selectors[i].GetFilter() + fName := p.selectors[i].FilterName() if fName != mainFilterName { - _, ok := c.processedFilters[p.selectors[i].GetFilter()] + _, ok := c.processedFilters[p.selectors[i].FilterName()] if !ok { return fmt.Errorf("%w: SELECT FROM '%s'", errFilterNotFound, fName) } } - sName := p.selectors[i].GetName() + sName := p.selectors[i].Name() c.processedSelectors[sName] = &p.selectors[i] @@ -36,13 +35,12 @@ func (c *context) processSelectors(p PlacementPolicy) error { // calcNodesCount returns number of buckets and minimum number of nodes in every bucket // for the given selector. -func calcNodesCount(s netmap.Selector) (int, int) { - switch s.GetClause() { - case netmap.Same: - return 1, int(s.GetCount()) - default: - return int(s.GetCount()), 1 +func calcNodesCount(s Selector) (int, int) { + n := int(s.NumberOfNodes()) + if s.IsSame() { + return 1, n } + return n, 1 } // calcBucketWeight computes weight for a node bucket. @@ -56,12 +54,12 @@ func calcBucketWeight(ns nodes, a aggregator, wf weightFunc) float64 { // getSelection returns nodes grouped by s.attribute. // Last argument specifies if more buckets can be used to fulfill CBF. -func (c *context) getSelection(_ PlacementPolicy, s netmap.Selector) ([]nodes, error) { +func (c *context) getSelection(_ PlacementPolicy, s Selector) ([]nodes, error) { bucketCount, nodesInBucket := calcNodesCount(s) buckets := c.getSelectionBase(s) if len(buckets) < bucketCount { - return nil, fmt.Errorf("%w: '%s'", ErrNotEnoughNodes, s.GetName()) + return nil, fmt.Errorf("%w: '%s'", ErrNotEnoughNodes, s.Name()) } // We need deterministic output in case there is no pivot. @@ -69,7 +67,7 @@ func (c *context) getSelection(_ PlacementPolicy, s netmap.Selector) ([]nodes, e // However, because initial order influences HRW order for buckets with equal weights, // we also need to have deterministic input to HRW sorting routine. if len(c.hrwSeed) == 0 { - if s.GetAttribute() == "" { + if s.BucketAttribute() == "" { sort.Slice(buckets, func(i, j int) bool { return less(buckets[i].nodes[0], buckets[j].nodes[0]) }) @@ -97,7 +95,7 @@ func (c *context) getSelection(_ PlacementPolicy, s netmap.Selector) ([]nodes, e // Fallback to using minimum allowed backup factor (1). res = append(res, fallback...) if len(res) < bucketCount { - return nil, fmt.Errorf("%w: '%s'", ErrNotEnoughNodes, s.GetName()) + return nil, fmt.Errorf("%w: '%s'", ErrNotEnoughNodes, s.Name()) } } @@ -110,7 +108,7 @@ func (c *context) getSelection(_ PlacementPolicy, s netmap.Selector) ([]nodes, e hrw.SortWeighted(res, weights, c.hrwSeedHash) } - if s.GetAttribute() == "" { + if s.BucketAttribute() == "" { res, fallback = res[:bucketCount], res[bucketCount:] for i := range fallback { index := i % bucketCount @@ -131,13 +129,13 @@ type nodeAttrPair struct { // getSelectionBase returns nodes grouped by selector attribute. // It it guaranteed that each pair will contain at least one node. -func (c *context) getSelectionBase(s netmap.Selector) []nodeAttrPair { - fName := s.GetFilter() +func (c *context) getSelectionBase(s Selector) []nodeAttrPair { + fName := s.FilterName() f := c.processedFilters[fName] isMain := fName == mainFilterName result := []nodeAttrPair{} nodeMap := map[string][]NodeInfo{} - attr := s.GetAttribute() + attr := s.BucketAttribute() for i := range c.netMap.nodes { if isMain || c.match(f, c.netMap.nodes[i]) { diff --git a/netmap/selector_test.go b/netmap/selector_test.go index 4ab9ac40..f040be96 100644 --- a/netmap/selector_test.go +++ b/netmap/selector_test.go @@ -9,6 +9,7 @@ import ( "github.com/nspcc-dev/hrw/v2" "github.com/nspcc-dev/neofs-api-go/v2/netmap" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" + protonetmap "github.com/nspcc-dev/neofs-sdk-go/proto/netmap" "github.com/stretchr/testify/require" ) @@ -73,8 +74,8 @@ func BenchmarkPolicyHRWType(b *testing.B) { newSelector("loc1", "Location", 1, "loc1", (*Selector).SelectSame), newSelector("loc2", "Location", 1, "loc2", (*Selector).SelectSame)}, []Filter{ - newFilter("loc1", "Location", "Shanghai", netmap.EQ), - newFilter("loc2", "Location", "Shanghai", netmap.NE), + newFilter("loc1", "Location", "Shanghai", FilterOpEQ), + newFilter("loc2", "Location", "Shanghai", FilterOpNE), }) nodes := make([]NodeInfo, netmapSize) @@ -118,8 +119,8 @@ func TestPlacementPolicy_DeterministicOrder(t *testing.T) { newSelector("loc1", "Location", 1, "loc1", (*Selector).SelectSame), newSelector("loc2", "Location", 1, "loc2", (*Selector).SelectSame)}, []Filter{ - newFilter("loc1", "Location", "Shanghai", netmap.EQ), - newFilter("loc2", "Location", "Shanghai", netmap.NE), + newFilter("loc1", "Location", "Shanghai", FilterOpEQ), + newFilter("loc2", "Location", "Shanghai", FilterOpNE), }) nodeList := make([]NodeInfo, netmapSize) @@ -174,8 +175,8 @@ func TestPlacementPolicy_ProcessSelectors(t *testing.T) { newSelector("Main", "Country", 3, "*", (*Selector).SelectDistinct), }, []Filter{ - newFilter("FromRU", "Country", "Russia", netmap.EQ), - newFilter("Good", "Rating", "4", netmap.GE), + newFilter("FromRU", "Country", "Russia", FilterOpEQ), + newFilter("Good", "Rating", "4", FilterOpGE), }) nodes := []NodeInfo{ nodeInfoFromAttributes("Country", "Russia", "Rating", "1", "City", "SPB"), @@ -199,13 +200,13 @@ func TestPlacementPolicy_ProcessSelectors(t *testing.T) { require.NoError(t, c.processSelectors(p)) for _, s := range p.selectors { - sel := c.selections[s.GetName()] - s := c.processedSelectors[s.GetName()] + sel := c.selections[s.Name()] + s := c.processedSelectors[s.Name()] bucketCount, nodesInBucket := calcNodesCount(*s) nodesInBucket *= int(c.cbf) - targ := fmt.Sprintf("selector '%s'", s.GetName()) + targ := fmt.Sprintf("selector '%s'", s.Name()) require.Equal(t, bucketCount, len(sel), targ) - fName := s.GetFilter() + fName := s.FilterName() for _, res := range sel { require.Equal(t, nodesInBucket, len(res), targ) for j := range res { @@ -219,11 +220,9 @@ func TestSelector_SetName(t *testing.T) { const name = "some name" var s Selector - require.Zero(t, s.m.GetName()) require.Zero(t, s.Name()) s.SetName(name) - require.Equal(t, name, s.m.GetName()) require.Equal(t, name, s.Name()) } @@ -231,29 +230,27 @@ func TestSelector_SetNumberOfNodes(t *testing.T) { const num = 3 var s Selector - require.Zero(t, s.m.GetCount()) require.Zero(t, s.NumberOfNodes()) s.SetNumberOfNodes(num) - require.EqualValues(t, num, s.m.GetCount()) require.EqualValues(t, num, s.NumberOfNodes()) } func TestSelectorClauses(t *testing.T) { var s Selector - require.Equal(t, netmap.UnspecifiedClause, s.m.GetClause()) + require.Equal(t, protonetmap.Clause_CLAUSE_UNSPECIFIED, s.clause) require.False(t, s.IsSame()) require.False(t, s.IsDistinct()) s.SelectDistinct() - require.Equal(t, netmap.Distinct, s.m.GetClause()) + require.Equal(t, netmap.Distinct, s.clause) require.False(t, s.IsSame()) require.True(t, s.IsDistinct()) s.SelectSame() - require.Equal(t, netmap.Same, s.m.GetClause()) + require.Equal(t, netmap.Same, s.clause) require.True(t, s.IsSame()) require.False(t, s.IsDistinct()) } @@ -262,18 +259,18 @@ func TestSelector_SelectByBucketAttribute(t *testing.T) { const attr = "some attribute" var s Selector - require.Zero(t, s.m.GetAttribute()) + require.Zero(t, s.BucketAttribute()) s.SelectByBucketAttribute(attr) - require.Equal(t, attr, s.m.GetAttribute()) + require.Equal(t, attr, s.BucketAttribute()) } func TestSelector_SetFilterName(t *testing.T) { const fName = "some filter" var s Selector - require.Zero(t, s.m.GetFilter()) + require.Zero(t, s.FilterName()) s.SetFilterName(fName) - require.Equal(t, fName, s.m.GetFilter()) + require.Equal(t, fName, s.FilterName()) }