// deleteOldPlaceholderCharmsOps returns the txn ops required to delete all placeholder charm // records older than the specified charm URL. func deleteOldPlaceholderCharmsOps(st *State, charms mongo.Collection, curl *charm.URL) ([]txn.Op, error) { // Get a regex with the charm URL and no revision. noRevURL := curl.WithRevision(-1) curlRegex := "^" + regexp.QuoteMeta(st.docID(noRevURL.String())) var docs []charmDoc query := bson.D{{"_id", bson.D{{"$regex", curlRegex}}}, {"placeholder", true}} err := charms.Find(query).Select(bson.D{{"_id", 1}, {"url", 1}}).All(&docs) if err != nil { return nil, errors.Trace(err) } refcounts, closer := st.getCollection(refcountsC) defer closer() var ops []txn.Op for _, doc := range docs { if doc.URL.Revision >= curl.Revision { continue } key := charmGlobalKey(doc.URL) refOp, err := nsRefcounts.RemoveOp(refcounts, key, 0) if err != nil { return nil, errors.Trace(err) } ops = append(ops, refOp, txn.Op{ C: charms.Name(), Id: doc.DocID, Assert: stillPlaceholder, Remove: true, }) } return ops, nil }
// AliveDecRefOp returns a txn.Op that decrements the value of a // refcount doc, or an error if the doc does not exist or the count // would go below 0. func (ns nsRefcounts_) AliveDecRefOp(coll mongo.Collection, key string) (txn.Op, error) { if refcount, err := ns.read(coll, key); err != nil { return txn.Op{}, errors.Trace(err) } else if refcount < 1 { return txn.Op{}, errors.New("cannot decRef below 0") } return ns.justDecRefOp(coll.Name(), key, 0), nil }
// StrictIncRefOp returns a txn.Op that increments the value of a // refcount doc, or returns an error if it does not exist. func (ns nsRefcounts_) StrictIncRefOp(coll mongo.Collection, key string, n int) (txn.Op, error) { if exists, err := ns.exists(coll, key); err != nil { return txn.Op{}, errors.Trace(err) } else if !exists { return txn.Op{}, errors.New("does not exist") } return ns.JustIncRefOp(coll.Name(), key, n), nil }
// StrictCreateOp returns a txn.Op that creates a refcount document as // configured, or an error if the document already exists. func (ns nsRefcounts_) StrictCreateOp(coll mongo.Collection, key string, value int) (txn.Op, error) { if exists, err := ns.exists(coll, key); err != nil { return txn.Op{}, errors.Trace(err) } else if exists { return txn.Op{}, errors.New("refcount already exists") } return ns.JustCreateOp(coll.Name(), key, value), nil }
// LazyCreateOp returns a txn.Op that creates a refcount document; or // false if the document already exists. func (ns nsRefcounts_) LazyCreateOp(coll mongo.Collection, key string) (txn.Op, bool, error) { if exists, err := ns.exists(coll, key); err != nil { return txn.Op{}, false, errors.Trace(err) } else if exists { return txn.Op{}, false, nil } return ns.JustCreateOp(coll.Name(), key, 0), true, nil }
func newStateCollection(collection mongo.Collection, envUUID string) mongo.Collection { if multiEnvCollections.Contains(collection.Name()) { return &envStateCollection{ WriteCollection: collection.Writeable(), envUUID: envUUID, } } return collection }
// RemoveOp returns a txn.Op that removes a refcount doc so long as its // refcount is the supplied value, or an error. func (ns nsRefcounts_) RemoveOp(coll mongo.Collection, key string, value int) (txn.Op, error) { refcount, err := ns.read(coll, key) if err != nil { return txn.Op{}, errors.Trace(err) } if refcount != value { return txn.Op{}, errRefcountChanged } return ns.JustRemoveOp(coll.Name(), key, value), nil }
// DyingDecRefOp returns a txn.Op that decrements the value of a // refcount doc and deletes it if the count reaches 0; if the Op will // cause a delete, the bool result will be true. It will return an error // if the doc does not exist or the count would go below 0. func (ns nsRefcounts_) DyingDecRefOp(coll mongo.Collection, key string) (txn.Op, bool, error) { refcount, err := ns.read(coll, key) if err != nil { return txn.Op{}, false, errors.Trace(err) } if refcount < 1 { return txn.Op{}, false, errors.New("cannot decRef below 0") } else if refcount > 1 { return ns.justDecRefOp(coll.Name(), key, 1), false, nil } return ns.JustRemoveOp(coll.Name(), key, 1), true, nil }
// setStatusOp returns a txn.Op that updates the status of the // identified payload. If the payload doesn't exist, it returns // errAlreadyRemoved. func (nsPayloads_) setStatusOp(payloads mongo.Collection, docID string, status string) (txn.Op, error) { count, err := payloads.FindId(docID).Count() if err != nil { return txn.Op{}, errors.Trace(err) } else if count == 0 { return txn.Op{}, errAlreadyRemoved } return txn.Op{ C: payloads.Name(), Id: docID, Assert: txn.DocExists, Update: bson.D{{"$set", bson.D{{"state", status}}}}, }, nil }
// untrackOp returns a txn.Op that will unconditionally remove the // identified document. If the payload doesn't exist, it returns // errAlreadyRemoved. func (nsPayloads_) untrackOp(payloads mongo.Collection, docID string) (txn.Op, error) { count, err := payloads.FindId(docID).Count() if err != nil { return txn.Op{}, errors.Trace(err) } else if count == 0 { return txn.Op{}, errAlreadyRemoved } return txn.Op{ C: payloads.Name(), Id: docID, Assert: txn.DocExists, Remove: true, }, nil }
// CurrentOp returns the current reference count value, and a txn.Op that // asserts that the refcount has that value, or an error. If the refcount // doc does not exist, then the op will assert that the document does not // exist instead, and no error is returned. func (ns nsRefcounts_) CurrentOp(coll mongo.Collection, key string) (txn.Op, int, error) { refcount, err := ns.read(coll, key) if errors.IsNotFound(err) { return txn.Op{ C: coll.Name(), Id: key, Assert: txn.DocMissing, }, 0, nil } if err != nil { return txn.Op{}, -1, errors.Trace(err) } return txn.Op{ C: coll.Name(), Id: key, Assert: bson.D{{"refcount", refcount}}, }, refcount, nil }
// trackOp returns a txn.Op that will either insert or update the // supplied payload, and fail if the observed precondition changes. func (nsPayloads_) trackOp(payloads mongo.Collection, doc payloadDoc) (txn.Op, error) { docID := nsPayloads.docID(doc.UnitID, doc.Name) payloadOp := txn.Op{ C: payloads.Name(), Id: docID, } count, err := payloads.FindId(docID).Count() if err != nil { return txn.Op{}, errors.Trace(err) } else if count == 0 { payloadOp.Assert = txn.DocMissing payloadOp.Insert = doc } else { payloadOp.Assert = txn.DocExists payloadOp.Update = bson.D{{"$set", doc}} } return payloadOp, nil }