33
33
RefCount int `bson:"refcount"`
37
errRefcountChanged = errors.New("refcount changed")
36
40
// nsRefcounts exposes methods for safely manipulating reference count
37
41
// documents. (You can also manipulate them unsafely via the Just*
38
42
// methods that don't keep track of DB state.)
66
70
// CreateOrIncrefOp returns a txn.Op that creates a refcount document as
67
// configured with a value of 1; or increments any such refcount doc
71
// configured with a specified value; or increments any such refcount doc
68
72
// that already exists.
69
func (ns nsRefcounts_) CreateOrIncRefOp(coll mongo.Collection, key string) (txn.Op, error) {
73
func (ns nsRefcounts_) CreateOrIncRefOp(coll mongo.Collection, key string, n int) (txn.Op, error) {
70
74
if exists, err := ns.exists(coll, key); err != nil {
71
75
return txn.Op{}, errors.Trace(err)
72
76
} else if !exists {
73
return ns.JustCreateOp(coll.Name(), key, 1), nil
77
return ns.JustCreateOp(coll.Name(), key, n), nil
75
return ns.JustIncRefOp(coll.Name(), key), nil
79
return ns.JustIncRefOp(coll.Name(), key, n), nil
78
82
// StrictIncRefOp returns a txn.Op that increments the value of a
79
83
// refcount doc, or returns an error if it does not exist.
80
func (ns nsRefcounts_) StrictIncRefOp(coll mongo.Collection, key string) (txn.Op, error) {
84
func (ns nsRefcounts_) StrictIncRefOp(coll mongo.Collection, key string, n int) (txn.Op, error) {
81
85
if exists, err := ns.exists(coll, key); err != nil {
82
86
return txn.Op{}, errors.Trace(err)
83
87
} else if !exists {
84
return txn.Op{}, errors.New("refcount does not exist")
88
return txn.Op{}, errors.New("does not exist")
86
return ns.JustIncRefOp(coll.Name(), key), nil
90
return ns.JustIncRefOp(coll.Name(), key, n), nil
89
93
// AliveDecRefOp returns a txn.Op that decrements the value of a
123
127
return txn.Op{}, errors.Trace(err)
125
129
if refcount != value {
126
return txn.Op{}, errors.New("refcount changed")
130
return txn.Op{}, errRefcountChanged
128
132
return ns.JustRemoveOp(coll.Name(), key, value), nil
135
// CurrentOp returns the current reference count value, and a txn.Op that
136
// asserts that the refcount has that value, or an error. If the refcount
137
// doc does not exist, then the op will assert that the document does not
138
// exist instead, and no error is returned.
139
func (ns nsRefcounts_) CurrentOp(coll mongo.Collection, key string) (txn.Op, int, error) {
140
refcount, err := ns.read(coll, key)
141
if errors.IsNotFound(err) {
145
Assert: txn.DocMissing,
149
return txn.Op{}, -1, errors.Trace(err)
154
Assert: bson.D{{"refcount", refcount}},
131
158
// JustCreateOp returns a txn.Op that creates a refcount document as
132
159
// configured, *without* checking database state for sanity first.
133
160
// You should avoid using this method in most cases.
143
170
// JustIncRefOp returns a txn.Op that increments a refcount document by
144
// 1, as configured, *without* checking database state for sanity first.
145
// You should avoid using this method in most cases.
146
func (nsRefcounts_) JustIncRefOp(collName, key string) txn.Op {
171
// the specified amount, as configured, *without* checking database state
172
// for sanity first. You should avoid using this method in most cases.
173
func (nsRefcounts_) JustIncRefOp(collName, key string, n int) txn.Op {
150
177
Assert: txn.DocExists,
151
Update: bson.D{{"$inc", bson.D{{"refcount", 1}}}},
178
Update: bson.D{{"$inc", bson.D{{"refcount", n}}}},
194
221
func (nsRefcounts_) read(coll mongo.Collection, key string) (int, error) {
195
222
var doc refcountDoc
196
223
if err := coll.FindId(key).One(&doc); err == mgo.ErrNotFound {
197
return 0, errors.NotFoundf("refcount")
224
return 0, errors.NotFoundf("refcount %q", key)
198
225
} else if err != nil {
199
226
return 0, errors.Trace(err)