Skip to content

Commit d46a5c7

Browse files
committed
SERVER-17132: Added SnapshotId and Snapshotted and use them in query to make sure we use correct versions of docs
1 parent 87f1334 commit d46a5c7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+302
-217
lines changed

src/mongo/db/catalog/collection.cpp

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -152,32 +152,20 @@ namespace mongo {
152152
return _recordStore->getManyIterators(txn);
153153
}
154154

155-
int64_t Collection::countTableScan( OperationContext* txn, const MatchExpression* expression ) {
156-
scoped_ptr<RecordIterator> iterator( getIterator( txn,
157-
RecordId(),
158-
CollectionScanParams::FORWARD ) );
159-
int64_t count = 0;
160-
while ( !iterator->isEOF() ) {
161-
RecordId loc = iterator->getNext();
162-
BSONObj obj = docFor( txn, loc );
163-
if ( expression->matchesBSON( obj ) )
164-
count++;
165-
}
166-
167-
return count;
168-
}
169-
170-
BSONObj Collection::docFor(OperationContext* txn, const RecordId& loc) const {
171-
return _recordStore->dataFor( txn, loc ).releaseToBson();
155+
Snapshotted<BSONObj> Collection::docFor(OperationContext* txn, const RecordId& loc) const {
156+
return Snapshotted<BSONObj>(txn->recoveryUnit()->getSnapshotId(),
157+
_recordStore->dataFor( txn, loc ).releaseToBson());
172158
}
173159

174-
bool Collection::findDoc(OperationContext* txn, const RecordId& loc, BSONObj* out) const {
160+
bool Collection::findDoc(OperationContext* txn,
161+
const RecordId& loc,
162+
Snapshotted<BSONObj>* out) const {
175163
dassert(txn->lockState()->isCollectionLockedForMode(ns().toString(), MODE_IS));
176164

177165
RecordData rd;
178166
if ( !_recordStore->findRecord( txn, loc, &rd ) )
179167
return false;
180-
*out = rd.releaseToBson();
168+
*out = Snapshotted<BSONObj>(txn->recoveryUnit()->getSnapshotId(), rd.releaseToBson());
181169
return true;
182170
}
183171

@@ -200,7 +188,7 @@ namespace mongo {
200188
const BSONObj& docToInsert,
201189
bool enforceQuota ) {
202190

203-
uint64_t txnId = txn->recoveryUnit()->getMyTransactionCount();
191+
const SnapshotId sid = txn->recoveryUnit()->getSnapshotId();
204192

205193
if ( _indexCatalog.findIdIndex( txn ) ) {
206194
if ( docToInsert["_id"].eoo() ) {
@@ -211,7 +199,7 @@ namespace mongo {
211199
}
212200

213201
StatusWith<RecordId> res = _insertDocument( txn, docToInsert, enforceQuota );
214-
invariant( txnId == txn->recoveryUnit()->getMyTransactionCount() );
202+
invariant( sid == txn->recoveryUnit()->getSnapshotId() );
215203
return res;
216204
}
217205

@@ -294,21 +282,21 @@ namespace mongo {
294282
return;
295283
}
296284

297-
BSONObj doc = docFor( txn, loc );
285+
Snapshotted<BSONObj> doc = docFor(txn, loc);
298286

299-
if ( deletedId ) {
300-
BSONElement e = doc["_id"];
301-
if ( e.type() ) {
287+
if (deletedId) {
288+
BSONElement e = doc.value()["_id"];
289+
if (e.type()) {
302290
*deletedId = e.wrap();
303291
}
304292
}
305293

306294
/* check if any cursors point to us. if so, advance them. */
307295
_cursorManager.invalidateDocument(txn, loc, INVALIDATION_DELETION);
308296

309-
_indexCatalog.unindexRecord(txn, doc, loc, noWarn);
297+
_indexCatalog.unindexRecord(txn, doc.value(), loc, noWarn);
310298

311-
_recordStore->deleteRecord( txn, loc );
299+
_recordStore->deleteRecord(txn, loc);
312300

313301
_infoCache.notifyOfWriteOp();
314302
}
@@ -318,16 +306,17 @@ namespace mongo {
318306

319307
StatusWith<RecordId> Collection::updateDocument( OperationContext* txn,
320308
const RecordId& oldLocation,
321-
const BSONObj& objOld,
309+
const Snapshotted<BSONObj>& objOld,
322310
const BSONObj& objNew,
323311
bool enforceQuota,
324312
bool indexesAffected,
325313
OpDebug* debug ) {
326314
dassert(txn->lockState()->isCollectionLockedForMode(ns().toString(), MODE_IX));
315+
invariant(objOld.snapshotId() == txn->recoveryUnit()->getSnapshotId());
327316

328-
uint64_t txnId = txn->recoveryUnit()->getMyTransactionCount();
317+
SnapshotId sid = txn->recoveryUnit()->getSnapshotId();
329318

330-
BSONElement oldId = objOld["_id"];
319+
BSONElement oldId = objOld.value()["_id"];
331320
if ( !oldId.eoo() && ( oldId != objNew["_id"] ) )
332321
return StatusWith<RecordId>( ErrorCodes::InternalError,
333322
"in Collection::updateDocument _id mismatch",
@@ -350,8 +339,12 @@ namespace mongo {
350339
|| repl::getGlobalReplicationCoordinator()->shouldIgnoreUniqueIndex(descriptor);
351340
UpdateTicket* updateTicket = new UpdateTicket();
352341
updateTickets.mutableMap()[descriptor] = updateTicket;
353-
Status ret = iam->validateUpdate(
354-
txn, objOld, objNew, oldLocation, options, updateTicket );
342+
Status ret = iam->validateUpdate(txn,
343+
objOld.value(),
344+
objNew,
345+
oldLocation,
346+
options,
347+
updateTicket);
355348
if ( !ret.isOK() ) {
356349
return StatusWith<RecordId>( ret );
357350
}
@@ -389,7 +382,7 @@ namespace mongo {
389382
Status s = _indexCatalog.indexRecord(txn, objNew, newLocation.getValue());
390383
if (!s.isOK())
391384
return StatusWith<RecordId>(s);
392-
invariant( txnId == txn->recoveryUnit()->getMyTransactionCount() );
385+
invariant( sid == txn->recoveryUnit()->getSnapshotId() );
393386
return newLocation;
394387
}
395388

@@ -414,7 +407,7 @@ namespace mongo {
414407
}
415408
}
416409

417-
invariant( txnId == txn->recoveryUnit()->getMyTransactionCount() );
410+
invariant( sid == txn->recoveryUnit()->getSnapshotId() );
418411
return newLocation;
419412
}
420413

@@ -438,15 +431,16 @@ namespace mongo {
438431

439432
Status Collection::updateDocumentWithDamages( OperationContext* txn,
440433
const RecordId& loc,
441-
const RecordData& oldRec,
434+
const Snapshotted<RecordData>& oldRec,
442435
const char* damageSource,
443436
const mutablebson::DamageVector& damages ) {
444437
dassert(txn->lockState()->isCollectionLockedForMode(ns().toString(), MODE_IX));
438+
invariant(oldRec.snapshotId() == txn->recoveryUnit()->getSnapshotId());
445439

446440
// Broadcast the mutation so that query results stay correct.
447441
_cursorManager.invalidateDocument(txn, loc, INVALIDATION_MUTATION);
448442

449-
return _recordStore->updateWithDamages( txn, loc, oldRec, damageSource, damages );
443+
return _recordStore->updateWithDamages(txn, loc, oldRec.value(), damageSource, damages);
450444
}
451445

452446
bool Collection::_enforceQuota( bool userEnforeQuota ) const {

src/mongo/db/catalog/collection.h

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "mongo/db/record_id.h"
4343
#include "mongo/db/storage/capped_callback.h"
4444
#include "mongo/db/storage/record_store.h"
45+
#include "mongo/db/storage/snapshot.h"
4546
#include "mongo/platform/cstdint.h"
4647

4748
namespace mongo {
@@ -129,13 +130,13 @@ namespace mongo {
129130

130131
bool requiresIdIndex() const;
131132

132-
BSONObj docFor(OperationContext* txn, const RecordId& loc) const;
133+
Snapshotted<BSONObj> docFor(OperationContext* txn, const RecordId& loc) const;
133134

134135
/**
135136
* @param out - contents set to the right docs if exists, or nothing.
136137
* @return true iff loc exists
137138
*/
138-
bool findDoc(OperationContext* txn, const RecordId& loc, BSONObj* out) const;
139+
bool findDoc(OperationContext* txn, const RecordId& loc, Snapshotted<BSONObj>* out) const;
139140

140141
// ---- things that should move to a CollectionAccessMethod like thing
141142
/**
@@ -152,14 +153,6 @@ namespace mongo {
152153
*/
153154
std::vector<RecordIterator*> getManyIterators( OperationContext* txn ) const;
154155

155-
156-
/**
157-
* does a table scan to do a count
158-
* this should only be used at a very low level
159-
* does no yielding, indexes, etc...
160-
*/
161-
int64_t countTableScan( OperationContext* txn, const MatchExpression* expression );
162-
163156
void deleteDocument( OperationContext* txn,
164157
const RecordId& loc,
165158
bool cappedOK = false,
@@ -205,7 +198,7 @@ namespace mongo {
205198
*/
206199
StatusWith<RecordId> updateDocument( OperationContext* txn,
207200
const RecordId& oldLocation,
208-
const BSONObj& oldDoc,
201+
const Snapshotted<BSONObj>& oldDoc,
209202
const BSONObj& newDoc,
210203
bool enforceQuota,
211204
bool indexesAffected,
@@ -216,7 +209,7 @@ namespace mongo {
216209
*/
217210
Status updateDocumentWithDamages( OperationContext* txn,
218211
const RecordId& loc,
219-
const RecordData& oldRec,
212+
const Snapshotted<RecordData>& oldRec,
220213
const char* damageSource,
221214
const mutablebson::DamageVector& damages );
222215

src/mongo/db/commands/list_collections.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ namespace mongo {
146146
member->state = WorkingSetMember::OWNED_OBJ;
147147
member->keyData.clear();
148148
member->loc = RecordId();
149-
member->obj = maybe;
149+
member->obj = Snapshotted<BSONObj>(SnapshotId(), maybe);
150150
root->pushBack(*member);
151151
}
152152

src/mongo/db/commands/list_indexes.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ namespace mongo {
142142
member->state = WorkingSetMember::OWNED_OBJ;
143143
member->keyData.clear();
144144
member->loc = RecordId();
145-
member->obj = indexSpec;
145+
member->obj = Snapshotted<BSONObj>(SnapshotId(), indexSpec);
146146
root->pushBack(*member);
147147
}
148148

src/mongo/db/commands/rename_collection.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,11 +310,12 @@ namespace mongo {
310310
while (!sourceIt->isEOF()) {
311311
txn->checkForInterrupt();
312312

313-
const BSONObj obj = sourceColl->docFor(txn, sourceIt->getNext());
313+
const Snapshotted<BSONObj> obj = sourceColl->docFor(txn, sourceIt->getNext());
314314

315315
WriteUnitOfWork wunit(txn);
316316
// No logOp necessary because the entire renameCollection command is one logOp.
317-
Status status = targetColl->insertDocument(txn, obj, &indexer, true).getStatus();
317+
Status status =
318+
targetColl->insertDocument(txn, obj.value(), &indexer, true).getStatus();
318319
if (!status.isOK())
319320
return appendCommandStatus(result, status);
320321
wunit.commit();

src/mongo/db/dbhelpers.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ namespace mongo {
115115
RecordId loc = findOne( txn, collection, query, requireIndex );
116116
if ( loc.isNull() )
117117
return false;
118-
result = collection->docFor(txn, loc);
118+
result = collection->docFor(txn, loc).value();
119119
return true;
120120
}
121121

@@ -188,7 +188,7 @@ namespace mongo {
188188
RecordId loc = accessMethod->findSingle( txn, query["_id"].wrap() );
189189
if ( loc.isNull() )
190190
return false;
191-
result = collection->docFor( txn, loc );
191+
result = collection->docFor(txn, loc).value();
192192
return true;
193193
}
194194

src/mongo/db/exec/collection_scan.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ namespace mongo {
146146
WorkingSetID id = _workingSet->allocate();
147147
WorkingSetMember* member = _workingSet->get(id);
148148
member->loc = curr;
149-
member->obj = _iter->dataFor(member->loc).releaseToBson();
149+
member->obj = Snapshotted<BSONObj>(_txn->recoveryUnit()->getSnapshotId(),
150+
_iter->dataFor(member->loc).releaseToBson());
150151
member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
151152

152153
// Advance the iterator.

src/mongo/db/exec/delete.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ namespace mongo {
101101
// If the working set member is in the owned obj with loc state, then the document may
102102
// have already been deleted after-being force-fetched.
103103
if (WorkingSetMember::LOC_AND_OWNED_OBJ == member->state) {
104-
BSONObj deletedDoc;
105-
if (!_collection->findDoc(_txn, rloc, &deletedDoc)) {
104+
if (!_collection->findDoc(_txn, rloc, &member->obj)) {
106105
// Doc is already deleted. Nothing more to do.
107106
++_commonStats.needTime;
108107
return PlanStage::NEED_TIME;

src/mongo/db/exec/filter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ namespace mongo {
4848
// that it should do a fetch beforehand.
4949
BSONObj toBSON() const {
5050
invariant(_wsm->hasObj());
51-
return _wsm->obj;
51+
return _wsm->obj.value();
5252
}
5353

5454
virtual ElementIterator* allocateIterator(const ElementPath* path) const {
5555
// BSONElementIterator does some interesting things with arrays that I don't think
5656
// SimpleArrayElementIterator does.
5757
if (_wsm->hasObj()) {
58-
return new BSONElementIterator(path, _wsm->obj);
58+
return new BSONElementIterator(path, _wsm->obj.value());
5959
}
6060

6161
// NOTE: This (kind of) duplicates code in WorkingSetMember::getFieldDotted.

src/mongo/db/exec/geo_near.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ namespace mongo {
154154
// Extract all the geometries out of this document for the near query
155155
OwnedPointerVector<StoredGeometry> geometriesOwned;
156156
vector<StoredGeometry*>& geometries = geometriesOwned.mutableVector();
157-
extractGeometries(member->obj, nearParams.nearQuery->field, &geometries);
157+
extractGeometries(member->obj.value(), nearParams.nearQuery->field, &geometries);
158158

159159
// Compute the minimum distance of all the geometries in the document
160160
double minDistance = -1;

0 commit comments

Comments
 (0)