git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/netmap/policy.go (about)

     1  package netmap
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
    11  	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap/parser"
    12  	"github.com/antlr4-go/antlr/v4"
    13  )
    14  
    15  // PlacementPolicy declares policy to store objects in the FrostFS container.
    16  // Within itself, PlacementPolicy represents a set of rules to select a subset
    17  // of nodes from FrostFS network map - node-candidates for object storage.
    18  //
    19  // PlacementPolicy is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap.PlacementPolicy
    20  // message. See ReadFromV2 / WriteToV2 methods.
    21  //
    22  // Instances can be created using built-in var declaration.
    23  type PlacementPolicy struct {
    24  	backupFactor uint32
    25  
    26  	filters []netmap.Filter
    27  
    28  	selectors []netmap.Selector
    29  
    30  	replicas []netmap.Replica
    31  
    32  	unique bool
    33  }
    34  
    35  func (p *PlacementPolicy) readFromV2(m netmap.PlacementPolicy, checkFieldPresence bool) error {
    36  	p.replicas = m.GetReplicas()
    37  	if checkFieldPresence {
    38  		if len(p.replicas) == 0 {
    39  			return errors.New("missing replicas")
    40  		}
    41  		if len(p.replicas) != 1 {
    42  			for i := range p.replicas {
    43  				if p.replicas[i].GetECDataCount() != 0 || p.replicas[i].GetECParityCount() != 0 {
    44  					return errors.New("erasure code group must be used exclusively")
    45  				}
    46  			}
    47  		}
    48  	}
    49  
    50  	p.backupFactor = m.GetContainerBackupFactor()
    51  	p.selectors = m.GetSelectors()
    52  	p.filters = m.GetFilters()
    53  	p.unique = m.GetUnique()
    54  
    55  	return nil
    56  }
    57  
    58  // Marshal encodes PlacementPolicy into a binary format of the FrostFS API
    59  // protocol (Protocol Buffers with direct field order).
    60  //
    61  // See also Unmarshal.
    62  func (p PlacementPolicy) Marshal() []byte {
    63  	var m netmap.PlacementPolicy
    64  	p.WriteToV2(&m)
    65  
    66  	return m.StableMarshal(nil)
    67  }
    68  
    69  // Unmarshal decodes FrostFS API protocol binary format into the PlacementPolicy
    70  // (Protocol Buffers with direct field order). Returns an error describing
    71  // a format violation.
    72  //
    73  // See also Marshal.
    74  func (p *PlacementPolicy) Unmarshal(data []byte) error {
    75  	var m netmap.PlacementPolicy
    76  
    77  	err := m.Unmarshal(data)
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	return p.readFromV2(m, false)
    83  }
    84  
    85  // MarshalJSON encodes PlacementPolicy into a JSON format of the FrostFS API
    86  // protocol (Protocol Buffers JSON).
    87  //
    88  // See also UnmarshalJSON.
    89  func (p PlacementPolicy) MarshalJSON() ([]byte, error) {
    90  	var m netmap.PlacementPolicy
    91  	p.WriteToV2(&m)
    92  
    93  	return m.MarshalJSON()
    94  }
    95  
    96  // UnmarshalJSON decodes FrostFS API protocol JSON format into the PlacementPolicy
    97  // (Protocol Buffers JSON). Returns an error describing a format violation.
    98  //
    99  // See also MarshalJSON.
   100  func (p *PlacementPolicy) UnmarshalJSON(data []byte) error {
   101  	var m netmap.PlacementPolicy
   102  
   103  	err := m.UnmarshalJSON(data)
   104  	if err != nil {
   105  		return err
   106  	}
   107  
   108  	return p.readFromV2(m, false)
   109  }
   110  
   111  // ReadFromV2 reads PlacementPolicy from the netmap.PlacementPolicy message.
   112  // Checks if the message conforms to FrostFS API V2 protocol.
   113  //
   114  // See also WriteToV2.
   115  func (p *PlacementPolicy) ReadFromV2(m netmap.PlacementPolicy) error {
   116  	return p.readFromV2(m, true)
   117  }
   118  
   119  // WriteToV2 writes PlacementPolicy to the session.Token message.
   120  // The message must not be nil.
   121  //
   122  // See also ReadFromV2.
   123  func (p PlacementPolicy) WriteToV2(m *netmap.PlacementPolicy) {
   124  	m.SetContainerBackupFactor(p.backupFactor)
   125  	m.SetFilters(p.filters)
   126  	m.SetSelectors(p.selectors)
   127  	m.SetReplicas(p.replicas)
   128  	m.SetUnique(p.unique)
   129  }
   130  
   131  // ReplicaDescriptor replica descriptor characterizes replicas of objects from
   132  // the subset selected by a particular Selector.
   133  type ReplicaDescriptor struct {
   134  	m netmap.Replica
   135  }
   136  
   137  // SetNumberOfObjects sets number of object replicas.
   138  func (r *ReplicaDescriptor) SetNumberOfObjects(c uint32) {
   139  	r.m.SetCount(c)
   140  }
   141  
   142  func (r *ReplicaDescriptor) SetECDataCount(v uint32) {
   143  	r.m.SetECDataCount(v)
   144  }
   145  
   146  func (r *ReplicaDescriptor) SetECParityCount(v uint32) {
   147  	r.m.SetECParityCount(v)
   148  }
   149  
   150  // NumberOfObjects returns number set using SetNumberOfObjects.
   151  //
   152  // Zero ReplicaDescriptor has zero number of objects.
   153  func (r ReplicaDescriptor) NumberOfObjects() uint32 {
   154  	return r.m.GetCount()
   155  }
   156  
   157  func (r ReplicaDescriptor) GetECDataCount() uint32 {
   158  	return r.m.GetECDataCount()
   159  }
   160  
   161  func (r ReplicaDescriptor) GetECParityCount() uint32 {
   162  	return r.m.GetECParityCount()
   163  }
   164  
   165  // TotalECPartCount returns total sum of ECDataCount and ECParityCount.
   166  func (r ReplicaDescriptor) TotalECPartCount() uint32 {
   167  	return r.m.GetECDataCount() + r.m.GetECParityCount()
   168  }
   169  
   170  // SetSelectorName sets name of the related Selector.
   171  //
   172  // Zero ReplicaDescriptor references to the root bucket's selector: it contains
   173  // all possible nodes to store the object.
   174  func (r *ReplicaDescriptor) SetSelectorName(s string) {
   175  	r.m.SetSelector(s)
   176  }
   177  
   178  // AddReplicas adds a bunch object replica's characteristics.
   179  //
   180  // See also IterateReplicas.
   181  func (p *PlacementPolicy) AddReplicas(rs ...ReplicaDescriptor) {
   182  	off := len(p.replicas)
   183  
   184  	p.replicas = append(p.replicas, make([]netmap.Replica, len(rs))...)
   185  
   186  	for i := range rs {
   187  		p.replicas[off+i] = rs[i].m
   188  	}
   189  }
   190  
   191  // NumberOfReplicas returns number of replica descriptors set using AddReplicas.
   192  //
   193  // Zero PlacementPolicy has no replicas which is incorrect according to the
   194  // FrostFS API protocol.
   195  func (p PlacementPolicy) NumberOfReplicas() int {
   196  	return len(p.replicas)
   197  }
   198  
   199  // ReplicaNumberByIndex returns number of object replicas from the i-th replica
   200  // descriptor. Index MUST be in range [0; NumberOfReplicas()).
   201  //
   202  // Zero PlacementPolicy has no replicas.
   203  //
   204  // Deprecated: Use PlacementPolicy.ReplicaDescriptor(int).NumberOfObjects() instead.
   205  func (p PlacementPolicy) ReplicaNumberByIndex(i int) uint32 {
   206  	return p.replicas[i].GetCount()
   207  }
   208  
   209  // ReplicaDescriptor returns i-th replica descriptor. Index MUST be in range [0; NumberOfReplicas()).
   210  func (p PlacementPolicy) ReplicaDescriptor(i int) ReplicaDescriptor {
   211  	return ReplicaDescriptor{
   212  		m: p.replicas[i],
   213  	}
   214  }
   215  
   216  // SetContainerBackupFactor sets container backup factor: it controls how deep
   217  // FrostFS will search for nodes alternatives to include into container's nodes subset.
   218  //
   219  // Zero PlacementPolicy has zero container backup factor.
   220  func (p *PlacementPolicy) SetContainerBackupFactor(f uint32) {
   221  	p.backupFactor = f
   222  }
   223  
   224  // SetUnique sets the unique flag: it controls whether the selected replica buckets
   225  // are disjoint or not.
   226  //
   227  // Zero PlacementPolicy has false unique flag.
   228  func (p *PlacementPolicy) SetUnique(b bool) {
   229  	p.unique = b
   230  }
   231  
   232  // Selector describes the bucket selection operator: choose a number of nodes
   233  // from the bucket taking the nearest nodes to the related container by hash distance.
   234  type Selector struct {
   235  	m netmap.Selector
   236  }
   237  
   238  // SetName sets name with which the Selector can be referenced.
   239  //
   240  // Zero Selector is unnamed.
   241  func (s *Selector) SetName(name string) {
   242  	s.m.SetName(name)
   243  }
   244  
   245  // SetNumberOfNodes sets number of nodes to select from the bucket.
   246  //
   247  // Zero Selector selects nothing.
   248  func (s *Selector) SetNumberOfNodes(num uint32) {
   249  	s.m.SetCount(num)
   250  }
   251  
   252  // SelectByBucketAttribute sets attribute of the bucket to select nodes from.
   253  //
   254  // Zero Selector has empty attribute.
   255  func (s *Selector) SelectByBucketAttribute(bucket string) {
   256  	s.m.SetAttribute(bucket)
   257  }
   258  
   259  // SetClause sets the clause for the Selector.
   260  func (s *Selector) SetClause(clause netmap.Clause) {
   261  	s.m.SetClause(clause)
   262  }
   263  
   264  // SelectSame makes selection algorithm to select only nodes having the same values
   265  // of the bucket attribute.
   266  //
   267  // Zero Selector doesn't specify selection modifier so nodes are selected randomly.
   268  //
   269  // See also SelectByBucketAttribute.
   270  func (s *Selector) SelectSame() {
   271  	s.m.SetClause(netmap.Same)
   272  }
   273  
   274  // SelectDistinct makes selection algorithm to select only nodes having the different values
   275  // of the bucket attribute.
   276  //
   277  // Zero Selector doesn't specify selection modifier so nodes are selected randomly.
   278  //
   279  // See also SelectByBucketAttribute.
   280  func (s *Selector) SelectDistinct() {
   281  	s.m.SetClause(netmap.Distinct)
   282  }
   283  
   284  // SetFilterName sets reference to pre-filtering nodes for selection.
   285  //
   286  // Zero Selector has no filtering reference.
   287  //
   288  // See also Filter.SetName.
   289  func (s *Selector) SetFilterName(f string) {
   290  	s.m.SetFilter(f)
   291  }
   292  
   293  // AddSelectors adds a Selector bunch to form the subset of the nodes
   294  // to store container objects.
   295  //
   296  // Zero PlacementPolicy does not declare selectors.
   297  func (p *PlacementPolicy) AddSelectors(ss ...Selector) {
   298  	off := len(p.selectors)
   299  
   300  	p.selectors = append(p.selectors, make([]netmap.Selector, len(ss))...)
   301  
   302  	for i := range ss {
   303  		p.selectors[off+i] = ss[i].m
   304  	}
   305  }
   306  
   307  // Filter contains rules for filtering the node sets.
   308  type Filter struct {
   309  	m netmap.Filter
   310  }
   311  
   312  // SetName sets name with which the Filter can be referenced or, for inner filters,
   313  // to which the Filter references. Top-level filters MUST be named. The name
   314  // MUST NOT be '*'.
   315  //
   316  // Zero Filter is unnamed.
   317  func (x *Filter) SetName(name string) {
   318  	x.m.SetName(name)
   319  }
   320  
   321  func (x *Filter) setAttribute(key string, op netmap.Operation, val string) {
   322  	x.m.SetKey(key)
   323  	x.m.SetOp(op)
   324  	x.m.SetValue(val)
   325  }
   326  
   327  // Like applies the rule to accept only nodes with attribute like value.
   328  //
   329  // Method SHOULD NOT be called along with other similar methods.
   330  func (x *Filter) Like(key, value string) {
   331  	x.setAttribute(key, netmap.LIKE, value)
   332  }
   333  
   334  // Equal applies the rule to accept only nodes with the same attribute value.
   335  //
   336  // Method SHOULD NOT be called along with other similar methods.
   337  func (x *Filter) Equal(key, value string) {
   338  	x.setAttribute(key, netmap.EQ, value)
   339  }
   340  
   341  // NotEqual applies the rule to accept only nodes with the distinct attribute value.
   342  //
   343  // Method SHOULD NOT be called along with other similar methods.
   344  func (x *Filter) NotEqual(key, value string) {
   345  	x.setAttribute(key, netmap.NE, value)
   346  }
   347  
   348  // NumericGT applies the rule to accept only nodes with the numeric attribute
   349  // greater than given number.
   350  //
   351  // Method SHOULD NOT be called along with other similar methods.
   352  func (x *Filter) NumericGT(key string, num int64) {
   353  	x.setAttribute(key, netmap.GT, strconv.FormatInt(num, 10))
   354  }
   355  
   356  // NumericGE applies the rule to accept only nodes with the numeric attribute
   357  // greater than or equal to given number.
   358  //
   359  // Method SHOULD NOT be called along with other similar methods.
   360  func (x *Filter) NumericGE(key string, num int64) {
   361  	x.setAttribute(key, netmap.GE, strconv.FormatInt(num, 10))
   362  }
   363  
   364  // NumericLT applies the rule to accept only nodes with the numeric attribute
   365  // less than given number.
   366  //
   367  // Method SHOULD NOT be called along with other similar methods.
   368  func (x *Filter) NumericLT(key string, num int64) {
   369  	x.setAttribute(key, netmap.LT, strconv.FormatInt(num, 10))
   370  }
   371  
   372  // NumericLE applies the rule to accept only nodes with the numeric attribute
   373  // less than or equal to given number.
   374  //
   375  // Method SHOULD NOT be called along with other similar methods.
   376  func (x *Filter) NumericLE(key string, num int64) {
   377  	x.setAttribute(key, netmap.LE, strconv.FormatInt(num, 10))
   378  }
   379  
   380  func (x *Filter) setInnerFilters(op netmap.Operation, filters []Filter) {
   381  	x.setAttribute("", op, "")
   382  
   383  	inner := x.m.GetFilters()
   384  	if rem := len(filters) - len(inner); rem > 0 {
   385  		inner = append(inner, make([]netmap.Filter, rem)...)
   386  	}
   387  
   388  	for i := range filters {
   389  		inner[i] = filters[i].m
   390  	}
   391  
   392  	x.m.SetFilters(inner)
   393  }
   394  
   395  // LogicalOR applies the rule to accept only nodes which satisfy at least one
   396  // of the given filters.
   397  //
   398  // Method SHOULD NOT be called along with other similar methods.
   399  func (x *Filter) LogicalOR(filters ...Filter) {
   400  	x.setInnerFilters(netmap.OR, filters)
   401  }
   402  
   403  // LogicalAND applies the rule to accept only nodes which satisfy all the given
   404  // filters.
   405  //
   406  // Method SHOULD NOT be called along with other similar methods.
   407  func (x *Filter) LogicalAND(filters ...Filter) {
   408  	x.setInnerFilters(netmap.AND, filters)
   409  }
   410  
   411  // AddFilters adds a Filter bunch that will be applied when selecting nodes.
   412  //
   413  // Zero PlacementPolicy has no filters.
   414  func (p *PlacementPolicy) AddFilters(fs ...Filter) {
   415  	off := len(p.filters)
   416  
   417  	p.filters = append(p.filters, make([]netmap.Filter, len(fs))...)
   418  
   419  	for i := range fs {
   420  		p.filters[off+i] = fs[i].m
   421  	}
   422  }
   423  
   424  // WriteStringTo encodes PlacementPolicy into human-readably query and writes
   425  // the result into w. Returns w's errors directly.
   426  //
   427  // See also DecodeString.
   428  // nolint: funlen
   429  func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) {
   430  	if p.unique {
   431  		if _, err := w.WriteString("UNIQUE\n"); err != nil {
   432  			return err
   433  		}
   434  	}
   435  
   436  	delim := ""
   437  
   438  	for i := range p.replicas {
   439  		c := p.replicas[i].GetCount()
   440  		s := p.replicas[i].GetSelector()
   441  
   442  		if c != 0 {
   443  			_, err = w.WriteString(fmt.Sprintf("%sREP %d", delim, c))
   444  		} else {
   445  			ecx, ecy := p.replicas[i].GetECDataCount(), p.replicas[i].GetECParityCount()
   446  			_, err = w.WriteString(fmt.Sprintf("%sEC %d.%d", delim, ecx, ecy))
   447  		}
   448  		if s != "" {
   449  			_, err = w.WriteString(fmt.Sprintf(" IN %s", s))
   450  		}
   451  
   452  		if err != nil {
   453  			return err
   454  		}
   455  
   456  		delim = "\n"
   457  	}
   458  
   459  	if p.backupFactor > 0 {
   460  		_, err = w.WriteString(fmt.Sprintf("\nCBF %d", p.backupFactor))
   461  		if err != nil {
   462  			return err
   463  		}
   464  	}
   465  
   466  	var s string
   467  
   468  	for i := range p.selectors {
   469  		_, err = w.WriteString(fmt.Sprintf("\nSELECT %d", p.selectors[i].GetCount()))
   470  		if err != nil {
   471  			return err
   472  		}
   473  
   474  		if s = p.selectors[i].GetAttribute(); s != "" {
   475  			var clause string
   476  
   477  			switch p.selectors[i].GetClause() {
   478  			case netmap.Same:
   479  				clause = "SAME "
   480  			case netmap.Distinct:
   481  				clause = "DISTINCT "
   482  			default:
   483  				clause = ""
   484  			}
   485  
   486  			_, err = w.WriteString(fmt.Sprintf(" IN %s%s", clause, s))
   487  			if err != nil {
   488  				return err
   489  			}
   490  		}
   491  
   492  		if s = p.selectors[i].GetFilter(); s != "" {
   493  			_, err = w.WriteString(" FROM " + s)
   494  			if err != nil {
   495  				return err
   496  			}
   497  		}
   498  
   499  		if s = p.selectors[i].GetName(); s != "" {
   500  			_, err = w.WriteString(" AS " + s)
   501  			if err != nil {
   502  				return err
   503  			}
   504  		}
   505  	}
   506  
   507  	for i := range p.filters {
   508  		_, err = w.WriteString("\nFILTER ")
   509  		if err != nil {
   510  			return err
   511  		}
   512  
   513  		err = writeFilterStringTo(w, p.filters[i], false)
   514  		if err != nil {
   515  			return err
   516  		}
   517  	}
   518  
   519  	return nil
   520  }
   521  
   522  func writeFilterStringTo(w io.StringWriter, f netmap.Filter, mayNeedOuterBrackets bool) error {
   523  	var err error
   524  	var s string
   525  	op := f.GetOp()
   526  	unspecified := op == 0
   527  
   528  	if s = f.GetKey(); s != "" {
   529  		_, err = w.WriteString(fmt.Sprintf("%s %s %s", escapeString(s), op, escapeString(f.GetValue())))
   530  		if err != nil {
   531  			return err
   532  		}
   533  	} else if s = f.GetName(); unspecified && s != "" {
   534  		_, err = w.WriteString(fmt.Sprintf("@%s", s))
   535  		if err != nil {
   536  			return err
   537  		}
   538  	}
   539  
   540  	inner := f.GetFilters()
   541  
   542  	if op == netmap.NOT {
   543  		_, err = w.WriteString(op.String() + " (")
   544  		if err != nil {
   545  			return err
   546  		}
   547  		err = writeFilterStringTo(w, inner[0], false)
   548  		if err != nil {
   549  			return err
   550  		}
   551  		_, err = w.WriteString(")")
   552  		if err != nil {
   553  			return err
   554  		}
   555  	} else {
   556  		useBrackets := mayNeedOuterBrackets && op == netmap.OR && len(inner) > 1
   557  		if useBrackets {
   558  			_, err = w.WriteString("(")
   559  			if err != nil {
   560  				return err
   561  			}
   562  		}
   563  		for i := range inner {
   564  			if i != 0 {
   565  				_, err = w.WriteString(" " + op.String() + " ")
   566  				if err != nil {
   567  					return err
   568  				}
   569  			}
   570  			err = writeFilterStringTo(w, inner[i], true)
   571  			if err != nil {
   572  				return err
   573  			}
   574  		}
   575  		if useBrackets {
   576  			_, err = w.WriteString(")")
   577  			if err != nil {
   578  				return err
   579  			}
   580  		}
   581  	}
   582  
   583  	if s = f.GetName(); s != "" && !unspecified {
   584  		_, err = w.WriteString(" AS " + s)
   585  		if err != nil {
   586  			return err
   587  		}
   588  	}
   589  
   590  	return nil
   591  }
   592  
   593  // DecodeString decodes PlacementPolicy from the string composed using
   594  // WriteStringTo. Returns error if s is malformed.
   595  func (p *PlacementPolicy) DecodeString(s string) error {
   596  	var v policyVisitor
   597  
   598  	input := antlr.NewInputStream(s)
   599  	lexer := parser.NewQueryLexer(input)
   600  	lexer.RemoveErrorListeners()
   601  	lexer.AddErrorListener(&v)
   602  	stream := antlr.NewCommonTokenStream(lexer, 0)
   603  
   604  	pp := parser.NewQuery(stream)
   605  	pp.BuildParseTrees = true
   606  
   607  	pp.RemoveErrorListeners()
   608  	pp.AddErrorListener(&v)
   609  	pl := pp.Policy().Accept(&v)
   610  
   611  	if len(v.errors) != 0 {
   612  		return v.errors[0]
   613  	}
   614  
   615  	parsed, ok := pl.(*PlacementPolicy)
   616  	if !ok {
   617  		return fmt.Errorf("unexpected parsed instance type %T", pl)
   618  	} else if parsed == nil {
   619  		return errors.New("parsed nil value")
   620  	}
   621  
   622  	if err := validatePolicy(*parsed); err != nil {
   623  		return fmt.Errorf("invalid policy: %w", err)
   624  	}
   625  
   626  	*p = *parsed
   627  
   628  	return nil
   629  }
   630  
   631  // SelectFilterExpr is an expression containing only selectors and filters.
   632  // It's useful to evaluate their effect before being used in a policy.
   633  type SelectFilterExpr struct {
   634  	cbf      uint32
   635  	selector *netmap.Selector
   636  	filters  []netmap.Filter
   637  }
   638  
   639  // DecodeString decodes a string into a SelectFilterExpr.
   640  // Returns an error if s is malformed.
   641  func DecodeSelectFilterString(s string) (*SelectFilterExpr, error) {
   642  	var v policyVisitor
   643  
   644  	input := antlr.NewInputStream(s)
   645  	lexer := parser.NewQueryLexer(input)
   646  	lexer.RemoveErrorListeners()
   647  	lexer.AddErrorListener(&v)
   648  	stream := antlr.NewCommonTokenStream(lexer, 0)
   649  
   650  	pp := parser.NewQuery(stream)
   651  	pp.BuildParseTrees = true
   652  
   653  	pp.RemoveErrorListeners()
   654  	pp.AddErrorListener(&v)
   655  	sfExpr := pp.SelectFilterExpr().Accept(&v)
   656  
   657  	if len(v.errors) != 0 {
   658  		return nil, v.errors[0]
   659  	}
   660  
   661  	parsed, ok := sfExpr.(*SelectFilterExpr)
   662  	if !ok {
   663  		return nil, fmt.Errorf("unexpected parsed instance type %T", sfExpr)
   664  	}
   665  
   666  	return parsed, nil
   667  }
   668  
   669  var (
   670  	// errUnknownFilter is returned when a value of FROM in a query is unknown.
   671  	errUnknownFilter = errors.New("filter not found")
   672  	// errUnknownSelector is returned when a value of IN is unknown.
   673  	errUnknownSelector = errors.New("policy: selector not found")
   674  	// errSyntaxError is returned for errors found by ANTLR parser.
   675  	errSyntaxError = errors.New("policy: syntax error")
   676  	// errRedundantSelector is returned for errors found by selectors policy validator.
   677  	errRedundantSelector = errors.New("policy: found redundant selector")
   678  	// errUnnamedSelector is returned for errors found by selectors policy validator.
   679  	errUnnamedSelector = errors.New("policy: unnamed selectors are useless, " +
   680  		"make sure to pair REP and SELECT clauses: \"REP .. IN X\" + \"SELECT ... AS X\"")
   681  	// errRedundantSelector is returned for errors found by filters policy validator.
   682  	errRedundantFilter = errors.New("policy: found redundant filter")
   683  	// errECFewSelectors is returned when EC keyword is used without UNIQUE keyword.
   684  	errECFewSelectors = errors.New("policy: too few nodes to select")
   685  )
   686  
   687  type policyVisitor struct {
   688  	errors []error
   689  	parser.BaseQueryVisitor
   690  	antlr.DefaultErrorListener
   691  }
   692  
   693  func (p *policyVisitor) SyntaxError(_ antlr.Recognizer, _ any, line, column int, msg string, _ antlr.RecognitionException) {
   694  	p.reportError(fmt.Errorf("%w: line %d:%d %s", errSyntaxError, line, column, msg))
   695  }
   696  
   697  func (p *policyVisitor) reportError(err error) any {
   698  	p.errors = append(p.errors, err)
   699  	return nil
   700  }
   701  
   702  // VisitPolicy implements parser.QueryVisitor interface.
   703  func (p *policyVisitor) VisitPolicy(ctx *parser.PolicyContext) any {
   704  	if len(p.errors) != 0 {
   705  		return nil
   706  	}
   707  
   708  	pl := new(PlacementPolicy)
   709  
   710  	pl.unique = ctx.UNIQUE() != nil
   711  
   712  	stmts := ctx.GetChildren()
   713  	for _, r := range stmts {
   714  		var res *netmap.Replica
   715  		var ok bool
   716  		switch r := r.(type) {
   717  		case parser.IRepStmtContext:
   718  			res, ok = r.Accept(p).(*netmap.Replica)
   719  		case parser.IEcStmtContext:
   720  			res, ok = r.Accept(p).(*netmap.Replica)
   721  		default:
   722  			continue
   723  		}
   724  		if !ok {
   725  			return nil
   726  		}
   727  
   728  		pl.replicas = append(pl.replicas, *res)
   729  	}
   730  
   731  	if cbfStmt := ctx.CbfStmt(); cbfStmt != nil {
   732  		cbf, ok := cbfStmt.(*parser.CbfStmtContext).Accept(p).(uint32)
   733  		if !ok {
   734  			return nil
   735  		}
   736  		pl.SetContainerBackupFactor(cbf)
   737  	}
   738  
   739  	selStmts := ctx.AllSelectStmt()
   740  	pl.selectors = make([]netmap.Selector, 0, len(selStmts))
   741  
   742  	for _, s := range selStmts {
   743  		res, ok := s.Accept(p).(*netmap.Selector)
   744  		if !ok {
   745  			return nil
   746  		}
   747  
   748  		pl.selectors = append(pl.selectors, *res)
   749  	}
   750  
   751  	filtStmts := ctx.AllFilterStmt()
   752  	pl.filters = make([]netmap.Filter, 0, len(filtStmts))
   753  
   754  	for _, f := range filtStmts {
   755  		pl.filters = append(pl.filters, *f.Accept(p).(*netmap.Filter))
   756  	}
   757  
   758  	return pl
   759  }
   760  
   761  func (p *policyVisitor) VisitSelectFilterExpr(ctx *parser.SelectFilterExprContext) any {
   762  	if len(p.errors) != 0 {
   763  		return nil
   764  	}
   765  
   766  	sfExpr := new(SelectFilterExpr)
   767  
   768  	if cbfStmt := ctx.CbfStmt(); cbfStmt != nil {
   769  		cbf, ok := cbfStmt.(*parser.CbfStmtContext).Accept(p).(uint32)
   770  		if !ok {
   771  			return nil
   772  		}
   773  		sfExpr.cbf = cbf
   774  	}
   775  
   776  	if selStmt := ctx.SelectStmt(); selStmt != nil {
   777  		sel, ok := selStmt.Accept(p).(*netmap.Selector)
   778  		if !ok {
   779  			return nil
   780  		}
   781  		sfExpr.selector = sel
   782  	}
   783  
   784  	filtStmts := ctx.AllFilterStmt()
   785  	sfExpr.filters = make([]netmap.Filter, 0, len(filtStmts))
   786  
   787  	for _, f := range filtStmts {
   788  		sfExpr.filters = append(sfExpr.filters, *f.Accept(p).(*netmap.Filter))
   789  	}
   790  
   791  	return sfExpr
   792  }
   793  
   794  func (p *policyVisitor) VisitCbfStmt(ctx *parser.CbfStmtContext) any {
   795  	cbf, err := strconv.ParseUint(ctx.GetBackupFactor().GetText(), 10, 32)
   796  	if err != nil {
   797  		return p.reportError(errInvalidNumber)
   798  	}
   799  
   800  	return uint32(cbf)
   801  }
   802  
   803  // VisitRepStmt implements parser.QueryVisitor interface.
   804  func (p *policyVisitor) VisitRepStmt(ctx *parser.RepStmtContext) any {
   805  	num, err := strconv.ParseUint(ctx.GetCount().GetText(), 10, 32)
   806  	if err != nil {
   807  		return p.reportError(errInvalidNumber)
   808  	}
   809  
   810  	rs := new(netmap.Replica)
   811  	rs.SetCount(uint32(num))
   812  
   813  	if sel := ctx.GetSelector(); sel != nil {
   814  		rs.SetSelector(sel.GetText())
   815  	}
   816  
   817  	return rs
   818  }
   819  
   820  // VisitRepStmt implements parser.QueryVisitor interface.
   821  func (p *policyVisitor) VisitEcStmt(ctx *parser.EcStmtContext) any {
   822  	dataCount, err := strconv.ParseUint(ctx.GetData().GetText(), 10, 32)
   823  	if err != nil {
   824  		return p.reportError(errInvalidNumber)
   825  	}
   826  	parityCount, err := strconv.ParseUint(ctx.GetParity().GetText(), 10, 32)
   827  	if err != nil {
   828  		return p.reportError(errInvalidNumber)
   829  	}
   830  
   831  	rs := new(netmap.Replica)
   832  	rs.SetECDataCount(uint32(dataCount))
   833  	rs.SetECParityCount(uint32(parityCount))
   834  
   835  	if sel := ctx.GetSelector(); sel != nil {
   836  		rs.SetSelector(sel.GetText())
   837  	}
   838  
   839  	return rs
   840  }
   841  
   842  // VisitSelectStmt implements parser.QueryVisitor interface.
   843  func (p *policyVisitor) VisitSelectStmt(ctx *parser.SelectStmtContext) any {
   844  	res, err := strconv.ParseUint(ctx.GetCount().GetText(), 10, 32)
   845  	if err != nil {
   846  		return p.reportError(errInvalidNumber)
   847  	}
   848  
   849  	s := new(netmap.Selector)
   850  	s.SetCount(uint32(res))
   851  
   852  	if clStmt := ctx.Clause(); clStmt != nil {
   853  		s.SetClause(clauseFromString(clStmt.GetText()))
   854  	}
   855  
   856  	if bStmt := ctx.GetBucket(); bStmt != nil {
   857  		s.SetAttribute(ctx.GetBucket().GetText())
   858  	}
   859  
   860  	s.SetFilter(ctx.GetFilter().GetText()) // either ident or wildcard
   861  
   862  	if ctx.AS() != nil {
   863  		s.SetName(ctx.GetName().GetText())
   864  	}
   865  	return s
   866  }
   867  
   868  // VisitFilterStmt implements parser.QueryVisitor interface.
   869  func (p *policyVisitor) VisitFilterStmt(ctx *parser.FilterStmtContext) any {
   870  	f := p.VisitFilterExpr(ctx.GetExpr().(*parser.FilterExprContext)).(*netmap.Filter)
   871  	f.SetName(ctx.GetName().GetText())
   872  	return f
   873  }
   874  
   875  func (p *policyVisitor) VisitFilterExpr(ctx *parser.FilterExprContext) any {
   876  	if eCtx := ctx.Expr(); eCtx != nil {
   877  		return eCtx.Accept(p)
   878  	}
   879  
   880  	if inner := ctx.GetInner(); inner != nil {
   881  		return inner.Accept(p)
   882  	}
   883  
   884  	f := new(netmap.Filter)
   885  	op := operationFromString(ctx.GetOp().GetText())
   886  	f.SetOp(op)
   887  
   888  	if op == netmap.NOT {
   889  		f1 := *ctx.GetF1().Accept(p).(*netmap.Filter)
   890  		f.SetFilters([]netmap.Filter{f1})
   891  		return f
   892  	}
   893  
   894  	f1 := *ctx.GetF1().Accept(p).(*netmap.Filter)
   895  	f2 := *ctx.GetF2().Accept(p).(*netmap.Filter)
   896  
   897  	// Consider f1=(.. AND ..) AND f2. This can be merged because our AND operation
   898  	// is of arbitrary arity. ANTLR generates left-associative parse-tree by default.
   899  	if f1.GetOp() == op {
   900  		f.SetFilters(append(f1.GetFilters(), f2))
   901  		return f
   902  	}
   903  
   904  	f.SetFilters([]netmap.Filter{f1, f2})
   905  
   906  	return f
   907  }
   908  
   909  // VisitFilterKey implements parser.QueryVisitor interface.
   910  func (p *policyVisitor) VisitFilterKey(ctx *parser.FilterKeyContext) any {
   911  	if id := ctx.Ident(); id != nil {
   912  		return id.GetText()
   913  	}
   914  
   915  	str := ctx.STRING().GetText()
   916  	return str[1 : len(str)-1]
   917  }
   918  
   919  func (p *policyVisitor) VisitFilterValue(ctx *parser.FilterValueContext) any {
   920  	if id := ctx.Ident(); id != nil {
   921  		return id.GetText()
   922  	}
   923  
   924  	if num := ctx.Number(); num != nil {
   925  		return num.GetText()
   926  	}
   927  
   928  	str := ctx.STRING().GetText()
   929  	return str[1 : len(str)-1]
   930  }
   931  
   932  // VisitExpr implements parser.QueryVisitor interface.
   933  func (p *policyVisitor) VisitExpr(ctx *parser.ExprContext) any {
   934  	f := new(netmap.Filter)
   935  	if flt := ctx.GetFilter(); flt != nil {
   936  		f.SetName(flt.GetText())
   937  		return f
   938  	}
   939  
   940  	key := ctx.GetKey().Accept(p)
   941  	opStr := ctx.SIMPLE_OP().GetText()
   942  	value := ctx.GetValue().Accept(p)
   943  
   944  	f.SetKey(key.(string))
   945  	f.SetOp(operationFromString(opStr))
   946  	f.SetValue(value.(string))
   947  
   948  	return f
   949  }
   950  
   951  // validatePolicy checks high-level constraints such as filter link in SELECT
   952  // being actually defined in FILTER section.
   953  func validatePolicy(p PlacementPolicy) error {
   954  	canOmitNames := len(p.selectors) == 1 && len(p.replicas) == 1
   955  	seenFilters := map[string]bool{}
   956  	expectedFilters := map[string]struct{}{}
   957  	for i := range p.filters {
   958  		seenFilters[p.filters[i].GetName()] = true
   959  		for _, f := range p.filters[i].GetFilters() {
   960  			if f.GetName() != "" {
   961  				expectedFilters[f.GetName()] = struct{}{}
   962  			}
   963  		}
   964  	}
   965  
   966  	seenSelectors := map[string]*netmap.Selector{}
   967  	for i := range p.selectors {
   968  		if p.selectors[i].GetName() == "" && !canOmitNames {
   969  			return errUnnamedSelector
   970  		}
   971  		if flt := p.selectors[i].GetFilter(); flt != mainFilterName {
   972  			expectedFilters[flt] = struct{}{}
   973  			if !seenFilters[flt] {
   974  				return fmt.Errorf("%w: '%s'", errUnknownFilter, flt)
   975  			}
   976  		}
   977  		seenSelectors[p.selectors[i].GetName()] = &p.selectors[i]
   978  	}
   979  
   980  	for _, f := range p.filters {
   981  		if _, ok := expectedFilters[f.GetName()]; !ok {
   982  			return fmt.Errorf("%w: '%s'", errRedundantFilter, f.GetName())
   983  		}
   984  	}
   985  
   986  	expectedSelectors := map[string]struct{}{}
   987  	for i := range p.replicas {
   988  		selName := p.replicas[i].GetSelector()
   989  		if selName != "" || canOmitNames {
   990  			expectedSelectors[selName] = struct{}{}
   991  			if seenSelectors[selName] == nil {
   992  				return fmt.Errorf("%w: '%s'", errUnknownSelector, selName)
   993  			}
   994  
   995  			dataCount := p.replicas[i].GetECDataCount()
   996  			parityCount := p.replicas[i].GetECParityCount()
   997  			if dataCount != 0 || parityCount != 0 {
   998  				if c := seenSelectors[selName].GetCount(); c < dataCount+parityCount {
   999  					return fmt.Errorf("%w: %d < %d + %d", errECFewSelectors, c, dataCount, parityCount)
  1000  				}
  1001  			}
  1002  		}
  1003  	}
  1004  
  1005  	for _, s := range p.selectors {
  1006  		if _, ok := expectedSelectors[s.GetName()]; !ok {
  1007  			return fmt.Errorf("%w: to use selector '%s' use keyword IN", errRedundantSelector, s.GetName())
  1008  		}
  1009  	}
  1010  
  1011  	return nil
  1012  }
  1013  
  1014  func clauseFromString(s string) (c netmap.Clause) {
  1015  	if !c.FromString(strings.ToUpper(s)) {
  1016  		// Such errors should be handled by ANTLR code thus this panic.
  1017  		panic(fmt.Errorf("BUG: invalid clause: %s", c))
  1018  	}
  1019  
  1020  	return
  1021  }
  1022  
  1023  func operationFromString(s string) (op netmap.Operation) {
  1024  	if !op.FromString(strings.ToUpper(s)) {
  1025  		// Such errors should be handled by ANTLR code thus this panic.
  1026  		panic(fmt.Errorf("BUG: invalid operation: %s", op))
  1027  	}
  1028  
  1029  	return
  1030  }
  1031  
  1032  // escapeString returns single quote wrapped string.
  1033  // Wrapping rules must be kept in sync with QueryLexer.g4.
  1034  // Currently only ASCII letters, digits and underscore can be parsed without quotes.
  1035  func escapeString(s string) string {
  1036  	for _, r := range s {
  1037  		if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || '0' <= r && r <= '9' || r == '_' {
  1038  			continue
  1039  		}
  1040  		return "'" + s + "'"
  1041  	}
  1042  	return s
  1043  }