github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/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  }