diff options
author | Randolph Tan <randolph@10gen.com> | 2012-09-19 16:32:42 -0400 |
---|---|---|
committer | Randolph Tan <randolph@10gen.com> | 2012-10-04 12:04:53 -0400 |
commit | 997b1c3718b378e4096fb708e054644690b38c4d (patch) | |
tree | f171e24b3fed6c9cd0c1092b045532911365064f /src/mongo/util/fail_point.cpp | |
parent | 13535ff54d3db78de6fc06a137915f25506dd7bc (diff) | |
download | mongo-997b1c3718b378e4096fb708e054644690b38c4d.tar.gz |
SERVER-5175 Need "failpoints" system to facilitate testing core server
Step 1: Implement and test the FailPoint class
Diffstat (limited to 'src/mongo/util/fail_point.cpp')
-rw-r--r-- | src/mongo/util/fail_point.cpp | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/src/mongo/util/fail_point.cpp b/src/mongo/util/fail_point.cpp new file mode 100644 index 00000000000..390fdb58bff --- /dev/null +++ b/src/mongo/util/fail_point.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2012 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "mongo/util/fail_point.h" + +#include "mongo/util/mongoutils/str.h" +#include "mongo/util/time_support.h" + +using mongoutils::str::stream; + +namespace mongo { + FailPoint::FailPoint(): + _fpInfo(0), + _mode(off), + _timesOrPeriod(0), + _modMutex("failPointMutex") { + } + + void FailPoint::shouldFailCloseBlock() { + _fpInfo.subtractAndFetch(1); + } + + void FailPoint::setMode(Mode mode, ValType val, const BSONObj& extra) { + /** + * Outline: + * + * 1. Deactivates fail point to enter write-only mode + * 2. Waits for all current readers of the fail point to finish + * 3. Sets the new mode. + */ + + scoped_lock scoped(_modMutex); + + // Step 1 + disableFailPoint(); + + // Step 2 + while (_fpInfo.load() != 0) { + sleepmillis(50); + } + + // Step 3 + uassert(16442, stream() << "mode not supported " << static_cast<int>(mode), + mode >= off && mode < numModes); + + _mode = mode; + _timesOrPeriod.store(val); + + _data = extra.copy(); + + if (_mode != off) { + _fpInfo.store(ACTIVE_BIT); + } + } + + const BSONObj& FailPoint::getData() const { + return _data; + } + + void FailPoint::disableFailPoint() { + // TODO: Better to replace with a bitwise AND, once available for AU32 + ValType currentVal = _fpInfo.load(); + ValType expectedCurrentVal; + ValType newVal; + + do { + expectedCurrentVal = currentVal; + newVal = expectedCurrentVal & REF_COUNTER_MASK; + currentVal = _fpInfo.compareAndSwap(expectedCurrentVal, newVal); + } while (expectedCurrentVal != currentVal); + } + + FailPoint::RetCode FailPoint::slowShouldFailOpenBlock() { + ValType localFpInfo = _fpInfo.addAndFetch(1); + + if ((localFpInfo & ACTIVE_BIT) == 0) { + return slowOff; + } + + switch (_mode) { + case alwaysOn: + return slowOn; + + case random: + // TODO: randomly determine if should be active or not + error() << "FailPoint Mode random is not yet supported." << endl; + fassertFailed(16443); + + case nTimes: + { + AtomicInt32::WordType newVal = _timesOrPeriod.subtractAndFetch(1); + + if (newVal <= 0) { + disableFailPoint(); + } + + return slowOn; + } + + default: + error() << "FailPoint Mode not supported: " << static_cast<int>(_mode) << endl; + fassertFailed(16444); + } + } + + ScopedFailPoint::ScopedFailPoint(FailPoint* failPoint): + _failPoint(failPoint), + _once(false), + _shouldClose(false) { + } + + ScopedFailPoint::~ScopedFailPoint() { + if (_shouldClose) { + _failPoint->shouldFailCloseBlock(); + } + } +} |