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 }