9
9
"gopkg.in/mgo.v2/txn"
12
func charmIncRefOps(st modelBackend, appName string, curl *charm.URL, canCreate bool) ([]txn.Op, error) {
12
var errCharmInUse = errors.New("charm in use")
14
// appCharmIncRefOps returns the operations necessary to record a reference
15
// to a charm and its per-application settings and storage constraints
16
// documents. It will fail if the charm is not Alive.
17
func appCharmIncRefOps(st modelBackend, appName string, curl *charm.URL, canCreate bool) ([]txn.Op, error) {
19
charms, closer := st.getCollection(charmsC)
22
// If we're migrating. charm document will not be present. But
23
// if we're not migrating, we need to check the charm is alive.
25
count, err := charms.FindId(curl.String()).Count()
27
return nil, errors.Annotate(err, "charm")
28
} else if count != 0 {
29
checkOp, err := nsLife.aliveOp(charms, curl.String())
31
return nil, errors.Annotate(err, "charm")
33
checkOps = []txn.Op{checkOp}
13
36
refcounts, closer := st.getCollection(refcountsC)
18
41
getIncRefOp = nsRefcounts.StrictIncRefOp
21
43
settingsKey := applicationSettingsKey(appName, curl)
22
settingsOp, err := getIncRefOp(refcounts, settingsKey)
24
return nil, errors.Trace(err)
44
settingsOp, err := getIncRefOp(refcounts, settingsKey, 1)
46
return nil, errors.Annotate(err, "settings reference")
48
storageConstraintsKey := applicationStorageConstraintsKey(appName, curl)
49
storageConstraintsOp, err := getIncRefOp(refcounts, storageConstraintsKey, 1)
51
return nil, errors.Annotate(err, "storage constraints reference")
26
53
charmKey := charmGlobalKey(curl)
27
charmOp, err := getIncRefOp(refcounts, charmKey)
54
charmOp, err := getIncRefOp(refcounts, charmKey, 1)
29
return nil, errors.Trace(err)
56
return nil, errors.Annotate(err, "charm reference")
59
return append(checkOps, settingsOp, storageConstraintsOp, charmOp), nil
38
func charmDecRefOps(st modelBackend, appName string, curl *charm.URL) ([]txn.Op, error) {
62
// appCharmDecRefOps returns the operations necessary to delete a
63
// reference to a charm and its per-application settings and storage
64
// constraints document. If no references to a given (app, charm) pair
65
// remain, the operations returned will also remove the settings and
66
// storage constraints documents for that pair, and schedule a cleanup
67
// to see if the charm itself is now unreferenced and can be tidied
69
func appCharmDecRefOps(st modelBackend, appName string, curl *charm.URL) ([]txn.Op, error) {
39
71
refcounts, closer := st.getCollection(refcountsC)
42
74
charmKey := charmGlobalKey(curl)
43
75
charmOp, err := nsRefcounts.AliveDecRefOp(refcounts, charmKey)
77
return nil, errors.Annotate(err, "charm reference")
45
80
settingsKey := applicationSettingsKey(appName, curl)
46
81
settingsOp, isFinal, err := nsRefcounts.DyingDecRefOp(refcounts, settingsKey)
48
return nil, errors.Trace(err)
51
ops := []txn.Op{settingsOp, charmOp}
83
return nil, errors.Annotatef(err, "settings reference %s", settingsKey)
86
storageConstraintsKey := applicationStorageConstraintsKey(appName, curl)
87
storageConstraintsOp, _, err := nsRefcounts.DyingDecRefOp(refcounts, storageConstraintsKey)
89
return nil, errors.Annotatef(err, "storage constraints reference %s", storageConstraintsKey)
92
ops := []txn.Op{settingsOp, storageConstraintsOp, charmOp}
53
ops = append(ops, txn.Op{
94
// XXX(fwereade): this construction, in common with ~all
95
// our refcount logic, is safe in parallel but not in
96
// serial. If this logic is used twice while composing a
97
// single transaction, the removal won't be triggered.
98
// see `Application.removeOps` for the workaround.
99
ops = append(ops, finalAppCharmRemoveOps(appName, curl)...)
104
// finalAppCharmRemoveOps returns operations to delete the settings
105
// and storage constraints documents and queue a charm cleanup.
106
func finalAppCharmRemoveOps(appName string, curl *charm.URL) []txn.Op {
107
settingsKey := applicationSettingsKey(appName, curl)
108
removeSettingsOp := txn.Op{
113
storageConstraintsKey := applicationStorageConstraintsKey(appName, curl)
114
removeStorageConstraintsOp := removeStorageConstraintsOp(storageConstraintsKey)
115
cleanupOp := newCleanupOp(cleanupCharm, curl.String())
116
return []txn.Op{removeSettingsOp, removeStorageConstraintsOp, cleanupOp}
119
// charmDestroyOps implements the logic of charm.Destroy.
120
func charmDestroyOps(st modelBackend, curl *charm.URL) ([]txn.Op, error) {
122
if curl.Schema != "local" {
123
// local charms keep a document around to prevent reuse
124
// of charm URLs, which several components believe to be
125
// unique keys (this is always true within a model).
127
// it's not so much that it's bad to delete store
128
// charms; but we don't have a way to reinstate them
129
// once purged, so we don't allow removal in the first
131
return nil, errors.New("cannot destroy non-local charms")
134
charms, closer := st.getCollection(charmsC)
137
charmKey := curl.String()
138
charmOp, err := nsLife.destroyOp(charms, charmKey, nil)
140
return nil, errors.Annotate(err, "charm")
143
refcounts, closer := st.getCollection(refcountsC)
146
refcountKey := charmGlobalKey(curl)
147
refcountOp, err := nsRefcounts.RemoveOp(refcounts, refcountKey, 0)
148
switch errors.Cause(err) {
150
case errRefcountChanged:
151
return nil, errCharmInUse
153
return nil, errors.Annotate(err, "charm reference")
156
return []txn.Op{charmOp, refcountOp}, nil
159
// charmRemoveOps implements the logic of charm.Remove.
160
func charmRemoveOps(st modelBackend, curl *charm.URL) ([]txn.Op, error) {
162
charms, closer := st.getCollection(charmsC)
165
// NOTE: we do *not* actually remove the charm document, to
166
// prevent its URL from being recycled, and breaking caches.
167
// The "remove" terminology refers to the client's view of the
168
// change (after which the charm really will be inaccessible).
169
charmKey := curl.String()
170
charmOp, err := nsLife.dieOp(charms, charmKey, nil)
172
return nil, errors.Annotate(err, "charm")
174
return []txn.Op{charmOp}, nil