Compare commits

...

9 Commits

Author SHA1 Message Date
Ramon Fernandez
8dd41ae580 BUMP 3.0.0-rc6 2015-01-23 14:05:15 -05:00
Matt Kangas
d1aaa562f7 Import wiredtiger-wiredtiger-mongodb-2.8-rc5-180-g724d863.tar.gz from wiredtiger branch mongodb-2.8
(cherry picked from commit 0637e0ab83)
2015-01-23 14:03:28 -05:00
Eric Milkie
6fa02fef66 SERVER-17003 Check command status for WriteConflictException on secondaries and rethrow
(cherry picked from commit d96cd52a48)
2015-01-23 12:01:09 -05:00
Eric Milkie
f8267b2689 SERVER-17005 skip clearing tmp collection if it fails with WriteConflictException
(cherry picked from commit 6741cd5a46)
2015-01-23 12:00:29 -05:00
Kaloian Manassiev
797afb0ef9 SERVER-16992 Add failpoints to throw WT_ROLLBACK
For the WT record store and indexes.

Also reverts commit 8e54b64c1d.

(cherry picked from commit 4f510d62cb)
2015-01-23 11:56:19 -05:00
Mathias Stearn
78e1975857 SERVER-17003 Add WriteConflict retry logic to applyOps command
(cherry picked from commit 8e2052f745)
2015-01-23 11:45:04 -05:00
Mathias Stearn
43e58e67ca SERVER-17003 Add WriteConflict retry logic to IndexBuilder
(cherry picked from commit c3413d543c)
2015-01-23 11:44:57 -05:00
mike o'brien
ef668908b1 fix multiversion test to handle 2.8->3.0 binversion change
Closes #913

Signed-off-by: Benety Goh <benety@mongodb.com>
(cherry picked from commit 616bc35c6f)
2015-01-23 11:44:48 -05:00
Benety Goh
1e4e8de086 SERVER-17016 fixed db.collection.ensureIndex() for devnull storage engine
(cherry picked from commit 54edc490c9)
2015-01-23 11:44:06 -05:00
13 changed files with 262 additions and 142 deletions

View File

@@ -3,7 +3,7 @@
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = MongoDB
PROJECT_NUMBER = 2.8.0-rc6-pre-
PROJECT_NUMBER = 3.0.0-rc6
OUTPUT_DIRECTORY = docs/doxygen
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English

View File

@@ -46,6 +46,7 @@
#include "mongo/db/catalog/collection_options.h"
#include "mongo/db/catalog/database_catalog_entry.h"
#include "mongo/db/catalog/database_holder.h"
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/dbhelpers.h"
#include "mongo/db/global_environment_experiment.h"
#include "mongo/db/global_environment_d.h"
@@ -262,20 +263,26 @@ namespace mongo {
CollectionOptions options = coll->getCollectionOptions( txn );
if ( !options.temp )
continue;
try {
WriteUnitOfWork wunit(txn);
Status status = dropCollection( txn, ns );
if ( !status.isOK() ) {
warning() << "could not drop temp collection '" << ns << "': " << status;
continue;
}
WriteUnitOfWork wunit(txn);
Status status = dropCollection( txn, ns );
if ( !status.isOK() ) {
warning() << "could not drop temp collection '" << ns << "': " << status;
continue;
string cmdNs = _name + ".$cmd";
repl::logOp( txn,
"c",
cmdNs.c_str(),
BSON( "drop" << nsToCollectionSubstring( ns ) ) );
wunit.commit();
}
catch (const WriteConflictException& exp) {
warning() << "could not drop temp collection '" << ns << "' due to "
"WriteConflictException";
txn->recoveryUnit()->commitAndRestart();
}
string cmdNs = _name + ".$cmd";
repl::logOp( txn,
"c",
cmdNs.c_str(),
BSON( "drop" << nsToCollectionSubstring( ns ) ) );
wunit.commit();
}
}

View File

@@ -26,6 +26,10 @@
* it in the license file.
*/
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand
#include "mongo/platform/basic.h"
#include <sstream>
#include <string>
#include <vector>
@@ -38,11 +42,13 @@
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
#include "mongo/db/commands/dbhash.h"
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/matcher/matcher.h"
#include "mongo/db/operation_context_impl.h"
#include "mongo/db/repl/oplog.h"
#include "mongo/util/log.h"
namespace mongo {
@@ -149,11 +155,26 @@ namespace mongo {
};
Client::Context ctx(txn, ns);
bool failed = repl::applyOperation_inlock(txn,
ctx.db(),
temp,
false,
alwaysUpsert);
bool failed;
while (true) {
try {
// We assume that in the WriteConflict retry case, either the op rolls back
// any changes it makes or is otherwise safe to rerun.
failed = repl::applyOperation_inlock(txn,
ctx.db(),
temp,
false,
alwaysUpsert);
break;
}
catch (const WriteConflictException& wce) {
LOG(2) << "WriteConflictException in applyOps command, retrying.";
txn->recoveryUnit()->commitAndRestart();
continue;
}
}
ab.append(!failed);
if ( failed )
errors++;
@@ -184,13 +205,26 @@ namespace mongo {
}
}
const BSONObj cmdRewritten = cmdBuilder.done();
// We currently always logOp the command regardless of whether the individial ops
// succeeded and rely on any failures to also happen on secondaries. This isn't
// perfect, but it's what the command has always done and is part of its "correct"
// behavior.
WriteUnitOfWork wunit(txn);
repl::logOp(txn, "c", tempNS.c_str(), cmdBuilder.done());
wunit.commit();
while (true) {
try {
WriteUnitOfWork wunit(txn);
repl::logOp(txn, "c", tempNS.c_str(), cmdRewritten);
wunit.commit();
break;
}
catch (const WriteConflictException& wce) {
LOG(2) <<
"WriteConflictException while logging applyOps command, retrying.";
txn->recoveryUnit()->commitAndRestart();
continue;
}
}
}
if (errors != 0) {

View File

@@ -38,6 +38,7 @@
#include "mongo/db/catalog/database.h"
#include "mongo/db/catalog/database_holder.h"
#include "mongo/db/catalog/index_create.h"
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/operation_context_impl.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/log.h"
@@ -125,72 +126,100 @@ namespace {
Collection* c = db->getCollection( ns.ns() );
if ( !c ) {
WriteUnitOfWork wunit(txn);
c = db->getOrCreateCollection( txn, ns.ns() );
verify(c);
wunit.commit();
while (true) {
try {
WriteUnitOfWork wunit(txn);
c = db->getOrCreateCollection( txn, ns.ns() );
verify(c);
wunit.commit();
break;
}
catch (const WriteConflictException& wce) {
LOG(2) << "WriteConflictException while creating collection in IndexBuilder"
<< ", retrying.";
txn->recoveryUnit()->commitAndRestart();
continue;
}
}
}
// Show which index we're building in the curop display.
txn->getCurOp()->setQuery(_index);
MultiIndexBlock indexer(txn, c);
indexer.allowInterruption();
bool haveSetBgIndexStarting = false;
while (true) {
Status status = Status::OK();
try {
MultiIndexBlock indexer(txn, c);
indexer.allowInterruption();
if (allowBackgroundBuilding)
indexer.allowBackgroundBuilding();
if (allowBackgroundBuilding)
indexer.allowBackgroundBuilding();
Status status = Status::OK();
IndexDescriptor* descriptor(NULL);
try {
status = indexer.init(_index);
if ( status.code() == ErrorCodes::IndexAlreadyExists ) {
if (allowBackgroundBuilding) {
// Must set this in case anyone is waiting for this build.
_setBgIndexStarting();
IndexDescriptor* descriptor(NULL);
try {
status = indexer.init(_index);
if ( status.code() == ErrorCodes::IndexAlreadyExists ) {
if (allowBackgroundBuilding) {
// Must set this in case anyone is waiting for this build.
_setBgIndexStarting();
}
return Status::OK();
}
if (status.isOK()) {
if (allowBackgroundBuilding) {
descriptor = indexer.registerIndexBuild();
if (!haveSetBgIndexStarting) {
_setBgIndexStarting();
haveSetBgIndexStarting = true;
}
invariant(dbLock);
dbLock->relockWithMode(MODE_IX);
}
Lock::CollectionLock colLock(txn->lockState(), ns.ns(), MODE_IX);
status = indexer.insertAllDocumentsInCollection();
}
if (status.isOK()) {
if (allowBackgroundBuilding) {
dbLock->relockWithMode(MODE_X);
}
WriteUnitOfWork wunit(txn);
indexer.commit();
wunit.commit();
}
}
return Status::OK();
}
if (status.isOK()) {
if (allowBackgroundBuilding) {
descriptor = indexer.registerIndexBuild();
_setBgIndexStarting();
invariant(dbLock);
dbLock->relockWithMode(MODE_IX);
catch (const DBException& e) {
status = e.toStatus();
}
Lock::CollectionLock colLock(txn->lockState(), ns.ns(), MODE_IX);
status = indexer.insertAllDocumentsInCollection();
}
if (status.isOK()) {
if (allowBackgroundBuilding) {
dbLock->relockWithMode(MODE_X);
Database* db = dbHolder().get(txn, ns.db());
fassert(28553, db);
fassert(28554, db->getCollection(ns.ns()));
indexer.unregisterIndexBuild(descriptor);
}
if (status.code() == ErrorCodes::InterruptedAtShutdown) {
// leave it as-if kill -9 happened. This will be handled on restart.
indexer.abortWithoutCleanup();
}
WriteUnitOfWork wunit(txn);
indexer.commit();
wunit.commit();
}
}
catch (const DBException& e) {
status = e.toStatus();
}
catch (const WriteConflictException& wce) {
status = wce.toStatus();
}
if (allowBackgroundBuilding) {
dbLock->relockWithMode(MODE_X);
Database* db = dbHolder().get(txn, ns.db());
fassert(28553, db);
fassert(28554, db->getCollection(ns.ns()));
indexer.unregisterIndexBuild(descriptor);
}
if (status.code() != ErrorCodes::WriteConflict)
return status;
if (status.code() == ErrorCodes::InterruptedAtShutdown) {
// leave it as-if kill -9 happened. This will be handled on restart.
indexer.abortWithoutCleanup();
}
return status;
LOG(2) << "WriteConflictException while creating index in IndexBuilder, retrying.";
txn->recoveryUnit()->commitAndRestart();
}
}
std::vector<BSONObj>

View File

@@ -737,16 +737,21 @@ namespace {
bool done = false;
while (!done) {
BufBuilder bb;
BSONObjBuilder ob;
BSONObjBuilder runCommandResult;
// Applying commands in repl is done under Global W-lock, so it is safe to not
// perform the current DB checks after reacquiring the lock.
invariant(txn->lockState()->isW());
_runCommands(txn, ns, o, bb, ob, true, 0);
_runCommands(txn, ns, o, bb, runCommandResult, true, 0);
// _runCommands takes care of adjusting opcounters for command counting.
Status status = Command::getStatusFromCommandResult(ob.done());
Status status = Command::getStatusFromCommandResult(runCommandResult.done());
switch (status.code()) {
case ErrorCodes::WriteConflict: {
// Need to throw this up to a higher level where it will be caught and the
// operation retried.
throw WriteConflictException();
}
case ErrorCodes::BackgroundOperationInProgressForDatabase: {
Lock::TempRelease release(txn->lockState());

View File

@@ -1,5 +1,3 @@
// devnull_kv_engine.cpp
/**
* Copyright (C) 2014 MongoDB Inc.
*
@@ -28,8 +26,11 @@
* it in the license file.
*/
#include "mongo/platform/basic.h"
#include "mongo/db/storage/devnull/devnull_kv_engine.h"
#include "mongo/base/disallow_copying.h"
#include "mongo/db/storage/in_memory/in_memory_record_store.h"
#include "mongo/db/storage/record_store.h"
#include "mongo/db/storage/sorted_data_interface.h"
@@ -175,12 +176,25 @@ namespace mongo {
BSONObj _dummy;
};
class DevNullSortedDataBuilderInterface : public SortedDataBuilderInterface {
MONGO_DISALLOW_COPYING(DevNullSortedDataBuilderInterface);
public:
DevNullSortedDataBuilderInterface() { }
virtual Status addKey(const BSONObj& key, const RecordId& loc) {
return Status::OK();
}
};
class DevNullSortedDataInterface : public SortedDataInterface {
public:
virtual ~DevNullSortedDataInterface() { }
virtual SortedDataBuilderInterface* getBulkBuilder(OperationContext* txn,
bool dupsAllowed) { return NULL; }
bool dupsAllowed) {
return new DevNullSortedDataBuilderInterface();
}
virtual Status insert(OperationContext* txn,
const BSONObj& key,

View File

@@ -46,8 +46,9 @@
#include "mongo/db/storage/wiredtiger/wiredtiger_session_cache.h"
#include "mongo/db/storage/wiredtiger/wiredtiger_util.h"
#include "mongo/db/storage_options.h"
#include "mongo/util/log.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/fail_point.h"
#include "mongo/util/log.h"
#include "mongo/util/mongoutils/str.h"
#if 0
@@ -330,7 +331,7 @@ namespace {
WT_CURSOR *c = curwrap.get();
if (!c)
return true;
int ret = c->next(c);
int ret = WT_OP_CHECK(c->next(c));
if (ret == WT_NOTFOUND)
return true;
invariantWTOK(ret);
@@ -349,9 +350,10 @@ namespace {
KeyString data( key, _ordering );
WiredTigerItem item( data.getBuffer(), data.getSize() );
c->set_key( c, item.Get() );
int ret = c->search(c);
if ( ret == WT_NOTFOUND )
int ret = WT_OP_CHECK(c->search(c));
if (ret == WT_NOTFOUND) {
return false;
}
invariantWTOK( ret );
// If the key exists, check if we already have this loc at this key. If so, we don't
@@ -449,7 +451,7 @@ namespace {
_cursor->set_value(_cursor, valueItem.Get());
invariantWTOK(_cursor->insert(_cursor));
invariantWTOK(WT_OP_CHECK(_cursor->insert(_cursor)));
invariantWTOK(_cursor->reset(_cursor));
return Status::OK();
@@ -543,7 +545,7 @@ namespace {
_cursor->set_key(_cursor, keyItem.Get());
_cursor->set_value(_cursor, valueItem.Get());
invariantWTOK(_cursor->insert(_cursor));
invariantWTOK(WT_OP_CHECK(_cursor->insert(_cursor)));
invariantWTOK(_cursor->reset(_cursor));
_records.clear();
@@ -677,7 +679,7 @@ namespace {
void advanceWTCursor() {
invalidateCache();
WT_CURSOR *c = _cursor.get();
int ret = _forward ? c->next(c) : c->prev(c);
int ret = WT_OP_CHECK(_forward ? c->next(c) : c->prev(c));
if ( ret == WT_NOTFOUND ) {
_eof = true;
return;
@@ -695,7 +697,7 @@ namespace {
const WiredTigerItem keyItem(_key.getBuffer(), _key.getSize());
c->set_key(c, keyItem.Get());
int ret = c->search_near(c, &cmp);
int ret = WT_OP_CHECK(c->search_near(c, &cmp));
if ( ret == WT_NOTFOUND ) {
_eof = true;
TRACE_CURSOR << "\t not found";
@@ -717,13 +719,13 @@ namespace {
if (_forward) {
// We need to be >=
if (cmp < 0) {
ret = c->next(c);
ret = WT_OP_CHECK(c->next(c));
}
}
else {
// We need to be <=
if (cmp > 0) {
ret = c->prev(c);
ret = WT_OP_CHECK(c->prev(c));
}
}
@@ -1003,7 +1005,7 @@ namespace {
WiredTigerItem valueItem(value.getBuffer(), value.getSize());
c->set_key( c, keyItem.Get() );
c->set_value( c, valueItem.Get() );
int ret = c->insert( c );
int ret = WT_OP_CHECK(c->insert(c));
if ( ret == WT_ROLLBACK && !dupsAllowed ) {
// if there is a conflict on a unique key, it means there is a dup key
@@ -1019,7 +1021,7 @@ namespace {
// we put them all in the "list"
// Note that we can't omit AllZeros when there are multiple locs for a value. When we remove
// down to a single value, it will be cleaned up.
ret = c->search(c);
ret = WT_OP_CHECK(c->search(c));
invariantWTOK( ret );
WT_ITEM old;
@@ -1069,7 +1071,7 @@ namespace {
if ( !dupsAllowed ) {
// nice and clear
int ret = c->remove(c);
int ret = WT_OP_CHECK(c->remove(c));
if (ret == WT_NOTFOUND) {
return;
}
@@ -1079,7 +1081,7 @@ namespace {
// dups are allowed, so we have to deal with a vector of RecordIds.
int ret = c->search(c);
int ret = WT_OP_CHECK(c->search(c));
if ( ret == WT_NOTFOUND )
return;
invariantWTOK( ret );
@@ -1099,7 +1101,7 @@ namespace {
if (records.empty() && !br.remaining()) {
// This is the common case: we are removing the only loc for this key.
// Remove the whole entry.
invariantWTOK(c->remove(c));
invariantWTOK(WT_OP_CHECK(c->remove(c)));
return;
}
@@ -1171,7 +1173,7 @@ namespace {
c->set_key(c, keyItem.Get());
c->set_value(c, valueItem.Get());
int ret = c->insert( c );
int ret = WT_OP_CHECK(c->insert(c));
if ( ret != WT_DUPLICATE_KEY )
return wtRCToStatus( ret );
@@ -1189,7 +1191,7 @@ namespace {
KeyString data( key, _ordering, loc );
WiredTigerItem item( data.getBuffer(), data.getSize() );
c->set_key(c, item.Get() );
int ret = c->remove(c);
int ret = WT_OP_CHECK(c->remove(c));
if (ret != WT_NOTFOUND) {
invariantWTOK(ret);
}

View File

@@ -51,7 +51,6 @@
#include "mongo/db/storage/wiredtiger/wiredtiger_util.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/fail_point.h"
#include "mongo/util/fail_point_service.h"
#include "mongo/util/log.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/scopeguard.h"
@@ -65,6 +64,7 @@ namespace mongo {
using std::string;
namespace {
static const int kMinimumRecordStoreVersion = 1;
static const int kCurrentRecordStoreVersion = 1; // New record stores use this by default.
static const int kMaximumRecordStoreVersion = 1;
@@ -80,17 +80,10 @@ namespace {
return (appMetadata.getValue().getIntField("oplogKeyExtractionVersion") == 1);
}
// Throws a WriteConflictException to ensure the calling code can handle it
MONGO_FP_DECLARE(wtWriteConflictException);
void checkWriteConflictExceptionFPEnabled() {
if (MONGO_FAIL_POINT(wtWriteConflictException)) {
throw WriteConflictException();
}
}
} // namespace
MONGO_FP_DECLARE(WTWriteConflictException);
const std::string kWiredTigerEngineName = "wiredTiger";
const long long WiredTigerRecordStore::kCollectionScanOnCreationThreshold = 10000;
@@ -316,14 +309,12 @@ namespace {
}
RecordData WiredTigerRecordStore::dataFor(OperationContext* txn, const RecordId& loc) const {
checkWriteConflictExceptionFPEnabled();
// ownership passes to the shared_array created below
WiredTigerCursor curwrap( _uri, _instanceId, true, txn);
WT_CURSOR *c = curwrap.get();
invariant( c );
c->set_key(c, _makeKey(loc));
int ret = c->search(c);
int ret = WT_OP_CHECK(c->search(c));
massert(28556, "Didn't find RecordId in WiredTigerRecordStore", ret != WT_NOTFOUND);
invariantWTOK(ret);
return _getData(curwrap);
@@ -331,13 +322,11 @@ namespace {
bool WiredTigerRecordStore::findRecord( OperationContext* txn,
const RecordId& loc, RecordData* out ) const {
checkWriteConflictExceptionFPEnabled();
WiredTigerCursor curwrap( _uri, _instanceId, true, txn);
WT_CURSOR *c = curwrap.get();
invariant( c );
c->set_key(c, _makeKey(loc));
int ret = c->search(c);
int ret = WT_OP_CHECK(c->search(c));
if (ret == WT_NOTFOUND) {
return false;
}
@@ -347,13 +336,11 @@ namespace {
}
void WiredTigerRecordStore::deleteRecord( OperationContext* txn, const RecordId& loc ) {
checkWriteConflictExceptionFPEnabled();
WiredTigerCursor cursor( _uri, _instanceId, true, txn );
cursor.assertInActiveTxn();
WT_CURSOR *c = cursor.get();
c->set_key(c, _makeKey(loc));
int ret = c->search(c);
int ret = WT_OP_CHECK(c->search(c));
invariantWTOK(ret);
WT_ITEM old_value;
@@ -362,7 +349,7 @@ namespace {
int old_length = old_value.size;
ret = c->remove(c);
ret = WT_OP_CHECK(c->remove(c));
invariantWTOK(ret);
_changeNumRecords(txn, -1);
@@ -438,9 +425,10 @@ namespace {
WT_CURSOR *c = curwrap.get();
RecordId newestOld;
int ret = 0;
while (( sizeSaved < sizeOverCap || docsRemoved < docsOverCap ) &&
docsRemoved < 1000 &&
(ret = c->next(c)) == 0 ) {
while ((sizeSaved < sizeOverCap || docsRemoved < docsOverCap) &&
(docsRemoved < 1000) &&
(ret = WT_OP_CHECK(c->next(c))) == 0) {
int64_t key;
ret = c->get_key(c, &key);
invariantWTOK(ret);
@@ -465,18 +453,21 @@ namespace {
}
}
if (ret != WT_NOTFOUND) invariantWTOK(ret);
if (ret != WT_NOTFOUND) {
invariantWTOK(ret);
}
if (docsRemoved > 0) {
// if we scanned to the end of the collection or past our insert, go back one
if ( ret == WT_NOTFOUND || newestOld >= justInserted ) {
ret = c->prev(c);
if (ret == WT_NOTFOUND || newestOld >= justInserted) {
ret = WT_OP_CHECK(c->prev(c));
}
invariantWTOK(ret);
WiredTigerCursor startWrap( _uri, _instanceId, true, txn);
WT_CURSOR* start = startWrap.get();
start->next(start);
ret = WT_OP_CHECK(start->next(start));
invariantWTOK(ret);
invariantWTOK(session->truncate(session, NULL, start, c, NULL));
_changeNumRecords(txn, -docsRemoved);
@@ -509,8 +500,6 @@ namespace {
const char* data,
int len,
bool enforceQuota ) {
checkWriteConflictExceptionFPEnabled();
if ( _isCapped && len > _cappedMaxSize ) {
return StatusWith<RecordId>( ErrorCodes::BadValue,
"object to insert exceeds cappedMaxSize" );
@@ -546,7 +535,7 @@ namespace {
c->set_key(c, _makeKey(loc));
WiredTigerItem value(data, len);
c->set_value(c, value.Get());
int ret = c->insert(c);
int ret = WT_OP_CHECK(c->insert(c));
if (ret) {
return StatusWith<RecordId>(wtRCToStatus(ret, "WiredTigerRecordStore::insertRecord"));
}
@@ -598,7 +587,7 @@ namespace {
WT_CURSOR *c = curwrap.get();
invariant( c );
c->set_key(c, _makeKey(loc));
int ret = c->search(c);
int ret = WT_OP_CHECK(c->search(c));
invariantWTOK(ret);
WT_ITEM old_value;
@@ -610,7 +599,7 @@ namespace {
c->set_key(c, _makeKey(loc));
WiredTigerItem value(data, len);
c->set_value(c, value.Get());
ret = c->insert(c);
ret = WT_OP_CHECK(c->insert(c));
invariantWTOK(ret);
_increaseDataSize(txn, len - old_length);
@@ -873,11 +862,8 @@ namespace {
OperationContext* txn,
const RecordId& startingPosition) const {
if (!_useOplogHack) {
if (!_useOplogHack)
return boost::none;
}
checkWriteConflictExceptionFPEnabled();
{
WiredTigerRecoveryUnit* wru = WiredTigerRecoveryUnit::get(txn);
@@ -889,7 +875,7 @@ namespace {
int cmp;
c->set_key(c, _makeKey(startingPosition));
int ret = c->search_near(c, &cmp);
int ret = WT_OP_CHECK(c->search_near(c, &cmp));
if (ret == 0 && cmp > 0) ret = c->prev(c); // landed one higher than startingPosition
if (ret == WT_NOTFOUND) return RecordId(); // nothing <= startingPosition
invariantWTOK(ret);

View File

@@ -41,6 +41,13 @@
#include "mongo/db/storage/record_store.h"
#include "mongo/db/storage/capped_callback.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/util/fail_point_service.h"
/**
* Either executes the specified operation and returns it's value or randomly throws a write
* conflict exception if the WTWriteConflictException failpoint is enabled.
*/
#define WT_OP_CHECK(x) (((MONGO_FAIL_POINT(WTWriteConflictException))) ? (WT_ROLLBACK) : (x))
namespace mongo {
@@ -282,4 +289,8 @@ namespace mongo {
WiredTigerSizeStorer* _sizeStorer; // not owned, can be NULL
int _sizeStorerCounter;
};
// WT failpoint to throw write conflict exceptions randomly
MONGO_FP_FORWARD_DECLARE(WTWriteConflictException);
}

View File

@@ -117,7 +117,9 @@ MongoRunner.binVersionSubs = [ new MongoRunner.VersionSub(/^latest$/, ""),
// Latest unstable and next stable are effectively the
// same release
new MongoRunner.VersionSub(/^2\.7(\..*){0,1}/, ""),
new MongoRunner.VersionSub(/^2\.8(\..*){0,1}/, "") ];
new MongoRunner.VersionSub(/^2\.8(\..*){0,1}/, ""),
new MongoRunner.VersionSub(/^3\.0(\..*){0,1}/, ""),
new MongoRunner.VersionSub(/^3\.1(\..*){0,1}/, "") ];
MongoRunner.getBinVersionFor = function(version) {

View File

@@ -26,28 +26,33 @@
* then also delete it in the license file.
*/
/**
* Should NOT be included by other header files. Include only in source files.
*/
#pragma once
#include "mongo/base/init.h"
#include "mongo/util/fail_point_registry.h"
namespace mongo {
/**
* @return the global fail point registry.
*/
FailPointRegistry* getGlobalFailPointRegistry();
/**
* Convenience macro for declaring a fail point. Must be used in global scope and
* never in a block with limited scope (ie, inside functions, loops, etc.)
* Convenience macro for declaring a fail point. Must be used in global scope and never in a
* block with limited scope (ie, inside functions, loops, etc.).
*
* NOTE: Never use in header files, only sources.
*/
#define MONGO_FP_DECLARE(fp) FailPoint fp; \
MONGO_INITIALIZER_GENERAL(fp, ("FailPointRegistry"), ("AllFailPointsRegistered")) \
(::mongo::InitializerContext* context) { \
return getGlobalFailPointRegistry()->addFailPoint(#fp, &fp); \
}
/**
* Convenience macro for defining a fail point in a header scope.
*/
#define MONGO_FP_FORWARD_DECLARE(fp) extern FailPoint fp;
}

View File

@@ -47,7 +47,7 @@ namespace mongo {
* 1.2.3-rc4-pre-
* If you really need to do something else you'll need to fix _versionArray()
*/
const char versionString[] = "2.8.0-rc6-pre-";
const char versionString[] = "3.0.0-rc6";
// See unit test for example outputs
BSONArray toVersionArray(const char* version){

View File

@@ -34,6 +34,31 @@ __wt_page_is_modified(WT_PAGE *page)
*/
#define WT_ALLOC_OVERHEAD 32U
/*
* Track a field in the cache. Use atomic CAS so that we can reliably avoid
* decrementing the cache below zero - since we use an unsigned number.
* Track if we would go below zero in a diagnostic build - something has gone
* wrong.
*/
#ifdef HAVE_DIAGNOSTIC
#define WT_CACHE_DECR(session, f, sz) do { \
uint64_t __val = f; \
uint64_t __sz = WT_MIN(__val, sz); \
if (__sz < sz) \
__wt_errx(session, "%s underflow: decrementing %" \
WT_SIZET_FMT, #f, sz); \
while (!WT_ATOMIC_CAS8(f, __val, __val - __sz)) \
__val = f, __sz = WT_MIN(__val, __sz); \
} while (0)
#else
#define WT_CACHE_DECR(session, f, sz) do { \
uint64_t __val = f; \
uint64_t __sz = WT_MIN(__val, sz); \
while (!WT_ATOMIC_CAS8(f, __val, __val - __sz)) \
__val = f, __sz = WT_MIN(__val, __sz); \
} while (0)
#endif
/*
* __wt_cache_page_inmem_incr --
* Increment a page's memory footprint in the cache.
@@ -66,11 +91,11 @@ __wt_cache_page_inmem_decr(WT_SESSION_IMPL *session, WT_PAGE *page, size_t size)
size += WT_ALLOC_OVERHEAD;
cache = S2C(session)->cache;
(void)WT_ATOMIC_SUB8(cache->bytes_inmem, size);
(void)WT_ATOMIC_SUB8(page->memory_footprint, size);
WT_CACHE_DECR(session, cache->bytes_inmem, size);
WT_CACHE_DECR(session, page->memory_footprint, size);
if (__wt_page_is_modified(page)) {
(void)WT_ATOMIC_SUB8(cache->bytes_dirty, size);
(void)WT_ATOMIC_SUB8(page->modify->bytes_dirty, size);
WT_CACHE_DECR(session, cache->bytes_dirty, size);
WT_CACHE_DECR(session, page->modify->bytes_dirty, size);
}
}