// readSkews reads all clock data for the client's namespace. func (client *client) readSkews(collection mongo.Collection) (map[string]Skew, error) { // Read the clock document, recording the time before and after completion. readBefore := client.config.Clock.Now() var clockDoc clockDoc if err := collection.FindId(client.clockDocId()).One(&clockDoc); err != nil { return nil, errors.Trace(err) } readAfter := client.config.Clock.Now() if err := clockDoc.validate(); err != nil { return nil, errors.Annotatef(err, "corrupt clock document") } // Create skew entries for each known writer... skews, err := clockDoc.skews(readBefore, readAfter) if err != nil { return nil, errors.Trace(err) } // If a writer was previously known to us, and has not written since last // time we read, we should keep the original skew, which is more accurate. for writer, skew := range client.skews { if skews[writer].LastWrite == skew.LastWrite { skews[writer] = skew } } // ...and overwrite our own with a zero skew, which will DTRT (assuming // nobody's reusing client ids across machines with different clocks, // which *should* never happen). skews[client.config.Id] = Skew{} return skews, nil }
// exists returns whether the identified refcount doc exists. func (nsRefcounts_) exists(coll mongo.Collection, key string) (bool, error) { count, err := coll.FindId(key).Count() if err != nil { return false, errors.Trace(err) } return count != 0, nil }
// 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) } var ops []txn.Op for _, doc := range docs { if doc.URL.Revision >= curl.Revision { continue } ops = append(ops, txn.Op{ C: charmsC, Id: doc.DocID, Assert: stillPlaceholder, Remove: true, }) } return ops, 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 }
// getEntitiesWithStatuses returns the ids for all entities that // have history entries func getEntitiesWithStatuses(coll mongo.Collection) ([]string, error) { var globalKeys []string err := coll.Find(nil).Distinct("globalkey", &globalKeys) if err != nil { return nil, errors.Trace(err) } return globalKeys, nil }
// getEntitiesWithStatuses returns the ids for all entities that // have history entries func getEntitiesWithStatuses(coll mongo.Collection) ([]string, error) { var entityKeys []string err := coll.Find(nil).Distinct("entityid", &entityKeys) if err != nil { return nil, errors.Trace(err) } return entityKeys, 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 }
// 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 }
// read returns the value stored in the identified refcount doc. func (nsRefcounts_) read(coll mongo.Collection, key string) (int, error) { var doc refcountDoc if err := coll.FindId(key).One(&doc); err == mgo.ErrNotFound { return 0, errors.NotFoundf("refcount %q", key) } else if err != nil { return 0, errors.Trace(err) } return doc.RefCount, 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 }
// getOldestTimeToKeep returns the create time for the oldest // status log to be kept. func getOldestTimeToKeep(coll mongo.Collection, globalKey string, size int) (int64, bool, error) { result := historicalStatusDoc{} err := coll.Find(bson.D{{"globalkey", globalKey}}).Sort("-updated").Skip(size - 1).One(&result) if err == mgo.ErrNotFound { return -1, false, nil } if err != nil { return -1, false, errors.Trace(err) } return result.Updated, true, 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 }
// readEntries reads all lease data for the client's namespace. func (client *client) readEntries(collection mongo.Collection) (map[string]entry, error) { // Read all lease documents in the client's namespace. query := bson.M{ fieldType: typeLease, fieldNamespace: client.config.Namespace, } iter := collection.Find(query).Iter() // Extract valid entries for each one. entries := make(map[string]entry) var leaseDoc leaseDoc for iter.Next(&leaseDoc) { name, entry, err := leaseDoc.entry() if err != nil { return nil, errors.Annotatef(err, "corrupt lease document %q", leaseDoc.Id) } entries[name] = entry } if err := iter.Close(); err != nil { return nil, errors.Trace(err) } return entries, nil }
func newBinaryStorage(uuid string, metadataCollection mongo.Collection, txnRunner jujutxn.Runner) binarystorage.Storage { db := metadataCollection.Writeable().Underlying().Database rs := blobstore.NewGridFS(blobstoreDB, blobstoreDB, db.Session) managedStorage := blobstore.NewManagedStorage(db, rs) return binarystorageNew(uuid, managedStorage, metadataCollection, txnRunner) }
func isAliveWithSession(coll mongo.Collection, id interface{}) (bool, error) { n, err := coll.Find(bson.D{{"_id", id}, {"life", Alive}}).Count() return n == 1, err }
func isNotDeadWithSession(coll mongo.Collection, id interface{}) (bool, error) { n, err := coll.Find(bson.D{{"_id", id}, {"life", bson.D{{"$ne", Dead}}}}).Count() return n == 1, err }