github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/asserts/pool.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package asserts 21 22 import ( 23 "errors" 24 "fmt" 25 26 "github.com/snapcore/snapd/asserts/internal" 27 ) 28 29 // A Grouping identifies opaquely a grouping of assertions. 30 // Pool uses it to label the intersection between a set of groups. 31 type Grouping string 32 33 // A pool helps holding and tracking a set of assertions and their 34 // prerequisites as they need to be updated or resolved. The 35 // assertions can be organized in groups. Failure can be tracked 36 // isolated to groups, conversely any error related to a single group 37 // alone will stop any work to resolve it. Independent assertions 38 // should not be grouped. Assertions and prerequisites that are part 39 // of more than one group are tracked properly only once. 40 // 41 // Typical usage involves specifying the initial assertions needing to 42 // be resolved or updated using AddUnresolved and AddToUpdate. 43 // AddUnresolvedSequence and AddSequenceToUpdate exist parallel to 44 // AddUnresolved/AddToUpdate to handle sequence-forming assertions, 45 // which cannot be used with the latter. 46 // At this point ToResolve can be called to get them organized in 47 // groupings ready for fetching. Fetched assertions can then be provided 48 // with Add or AddBatch. Because these can have prerequisites calling 49 // ToResolve and fetching needs to be repeated until ToResolve's 50 // result is empty. Between any two ToResolve invocations but after 51 // any Add or AddBatch AddUnresolved/AddToUpdate can also be used 52 // again. 53 // 54 // V 55 // | 56 // /-> AddUnresolved, AddToUpdate 57 // | | 58 // | V 59 // |------> ToResolve -> empty? done 60 // | | 61 // | V 62 // \ __________ Add 63 // 64 // 65 // If errors prevent from fulfilling assertions from a ToResolve, 66 // AddError and AddGroupingError can be used to report the errors so 67 // that they can be associated with groups. 68 // 69 // All the resolved assertions in a Pool from groups not in error can 70 // be committed to a destination database with CommitTo. 71 type Pool struct { 72 groundDB RODatabase 73 74 numbering map[string]uint16 75 groupings *internal.Groupings 76 77 unresolved map[string]unresolvedAssertRecord 78 unresolvedSequences map[string]unresolvedAssertRecord 79 prerequisites map[string]unresolvedAssertRecord 80 81 bs Backstore 82 unchanged map[string]bool 83 84 groups map[uint16]*groupRec 85 86 curPhase poolPhase 87 } 88 89 // NewPool creates a new Pool, groundDB is used to resolve trusted and 90 // predefined assertions and to provide the current revision for 91 // assertions to update and their prerequisites. Up to n groups can be 92 // used to organize the assertions. 93 func NewPool(groundDB RODatabase, n int) *Pool { 94 groupings, err := internal.NewGroupings(n) 95 if err != nil { 96 panic(fmt.Sprintf("NewPool: %v", err)) 97 } 98 return &Pool{ 99 groundDB: groundDB, 100 numbering: make(map[string]uint16), 101 groupings: groupings, 102 unresolved: make(map[string]unresolvedAssertRecord), 103 unresolvedSequences: make(map[string]unresolvedAssertRecord), 104 prerequisites: make(map[string]unresolvedAssertRecord), 105 bs: NewMemoryBackstore(), 106 unchanged: make(map[string]bool), 107 groups: make(map[uint16]*groupRec), 108 } 109 } 110 111 func (p *Pool) groupNum(group string) (gnum uint16, err error) { 112 if gnum, ok := p.numbering[group]; ok { 113 return gnum, nil 114 } 115 gnum = uint16(len(p.numbering)) 116 if err = p.groupings.WithinRange(gnum); err != nil { 117 return 0, err 118 } 119 p.numbering[group] = gnum 120 return gnum, nil 121 } 122 123 func (p *Pool) ensureGroup(group string) (gnum uint16, err error) { 124 gnum, err = p.groupNum(group) 125 if err != nil { 126 return 0, err 127 } 128 if gRec := p.groups[gnum]; gRec == nil { 129 p.groups[gnum] = &groupRec{ 130 name: group, 131 } 132 } 133 return gnum, nil 134 } 135 136 // Singleton returns a grouping containing only the given group. 137 // It is useful mainly for tests and to drive Add are AddBatch when the 138 // server is pushing assertions (instead of the usual pull scenario). 139 func (p *Pool) Singleton(group string) (Grouping, error) { 140 gnum, err := p.ensureGroup(group) 141 if err != nil { 142 return Grouping(""), nil 143 } 144 145 var grouping internal.Grouping 146 p.groupings.AddTo(&grouping, gnum) 147 return Grouping(p.groupings.Serialize(&grouping)), nil 148 } 149 150 type unresolvedAssertRecord interface { 151 isAssertionNewer(a Assertion) bool 152 groupingPtr() *internal.Grouping 153 label() Grouping 154 isRevisionNotKnown() bool 155 error() error 156 } 157 158 // An unresolvedRec tracks a single unresolved assertion until it is 159 // resolved or there is an error doing so. The field 'grouping' will 160 // grow to contain all the groups requiring this assertion while it 161 // is unresolved. 162 type unresolvedRec struct { 163 at *AtRevision 164 grouping internal.Grouping 165 166 serializedLabel Grouping 167 168 err error 169 } 170 171 func (u *unresolvedRec) isAssertionNewer(a Assertion) bool { 172 return a.Revision() > u.at.Revision 173 } 174 175 func (u *unresolvedRec) groupingPtr() *internal.Grouping { 176 return &u.grouping 177 } 178 179 func (u *unresolvedRec) label() Grouping { 180 return u.serializedLabel 181 } 182 183 func (u *unresolvedRec) isRevisionNotKnown() bool { 184 return u.at.Revision == RevisionNotKnown 185 } 186 187 func (u *unresolvedRec) error() error { 188 return u.err 189 } 190 191 func (u *unresolvedRec) exportTo(r map[Grouping][]*AtRevision, gr *internal.Groupings) { 192 serLabel := Grouping(gr.Serialize(&u.grouping)) 193 // remember serialized label 194 u.serializedLabel = serLabel 195 r[serLabel] = append(r[serLabel], u.at) 196 } 197 198 func (u *unresolvedRec) merge(at *AtRevision, gnum uint16, gr *internal.Groupings) { 199 gr.AddTo(&u.grouping, gnum) 200 // assume we want to resolve/update wrt the highest revision 201 if at.Revision > u.at.Revision { 202 u.at.Revision = at.Revision 203 } 204 } 205 206 type unresolvedSeqRec struct { 207 at *AtSequence 208 grouping internal.Grouping 209 210 serializedLabel Grouping 211 212 err error 213 } 214 215 func (u *unresolvedSeqRec) groupingPtr() *internal.Grouping { 216 return &u.grouping 217 } 218 219 func (u *unresolvedSeqRec) label() Grouping { 220 return u.serializedLabel 221 } 222 223 func (u *unresolvedSeqRec) isAssertionNewer(a Assertion) bool { 224 seqf, ok := a.(SequenceMember) 225 if !ok { 226 // This should never happen because resolveWith() compares correct types. 227 panic(fmt.Sprintf("internal error: cannot compare assertion %v with unresolved sequence-forming assertion (wrong type)", a.Ref())) 228 } 229 if u.at.Pinned { 230 return seqf.Sequence() == u.at.Sequence && a.Revision() > u.at.Revision 231 } 232 // not pinned 233 if seqf.Sequence() == u.at.Sequence { 234 return a.Revision() > u.at.Revision 235 } 236 return seqf.Sequence() > u.at.Sequence 237 } 238 239 func (u *unresolvedSeqRec) isRevisionNotKnown() bool { 240 return u.at.Revision == RevisionNotKnown 241 } 242 243 func (u *unresolvedSeqRec) error() error { 244 return u.err 245 } 246 247 func (u *unresolvedSeqRec) exportTo(r map[Grouping][]*AtSequence, gr *internal.Groupings) { 248 serLabel := Grouping(gr.Serialize(&u.grouping)) 249 // remember serialized label 250 u.serializedLabel = serLabel 251 r[serLabel] = append(r[serLabel], u.at) 252 } 253 254 // A groupRec keeps track of all the resolved assertions in a group 255 // or whether the group should be considered in error (err != nil). 256 type groupRec struct { 257 name string 258 err error 259 resolved []Ref 260 } 261 262 func (gRec *groupRec) hasErr() bool { 263 return gRec.err != nil 264 } 265 266 func (gRec *groupRec) setErr(e error) { 267 if gRec.err == nil { 268 gRec.err = e 269 } 270 } 271 272 func (gRec *groupRec) markResolved(ref *Ref) (marked bool) { 273 if gRec.hasErr() { 274 return false 275 } 276 gRec.resolved = append(gRec.resolved, *ref) 277 return true 278 } 279 280 // markResolved marks the assertion referenced by ref as resolved 281 // in all the groups in grouping, except those already in error. 282 func (p *Pool) markResolved(grouping *internal.Grouping, resolved *Ref) (marked bool) { 283 p.groupings.Iter(grouping, func(gnum uint16) error { 284 if p.groups[gnum].markResolved(resolved) { 285 marked = true 286 } 287 return nil 288 }) 289 return marked 290 } 291 292 // setErr marks all the groups in grouping as in error with error err 293 // except those already in error. 294 func (p *Pool) setErr(grouping *internal.Grouping, err error) { 295 p.groupings.Iter(grouping, func(gnum uint16) error { 296 p.groups[gnum].setErr(err) 297 return nil 298 }) 299 } 300 301 func (p *Pool) isPredefined(ref *Ref) (bool, error) { 302 _, err := ref.Resolve(p.groundDB.FindPredefined) 303 if err == nil { 304 return true, nil 305 } 306 if !IsNotFound(err) { 307 return false, err 308 } 309 return false, nil 310 } 311 312 func (p *Pool) isResolved(ref *Ref) (bool, error) { 313 if p.unchanged[ref.Unique()] { 314 return true, nil 315 } 316 _, err := p.bs.Get(ref.Type, ref.PrimaryKey, ref.Type.MaxSupportedFormat()) 317 if err == nil { 318 return true, nil 319 } 320 if !IsNotFound(err) { 321 return false, err 322 } 323 return false, nil 324 } 325 326 func (p *Pool) curRevision(ref *Ref) (int, error) { 327 a, err := ref.Resolve(p.groundDB.Find) 328 if err != nil && !IsNotFound(err) { 329 return 0, err 330 } 331 if err == nil { 332 return a.Revision(), nil 333 } 334 return RevisionNotKnown, nil 335 } 336 337 func (p *Pool) curSeqRevision(seq *AtSequence) (int, error) { 338 a, err := seq.Resolve(p.groundDB.Find) 339 if err != nil && !IsNotFound(err) { 340 return 0, err 341 } 342 if err == nil { 343 return a.Revision(), nil 344 } 345 return RevisionNotKnown, nil 346 } 347 348 type poolPhase int 349 350 const ( 351 poolPhaseAddUnresolved = iota 352 poolPhaseAdd 353 ) 354 355 func (p *Pool) phase(ph poolPhase) error { 356 if ph == p.curPhase { 357 return nil 358 } 359 if ph == poolPhaseAdd { 360 return fmt.Errorf("internal error: cannot switch to Pool add phase without invoking ToResolve first") 361 } 362 // ph == poolPhaseAddUnresolved 363 p.unresolvedBookkeeping() 364 p.curPhase = poolPhaseAddUnresolved 365 return nil 366 } 367 368 // AddUnresolved adds the assertion referenced by unresolved 369 // AtRevision to the Pool as unresolved and as required by the given group. 370 // Usually unresolved.Revision will have been set to RevisionNotKnown. 371 func (p *Pool) AddUnresolved(unresolved *AtRevision, group string) error { 372 if unresolved.Type.SequenceForming() { 373 return fmt.Errorf("internal error: AddUnresolved requested for sequence-forming assertion") 374 } 375 376 if err := p.phase(poolPhaseAddUnresolved); err != nil { 377 return err 378 } 379 gnum, err := p.ensureGroup(group) 380 if err != nil { 381 return err 382 } 383 u := *unresolved 384 ok, err := p.isPredefined(&u.Ref) 385 if err != nil { 386 return err 387 } 388 if ok { 389 // predefined, nothing to do 390 return nil 391 } 392 return p.addUnresolved(&u, gnum) 393 } 394 395 // AddUnresolvedSequence adds the assertion referenced by unresolved 396 // AtSequence to the Pool as unresolved and as required by the given group. 397 // Usually unresolved.Revision will have been set to RevisionNotKnown. 398 // Given sequence can only be added once to the Pool. 399 func (p *Pool) AddUnresolvedSequence(unresolved *AtSequence, group string) error { 400 if err := p.phase(poolPhaseAddUnresolved); err != nil { 401 return err 402 } 403 if p.unresolvedSequences[unresolved.Unique()] != nil { 404 return fmt.Errorf("internal error: sequence %v is already being resolved", unresolved.SequenceKey) 405 } 406 gnum, err := p.ensureGroup(group) 407 if err != nil { 408 return err 409 } 410 u := *unresolved 411 p.addUnresolvedSeq(&u, gnum) 412 return nil 413 } 414 415 func (p *Pool) addUnresolved(unresolved *AtRevision, gnum uint16) error { 416 ok, err := p.isResolved(&unresolved.Ref) 417 if err != nil { 418 return err 419 } 420 if ok { 421 // We assume that either the resolving of 422 // prerequisites for the already resolved assertion in 423 // progress has succeeded or will. If that's not the 424 // case we will fail at CommitTo time. We could 425 // instead recurse into its prerequisites again but the 426 // complexity isn't clearly worth it. 427 // See TestParallelPartialResolutionFailure 428 // Mark this as resolved in the group. 429 p.groups[gnum].markResolved(&unresolved.Ref) 430 return nil 431 } 432 uniq := unresolved.Ref.Unique() 433 var u unresolvedAssertRecord 434 if u = p.unresolved[uniq]; u == nil { 435 u = &unresolvedRec{ 436 at: unresolved, 437 } 438 p.unresolved[uniq] = u 439 } 440 441 urec := u.(*unresolvedRec) 442 urec.merge(unresolved, gnum, p.groupings) 443 return nil 444 } 445 446 func (p *Pool) addUnresolvedSeq(unresolved *AtSequence, gnum uint16) error { 447 uniq := unresolved.Unique() 448 u := &unresolvedSeqRec{ 449 at: unresolved, 450 } 451 p.unresolvedSequences[uniq] = u 452 return p.groupings.AddTo(&u.grouping, gnum) 453 } 454 455 // ToResolve returns all the currently unresolved assertions in the 456 // Pool, organized in opaque groupings based on which set of groups 457 // requires each of them. 458 // At the next ToResolve any unresolved assertion with not known 459 // revision that was not added via Add or AddBatch will result in all 460 // groups requiring it being in error with ErrUnresolved. 461 // Conversely, the remaining unresolved assertions originally added 462 // via AddToUpdate will be assumed to still be at their current 463 // revisions. 464 func (p *Pool) ToResolve() (map[Grouping][]*AtRevision, map[Grouping][]*AtSequence, error) { 465 if p.curPhase == poolPhaseAdd { 466 p.unresolvedBookkeeping() 467 } else { 468 p.curPhase = poolPhaseAdd 469 } 470 atr := make(map[Grouping][]*AtRevision) 471 for _, ur := range p.unresolved { 472 u := ur.(*unresolvedRec) 473 if u.at.Revision == RevisionNotKnown { 474 rev, err := p.curRevision(&u.at.Ref) 475 if err != nil { 476 return nil, nil, err 477 } 478 if rev != RevisionNotKnown { 479 u.at.Revision = rev 480 } 481 } 482 u.exportTo(atr, p.groupings) 483 } 484 485 ats := make(map[Grouping][]*AtSequence) 486 for _, u := range p.unresolvedSequences { 487 seq := u.(*unresolvedSeqRec) 488 if seq.at.Revision == RevisionNotKnown { 489 rev, err := p.curSeqRevision(seq.at) 490 if err != nil { 491 return nil, nil, err 492 } 493 if rev != RevisionNotKnown { 494 seq.at.Revision = rev 495 } 496 } 497 seq.exportTo(ats, p.groupings) 498 } 499 return atr, ats, nil 500 } 501 502 func (p *Pool) addPrerequisite(pref *Ref, g *internal.Grouping) error { 503 uniq := pref.Unique() 504 u := p.unresolved[uniq] 505 at := &AtRevision{ 506 Ref: *pref, 507 Revision: RevisionNotKnown, 508 } 509 if u == nil { 510 u = p.prerequisites[uniq] 511 } 512 if u != nil { 513 gr := p.groupings 514 gr.Iter(g, func(gnum uint16) error { 515 urec := u.(*unresolvedRec) 516 urec.merge(at, gnum, gr) 517 return nil 518 }) 519 return nil 520 } 521 ok, err := p.isPredefined(pref) 522 if err != nil { 523 return err 524 } 525 if ok { 526 // nothing to do 527 return nil 528 } 529 ok, err = p.isResolved(pref) 530 if err != nil { 531 return err 532 } 533 if ok { 534 // nothing to do, it is anyway implied 535 return nil 536 } 537 p.prerequisites[uniq] = &unresolvedRec{ 538 at: at, 539 grouping: g.Copy(), 540 } 541 return nil 542 } 543 544 func (p *Pool) add(a Assertion, g *internal.Grouping) error { 545 if err := p.bs.Put(a.Type(), a); err != nil { 546 if revErr, ok := err.(*RevisionError); ok { 547 if revErr.Current >= a.Revision() { 548 // we already got something more recent 549 return nil 550 } 551 } 552 553 return err 554 } 555 for _, pref := range a.Prerequisites() { 556 if err := p.addPrerequisite(pref, g); err != nil { 557 return err 558 } 559 } 560 keyRef := &Ref{ 561 Type: AccountKeyType, 562 PrimaryKey: []string{a.SignKeyID()}, 563 } 564 if err := p.addPrerequisite(keyRef, g); err != nil { 565 return err 566 } 567 return nil 568 } 569 570 func (p *Pool) resolveWith(unresolved map[string]unresolvedAssertRecord, uniq string, u unresolvedAssertRecord, a Assertion, extrag *internal.Grouping) (ok bool, err error) { 571 if u.isAssertionNewer(a) { 572 if extrag == nil { 573 extrag = u.groupingPtr() 574 } else { 575 p.groupings.Iter(u.groupingPtr(), func(gnum uint16) error { 576 p.groupings.AddTo(extrag, gnum) 577 return nil 578 }) 579 } 580 ref := a.Ref() 581 if p.markResolved(extrag, ref) { 582 // remove from tracking - 583 // remove u from unresolved only if the assertion 584 // is added to the resolved backstore; 585 // otherwise it might resurface as unresolved; 586 // it will be ultimately handled in 587 // unresolvedBookkeeping if it stays around 588 delete(unresolved, uniq) 589 if err := p.add(a, extrag); err != nil { 590 p.setErr(extrag, err) 591 return false, err 592 } 593 } 594 } 595 return true, nil 596 } 597 598 // Add adds the given assertion associated with the given grouping to the 599 // Pool as resolved in all the groups requiring it. 600 // Any not already resolved prerequisites of the assertion will 601 // be implicitly added as unresolved and required by all of those groups. 602 // The grouping will usually have been associated with the assertion 603 // in a ToResolve's result. Otherwise the union of all groups 604 // requiring the assertion plus the groups in grouping will be considered. 605 // The latter is mostly relevant in scenarios where the server is pushing 606 // assertions. 607 // If an error is returned it refers to an immediate or local error. 608 // Errors related to the assertions are associated with the relevant groups 609 // and can be retrieved with Err, in which case ok is set to false. 610 func (p *Pool) Add(a Assertion, grouping Grouping) (ok bool, err error) { 611 if err := p.phase(poolPhaseAdd); err != nil { 612 return false, err 613 } 614 615 if !a.SupportedFormat() { 616 e := &UnsupportedFormatError{Ref: a.Ref(), Format: a.Format()} 617 p.AddGroupingError(e, grouping) 618 return false, nil 619 } 620 621 return p.addToGrouping(a, grouping, p.groupings.Deserialize) 622 } 623 624 func (p *Pool) addToGrouping(a Assertion, grouping Grouping, deserializeGrouping func(string) (*internal.Grouping, error)) (ok bool, err error) { 625 var uniq string 626 ref := a.Ref() 627 var u unresolvedAssertRecord 628 var extrag *internal.Grouping 629 var unresolved map[string]unresolvedAssertRecord 630 631 if !ref.Type.SequenceForming() { 632 uniq = ref.Unique() 633 if u = p.unresolved[uniq]; u != nil { 634 unresolved = p.unresolved 635 } else if u = p.prerequisites[uniq]; u != nil { 636 unresolved = p.prerequisites 637 } else { 638 ok, err := p.isPredefined(a.Ref()) 639 if err != nil { 640 return false, err 641 } 642 if ok { 643 // nothing to do 644 return true, nil 645 } 646 // a is not tracked as unresolved in any way so far, 647 // this is an atypical scenario where something gets 648 // pushed but we still want to add it to the resolved 649 // lists of the relevant groups; in case it is 650 // actually already resolved most of resolveWith below will 651 // be a nop 652 rec := &unresolvedRec{ 653 at: a.At(), 654 } 655 rec.at.Revision = RevisionNotKnown 656 u = rec 657 } 658 } else { 659 atseq := AtSequence{ 660 Type: ref.Type, 661 SequenceKey: ref.PrimaryKey[:len(ref.PrimaryKey)-1], 662 } 663 uniq = atseq.Unique() 664 if u = p.unresolvedSequences[uniq]; u != nil { 665 unresolved = p.unresolvedSequences 666 } else { 667 // note: sequence-forming assertions are never prerequisites. 668 at := a.At() 669 // a is not tracked as unresolved in any way so far, 670 // this is an atypical scenario where something gets 671 // pushed but we still want to add it to the resolved 672 // lists of the relevant groups; in case it is 673 // actually already resolved most of resolveWith below will 674 // be a nop 675 rec := &unresolvedSeqRec{ 676 at: &AtSequence{ 677 Type: a.Type(), 678 SequenceKey: at.PrimaryKey[:len(at.PrimaryKey)-1], 679 }, 680 } 681 rec.at.Revision = RevisionNotKnown 682 u = rec 683 } 684 } 685 686 if u.label() != grouping { 687 var err error 688 extrag, err = deserializeGrouping(string(grouping)) 689 if err != nil { 690 return false, err 691 } 692 } 693 694 return p.resolveWith(unresolved, uniq, u, a, extrag) 695 } 696 697 // AddBatch adds all the assertions in the Batch to the Pool, 698 // associated with the given grouping and as resolved in all the 699 // groups requiring them. It is equivalent to using Add on each of them. 700 // If an error is returned it refers to an immediate or local error. 701 // Errors related to the assertions are associated with the relevant groups 702 // and can be retrieved with Err, in which case ok set to false. 703 func (p *Pool) AddBatch(b *Batch, grouping Grouping) (ok bool, err error) { 704 if err := p.phase(poolPhaseAdd); err != nil { 705 return false, err 706 } 707 708 // b dealt with unsupported formats already 709 710 // deserialize grouping if needed only once 711 var cachedGrouping *internal.Grouping 712 deser := func(_ string) (*internal.Grouping, error) { 713 if cachedGrouping != nil { 714 // do a copy as addToGrouping and resolveWith 715 // might add to their input 716 g := cachedGrouping.Copy() 717 return &g, nil 718 } 719 var err error 720 cachedGrouping, err = p.groupings.Deserialize(string(grouping)) 721 return cachedGrouping, err 722 } 723 724 inError := false 725 for _, a := range b.added { 726 ok, err := p.addToGrouping(a, grouping, deser) 727 if err != nil { 728 return false, err 729 } 730 if !ok { 731 inError = true 732 } 733 } 734 735 return !inError, nil 736 } 737 738 var ( 739 ErrUnresolved = errors.New("unresolved assertion") 740 ErrUnknownPoolGroup = errors.New("unknown pool group") 741 ) 742 743 // unresolvedBookkeeping processes any left over unresolved assertions 744 // since the last ToResolve invocation and intervening calls to Add/AddBatch, 745 // * they were either marked as in error which will be propagated 746 // to all groups requiring them 747 // * simply unresolved, which will be propagated to groups requiring them 748 // as ErrUnresolved 749 // * unchanged (update case) 750 // unresolvedBookkeeping will also promote any recorded prerequisites 751 // into actively unresolved, as long as not all the groups requiring them 752 // are in error. 753 func (p *Pool) unresolvedBookkeeping() { 754 // any left over unresolved are either: 755 // * in error 756 // * unchanged 757 // * or unresolved 758 processUnresolved := func(unresolved map[string]unresolvedAssertRecord) { 759 for uniq, ur := range unresolved { 760 e := ur.error() 761 if e == nil { 762 if ur.isRevisionNotKnown() { 763 e = ErrUnresolved 764 } else { 765 // unchanged 766 p.unchanged[uniq] = true 767 } 768 } 769 if e != nil { 770 p.setErr(ur.groupingPtr(), e) 771 } 772 delete(unresolved, uniq) 773 } 774 } 775 processUnresolved(p.unresolved) 776 processUnresolved(p.unresolvedSequences) 777 778 // prerequisites will become the new unresolved but drop them 779 // if all their groups are in error 780 for uniq, pr := range p.prerequisites { 781 prereq := pr.(*unresolvedRec) 782 useful := false 783 p.groupings.Iter(&prereq.grouping, func(gnum uint16) error { 784 if !p.groups[gnum].hasErr() { 785 useful = true 786 } 787 return nil 788 }) 789 if !useful { 790 delete(p.prerequisites, uniq) 791 continue 792 } 793 } 794 795 // prerequisites become the new unresolved, the emptied 796 // unresolved is used for prerequisites in the next round 797 p.unresolved, p.prerequisites = p.prerequisites, p.unresolved 798 } 799 800 // Err returns the error for group if group is in error, nil otherwise. 801 func (p *Pool) Err(group string) error { 802 gnum, err := p.groupNum(group) 803 if err != nil { 804 return err 805 } 806 gRec := p.groups[gnum] 807 if gRec == nil { 808 return ErrUnknownPoolGroup 809 } 810 return gRec.err 811 } 812 813 // Errors returns a mapping of groups in error to their errors. 814 func (p *Pool) Errors() map[string]error { 815 res := make(map[string]error) 816 for _, gRec := range p.groups { 817 if err := gRec.err; err != nil { 818 res[gRec.name] = err 819 } 820 } 821 if len(res) == 0 { 822 return nil 823 } 824 return res 825 } 826 827 // AddError associates error e with the unresolved assertion. 828 // The error will be propagated to all the affected groups at 829 // the next ToResolve. 830 func (p *Pool) AddError(e error, ref *Ref) error { 831 if err := p.phase(poolPhaseAdd); err != nil { 832 return err 833 } 834 uniq := ref.Unique() 835 if u := p.unresolved[uniq]; u != nil && u.(*unresolvedRec).err == nil { 836 u.(*unresolvedRec).err = e 837 } 838 return nil 839 } 840 841 // AddSequenceError associates error e with the unresolved sequence-forming 842 // assertion. 843 // The error will be propagated to all the affected groups at 844 // the next ToResolve. 845 func (p *Pool) AddSequenceError(e error, atSeq *AtSequence) error { 846 if err := p.phase(poolPhaseAdd); err != nil { 847 return err 848 } 849 uniq := atSeq.Unique() 850 if u := p.unresolvedSequences[uniq]; u != nil && u.(*unresolvedSeqRec).err == nil { 851 u.(*unresolvedSeqRec).err = e 852 } 853 return nil 854 } 855 856 // AddGroupingError puts all the groups of grouping in error, with error e. 857 func (p *Pool) AddGroupingError(e error, grouping Grouping) error { 858 if err := p.phase(poolPhaseAdd); err != nil { 859 return err 860 } 861 862 g, err := p.groupings.Deserialize(string(grouping)) 863 if err != nil { 864 return err 865 } 866 867 p.setErr(g, e) 868 return nil 869 } 870 871 // AddToUpdate adds the assertion referenced by toUpdate and all its 872 // prerequisites to the Pool as unresolved and as required by the 873 // given group. It is assumed that the assertion is currently in the 874 // ground database of the Pool, otherwise this will error. 875 // The current revisions of the assertion and its prerequisites will 876 // be recorded and only higher revisions will then resolve them, 877 // otherwise if ultimately unresolved they will be assumed to still be 878 // at their current ones. 879 func (p *Pool) AddToUpdate(toUpdate *Ref, group string) error { 880 if toUpdate.Type.SequenceForming() { 881 return fmt.Errorf("internal error: AddToUpdate requested for sequence-forming assertion") 882 } 883 if err := p.phase(poolPhaseAddUnresolved); err != nil { 884 return err 885 } 886 gnum, err := p.ensureGroup(group) 887 if err != nil { 888 return err 889 } 890 retrieve := func(ref *Ref) (Assertion, error) { 891 return ref.Resolve(p.groundDB.Find) 892 } 893 add := func(a Assertion) error { 894 return p.addUnresolved(a.At(), gnum) 895 } 896 f := NewFetcher(p.groundDB, retrieve, add) 897 if err := f.Fetch(toUpdate); err != nil { 898 return err 899 } 900 return nil 901 } 902 903 // AddSequenceToUpdate adds the assertion referenced by toUpdate and all its 904 // prerequisites to the Pool as unresolved and as required by the 905 // given group. It is assumed that the assertion is currently in the 906 // ground database of the Pool, otherwise this will error. 907 // The current revisions of the assertion and its prerequisites will 908 // be recorded and only higher revisions will then resolve them, 909 // otherwise if ultimately unresolved they will be assumed to still be 910 // at their current ones. If toUpdate is pinned, then it will be resolved 911 // to the highest revision with same sequence point (toUpdate.Sequence). 912 func (p *Pool) AddSequenceToUpdate(toUpdate *AtSequence, group string) error { 913 if err := p.phase(poolPhaseAddUnresolved); err != nil { 914 return err 915 } 916 if toUpdate.Sequence <= 0 { 917 return fmt.Errorf("internal error: sequence to update must have a sequence number set") 918 } 919 if p.unresolvedSequences[toUpdate.Unique()] != nil { 920 return fmt.Errorf("internal error: sequence %v is already being resolved", toUpdate.SequenceKey) 921 } 922 gnum, err := p.ensureGroup(group) 923 if err != nil { 924 return err 925 } 926 927 u := *toUpdate 928 retrieve := func(ref *Ref) (Assertion, error) { 929 return ref.Resolve(p.groundDB.Find) 930 } 931 add := func(a Assertion) error { 932 if !a.Type().SequenceForming() { 933 return p.addUnresolved(a.At(), gnum) 934 } 935 // sequence forming assertions are never predefined, so no check for it. 936 // final add corresponding to toUpdate itself. 937 u.Revision = a.Revision() 938 return p.addUnresolvedSeq(&u, gnum) 939 } 940 f := NewFetcher(p.groundDB, retrieve, add) 941 ref := &Ref{ 942 Type: toUpdate.Type, 943 PrimaryKey: append(u.SequenceKey, fmt.Sprintf("%d", u.Sequence)), 944 } 945 if err := f.Fetch(ref); err != nil { 946 return err 947 } 948 return nil 949 } 950 951 // CommitTo adds the assertions from groups without errors to the 952 // given assertion database. Commit errors can be retrieved via Err 953 // per group. An error is returned directly only if CommitTo is called 954 // with possible pending unresolved assertions. 955 func (p *Pool) CommitTo(db *Database) error { 956 if p.curPhase == poolPhaseAddUnresolved { 957 return fmt.Errorf("internal error: cannot commit Pool during add unresolved phase") 958 } 959 p.unresolvedBookkeeping() 960 961 retrieve := func(ref *Ref) (Assertion, error) { 962 a, err := p.bs.Get(ref.Type, ref.PrimaryKey, ref.Type.MaxSupportedFormat()) 963 if IsNotFound(err) { 964 // fallback to pre-existing assertions 965 a, err = ref.Resolve(db.Find) 966 } 967 if err != nil { 968 return nil, resolveError("cannot resolve prerequisite assertion: %s", ref, err) 969 } 970 return a, nil 971 } 972 save := func(a Assertion) error { 973 err := db.Add(a) 974 if IsUnaccceptedUpdate(err) { 975 // unsupported format case is handled before. 976 // be idempotent, db has already the same or 977 // newer. 978 return nil 979 } 980 return err 981 } 982 983 NextGroup: 984 for _, gRec := range p.groups { 985 if gRec.hasErr() { 986 // already in error, ignore 987 continue 988 } 989 // TODO: try to reuse fetcher 990 f := NewFetcher(db, retrieve, save) 991 for i := range gRec.resolved { 992 if err := f.Fetch(&gRec.resolved[i]); err != nil { 993 gRec.setErr(err) 994 continue NextGroup 995 } 996 } 997 } 998 999 return nil 1000 } 1001 1002 // ClearGroups clears the pool in terms of information associated with groups 1003 // while preserving information about already resolved or unchanged assertions. 1004 // It is useful for reusing a pool once the maximum of usable groups 1005 // that was set with NewPool has been exhausted. Group errors must be 1006 // queried before calling it otherwise they are lost. It is an error 1007 // to call it when there are still pending unresolved assertions in 1008 // the pool. 1009 func (p *Pool) ClearGroups() error { 1010 if len(p.unresolved) != 0 || len(p.prerequisites) != 0 { 1011 return fmt.Errorf("internal error: trying to clear groups of asserts.Pool with pending unresolved or prerequisites") 1012 } 1013 1014 p.numbering = make(map[string]uint16) 1015 // use a fresh Groupings as well so that max group tracking starts 1016 // from scratch. 1017 // NewGroupings cannot fail on a value accepted by it previously 1018 p.groupings, _ = internal.NewGroupings(p.groupings.N()) 1019 p.groups = make(map[uint16]*groupRec) 1020 p.curPhase = poolPhaseAdd 1021 return nil 1022 } 1023 1024 // Backstore returns the memory backstore of this pool. 1025 func (p *Pool) Backstore() Backstore { 1026 return p.bs 1027 }