summaryrefslogtreecommitdiff
path: root/src/mongo/util/fail_point.cpp
diff options
context:
space:
mode:
authorRandolph Tan <randolph@10gen.com>2012-09-19 16:32:42 -0400
committerRandolph Tan <randolph@10gen.com>2012-10-04 12:04:53 -0400
commit997b1c3718b378e4096fb708e054644690b38c4d (patch)
treef171e24b3fed6c9cd0c1092b045532911365064f /src/mongo/util/fail_point.cpp
parent13535ff54d3db78de6fc06a137915f25506dd7bc (diff)
downloadmongo-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.cpp130
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();
+ }
+ }
+}