func (bdc *cache) CandidateLocations(transport types.ImageTransport, scope types.BICTransportScope, primaryDigest digest.Digest, canSubstitute bool) []types.BICReplacementCandidate {
	res := []prioritize.CandidateWithTime{}
	var uncompressedDigestValue digest.Digest // = ""
	if err := bdc.view(func(tx *bolt.Tx) error {
		scopeBucket := tx.Bucket(knownLocationsBucket)
		if scopeBucket == nil {
			return nil
		}
		scopeBucket = scopeBucket.Bucket([]byte(transport.Name()))
		if scopeBucket == nil {
			return nil
		}
		scopeBucket = scopeBucket.Bucket([]byte(scope.Opaque))
		if scopeBucket == nil {
			return nil
		}

		res = bdc.appendReplacementCandidates(res, scopeBucket, primaryDigest)
		if canSubstitute {
			if uncompressedDigestValue = bdc.uncompressedDigest(tx, primaryDigest); uncompressedDigestValue != "" {
				b := tx.Bucket(digestByUncompressedBucket)
				if b != nil {
					b = b.Bucket([]byte(uncompressedDigestValue.String()))
					if b != nil {
						if err := b.ForEach(func(k, _ []byte) error {
							d, err := digest.Parse(string(k))
							if err != nil {
								return err
							}
							if d != primaryDigest && d != uncompressedDigestValue {
								res = bdc.appendReplacementCandidates(res, scopeBucket, d)
							}
							return nil
						}); err != nil {
							return err
						}
					}
				}
				if uncompressedDigestValue != primaryDigest {
					res = bdc.appendReplacementCandidates(res, scopeBucket, uncompressedDigestValue)
				}
			}
		}
		return nil
	}); err != nil { // Including os.IsNotExist(err)
		return []types.BICReplacementCandidate{} // FIXME? Log err (but throttle the log volume on repeated accesses)?
	}

	return prioritize.DestructivelyPrioritizeReplacementCandidates(res, primaryDigest, uncompressedDigestValue)
}
func (bdc *cache) CandidateLocations(transport types.ImageTransport, scope types.BICTransportScope, primaryDigest digest.Digest, canSubstitute bool) []types.BICReplacementCandidate {
	res := []prioritize.CandidateWithTime{}
	var uncompressedDigestValue digest.Digest // = ""
	if err := bdc.view(func(tx *bolt.Tx) error {
		scopeBucket := tx.Bucket(knownLocationsBucket)
		if scopeBucket == nil {
			return nil
		}
		scopeBucket = scopeBucket.Bucket([]byte(transport.Name()))
		if scopeBucket == nil {
			return nil
		}
		scopeBucket = scopeBucket.Bucket([]byte(scope.Opaque))
		if scopeBucket == nil {
			return nil
		}

		res = bdc.appendReplacementCandidates(res, scopeBucket, primaryDigest)
		if canSubstitute {
			if uncompressedDigestValue = bdc.uncompressedDigest(tx, primaryDigest); uncompressedDigestValue != "" {
				b := tx.Bucket(digestByUncompressedBucket)
				if b != nil {
					b = b.Bucket([]byte(uncompressedDigestValue.String()))
					if b != nil {
						if err := b.ForEach(func(k, _ []byte) error {
							d, err := digest.Parse(string(k))
							if err != nil {
								return err
							}
							if d != primaryDigest && d != uncompressedDigestValue {
								res = bdc.appendReplacementCandidates(res, scopeBucket, d)
							}
							return nil
						}); err != nil {
							return err
						}
					}
				}
				if uncompressedDigestValue != primaryDigest {
					res = bdc.appendReplacementCandidates(res, scopeBucket, uncompressedDigestValue)
				}
			}
		}
		return nil
	}); err != nil { // Including os.IsNotExist(err)
		return []types.BICReplacementCandidate{} // FIXME? Log err (but throttle the log volume on repeated accesses)?
	}

	return prioritize.DestructivelyPrioritizeReplacementCandidates(res, primaryDigest, uncompressedDigestValue)
}
// CandidateLocations returns a prioritized, limited, number of blobs and their locations that could possibly be reused
// within the specified (transport scope) (if they still exist, which is not guaranteed).
//
// If !canSubstitute, the returned cadidates will match the submitted digest exactly; if canSubstitute,
// data from previous RecordDigestUncompressedPair calls is used to also look up variants of the blob which have the same
// uncompressed digest.