13
13
* You should have received a copy of the GNU Affero General Public License
14
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* As a special exception, the copyright holders give permission to link the
17
* code of portions of this program with the OpenSSL library under certain
18
* conditions as described in each individual source file and distribute
19
* linked combinations including the program with the OpenSSL library. You
20
* must comply with the GNU Affero General Public License in all respects for
21
* all of the code used other than as permitted herein. If you modify file(s)
22
* with this exception, you may extend this exception to your version of the
23
* file(s), but you are not obligated to do so. If you do not wish to do so,
24
* delete this exception statement from your version. If you delete this
25
* exception statement from all source files in the program, then also delete
26
* it in the license file.
17
29
#include "mongo/db/kill_current_op.h"
21
33
#include "mongo/bson/util/atomic_int.h"
22
34
#include "mongo/db/client.h"
23
35
#include "mongo/db/curop.h"
36
#include "mongo/platform/random.h"
24
37
#include "mongo/scripting/engine.h"
38
#include "mongo/util/fail_point_service.h"
42
// Enabling the checkForInterruptFail fail point will start a game of random chance on the
43
// connection specified in the fail point data, generating an interrupt with a given fixed
44
// probability. Example invocation:
46
// {configureFailPoint: "checkForInterruptFail",
48
// data: {conn: 17, chance: .01, allowNested: true}}
50
// All three data fields must be specified. In the above example, all interrupt points on
51
// connection 17 will generate a kill on the current operation with probability p(.01),
52
// including interrupt points of nested operations. If "allowNested" is false, nested
53
// operations are not targeted. "chance" must be a double between 0 and 1, inclusive.
54
MONGO_FP_DECLARE(checkForInterruptFail);
28
56
void KillCurrentOp::interruptJs( AtomicUInt *op ) {
29
57
if ( !globalScriptEngine )
104
132
_condvar.notify_all();
107
void KillCurrentOp::checkForInterrupt( bool heedMutex ) {
137
// Global state for checkForInterrupt fail point.
138
PseudoRandom checkForInterruptPRNG(static_cast<int64_t>(time(NULL)));
140
// Helper function for checkForInterrupt fail point. Decides whether the operation currently
141
// being run by the given Client meet the (probabilistic) conditions for interruption as
142
// specified in the fail point info.
143
bool opShouldFail(const Client& c, const BSONObj& failPointInfo) {
144
// Only target the client with the specified connection number.
145
if (c.getConnectionId() != failPointInfo["conn"].safeNumberLong()) {
149
// Only target nested operations if requested.
150
if (!failPointInfo["allowNested"].trueValue() && c.curop()->parent() != NULL) {
154
// Return true with (approx) probability p = "chance". Recall: 0 <= chance <= 1.
155
double next = static_cast<double>(std::abs(checkForInterruptPRNG.nextInt64()));
157
std::numeric_limits<int64_t>::max() * failPointInfo["chance"].numberDouble();
158
if (next > upperBound) {
166
void KillCurrentOp::checkForInterrupt(bool heedMutex) {
108
167
Client& c = cc();
109
if ( heedMutex && Lock::somethingWriteLocked() && c.hasWrittenThisPass() )
169
if (heedMutex && Lock::somethingWriteLocked() && c.hasWrittenSinceCheckpoint()) {
112
uasserted(11600,"interrupted at shutdown");
113
if( c.curop()->killPending() ) {
115
uasserted(11601,"operation was interrupted");
173
uassert(ErrorCodes::InterruptedAtShutdown, "interrupted at shutdown", !_globalKill);
175
if (c.curop()->maxTimeHasExpired()) {
178
uasserted(ErrorCodes::ExceededTimeLimit, "operation exceeded time limit");
180
MONGO_FAIL_POINT_BLOCK(checkForInterruptFail, scopedFailPoint) {
181
if (opShouldFail(c, scopedFailPoint.getData())) {
182
log() << "set pending kill on " << (c.curop()->parent() ? "nested" : "top-level")
183
<< " op " << c.curop()->opNum().get() << ", for checkForInterruptFail";
187
if (c.curop()->killPending()) {
189
uasserted(11601, "operation was interrupted");
119
193
const char * KillCurrentOp::checkForInterruptNoAssert() {
120
194
Client& c = cc();
122
197
return "interrupted at shutdown";
123
if( c.curop()->killPending() )
199
if (c.curop()->maxTimeHasExpired()) {
201
return "exceeded time limit";
203
MONGO_FAIL_POINT_BLOCK(checkForInterruptFail, scopedFailPoint) {
204
if (opShouldFail(c, scopedFailPoint.getData())) {
205
log() << "set pending kill on " << (c.curop()->parent() ? "nested" : "top-level")
206
<< " op " << c.curop()->opNum().get() << ", for checkForInterruptFail";
210
if (c.curop()->killPending()) {
124
211
return "interrupted";