summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonathan Reams <jbreams@mongodb.com>2016-09-07 14:18:23 -0400
committerJonathan Reams <jbreams@mongodb.com>2016-09-16 10:18:34 -0400
commite3b42fd990070f48c11b233cec0c198098d1a48f (patch)
tree464665d664b18fe709ccf5e9d039a424b9489a12 /src
parent7693fa59c4470db729d85af99fb9cc3b264fa8c8 (diff)
downloadmongo-e3b42fd990070f48c11b233cec0c198098d1a48f.tar.gz
SERVER-26002 Make sure javascript sleep isn't interrupted
Diffstat (limited to 'src')
-rw-r--r--src/mongo/scripting/SConscript2
-rw-r--r--src/mongo/scripting/deadline_monitor.cpp43
-rw-r--r--src/mongo/scripting/deadline_monitor.h24
-rw-r--r--src/mongo/scripting/mozjs/mongo.cpp21
-rw-r--r--src/mongo/scripting/mozjs/mongo.h3
-rw-r--r--src/mongo/scripting/utils.cpp3
-rw-r--r--src/mongo/shell/shell_utils_launcher.cpp7
-rw-r--r--src/mongo/stdx/thread.h34
-rw-r--r--src/mongo/util/net/sock.cpp13
-rw-r--r--src/mongo/util/net/sock.h2
10 files changed, 130 insertions, 22 deletions
diff --git a/src/mongo/scripting/SConscript b/src/mongo/scripting/SConscript
index 8c2604c76b6..18574fb2f16 100644
--- a/src/mongo/scripting/SConscript
+++ b/src/mongo/scripting/SConscript
@@ -10,6 +10,7 @@ Import([
env.Library(
target='scripting_common',
source=[
+ 'deadline_monitor.cpp',
'dbdirectclient_factory.cpp',
'engine.cpp',
'utils.cpp',
@@ -176,5 +177,6 @@ env.CppUnitTest(
'deadline_monitor_test.cpp',
],
LIBDEPS=[
+ 'scripting_common',
],
)
diff --git a/src/mongo/scripting/deadline_monitor.cpp b/src/mongo/scripting/deadline_monitor.cpp
new file mode 100644
index 00000000000..5eb0f52e5de
--- /dev/null
+++ b/src/mongo/scripting/deadline_monitor.cpp
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2016 MongoDB 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/scripting/deadline_monitor.h"
+
+#include "mongo/db/server_parameters.h"
+
+namespace mongo {
+
+MONGO_EXPORT_SERVER_PARAMETER(scriptingEngineInterruptIntervalMS, int, 1000);
+
+int getScriptingEngineInterruptInterval() {
+ return scriptingEngineInterruptIntervalMS.load();
+}
+
+} // namespace mongo
diff --git a/src/mongo/scripting/deadline_monitor.h b/src/mongo/scripting/deadline_monitor.h
index cd5c532c974..127bc81288d 100644
--- a/src/mongo/scripting/deadline_monitor.h
+++ b/src/mongo/scripting/deadline_monitor.h
@@ -30,6 +30,7 @@
#include <cstdint>
#include "mongo/base/disallow_copying.h"
+#include "mongo/platform/atomic_word.h"
#include "mongo/platform/unordered_map.h"
#include "mongo/stdx/condition_variable.h"
#include "mongo/stdx/mutex.h"
@@ -39,6 +40,9 @@
namespace mongo {
+// Returns the current interrupt interval from the setParameter value
+int getScriptingEngineInterruptInterval();
+
/**
* DeadlineMonitor
*
@@ -133,12 +137,21 @@ private:
while (!_inShutdown) {
// get the next interval to wait
const Date_t now = Date_t::now();
+ const auto interruptInterval = Milliseconds{getScriptingEngineInterruptInterval()};
+
+ if (now - lastInterruptCycle > interruptInterval) {
+ for (const auto& task : _tasks) {
+ if (task.second > now)
+ task.first->interrupt();
+ }
+ lastInterruptCycle = now;
+ }
// wait for a task to be added or a deadline to expire
if (_nearestDeadlineWallclock > now) {
if (_nearestDeadlineWallclock == Date_t::max() ||
- _nearestDeadlineWallclock - now > Seconds{1}) {
- _newDeadlineAvailable.wait_for(lk, Seconds{1}.toSystemDuration());
+ _nearestDeadlineWallclock - now > interruptInterval) {
+ _newDeadlineAvailable.wait_for(lk, interruptInterval.toSystemDuration());
} else {
_newDeadlineAvailable.wait_until(lk,
_nearestDeadlineWallclock.toSystemTimePoint());
@@ -162,13 +175,6 @@ private:
++i;
}
}
-
- if (now - lastInterruptCycle > Seconds{1}) {
- for (auto it : _tasks) {
- it.first->interrupt();
- }
- lastInterruptCycle = now;
- }
}
}
diff --git a/src/mongo/scripting/mozjs/mongo.cpp b/src/mongo/scripting/mozjs/mongo.cpp
index 8df2629c08f..2c887804203 100644
--- a/src/mongo/scripting/mozjs/mongo.cpp
+++ b/src/mongo/scripting/mozjs/mongo.cpp
@@ -46,12 +46,14 @@
#include "mongo/scripting/mozjs/valuewriter.h"
#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
#include "mongo/stdx/memory.h"
+#include "mongo/util/assert_util.h"
namespace mongo {
namespace mozjs {
const JSFunctionSpec MongoBase::methods[] = {
MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(auth, MongoLocalInfo, MongoExternalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(close, MongoExternalInfo),
MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(
copyDatabaseWithSCRAM, MongoLocalInfo, MongoExternalInfo),
MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(cursorFromId, MongoLocalInfo, MongoExternalInfo),
@@ -91,8 +93,12 @@ const JSFunctionSpec MongoExternalInfo::freeFunctions[4] = {
namespace {
DBClientBase* getConnection(JS::CallArgs& args) {
- return static_cast<std::shared_ptr<DBClientBase>*>(JS_GetPrivate(args.thisv().toObjectOrNull()))
- ->get();
+ auto ret =
+ static_cast<std::shared_ptr<DBClientBase>*>(JS_GetPrivate(args.thisv().toObjectOrNull()))
+ ->get();
+ uassert(
+ ErrorCodes::BadValue, "Trying to get connection for closed Mongo object", ret != nullptr);
+ return ret;
}
void setCursor(JS::HandleObject target,
@@ -166,6 +172,17 @@ void MongoBase::finalize(JSFreeOp* fop, JSObject* obj) {
}
}
+void MongoBase::Functions::close::call(JSContext* cx, JS::CallArgs args) {
+ getConnection(args);
+
+ auto thisv = args.thisv().toObjectOrNull();
+ auto conn = static_cast<std::shared_ptr<DBClientBase>*>(JS_GetPrivate(thisv));
+
+ conn->reset();
+
+ args.rval().setUndefined();
+}
+
void MongoBase::Functions::runCommand::call(JSContext* cx, JS::CallArgs args) {
if (args.length() != 3)
uasserted(ErrorCodes::BadValue, "runCommand needs 3 args");
diff --git a/src/mongo/scripting/mozjs/mongo.h b/src/mongo/scripting/mozjs/mongo.h
index c3a82d10998..297b4907c6d 100644
--- a/src/mongo/scripting/mozjs/mongo.h
+++ b/src/mongo/scripting/mozjs/mongo.h
@@ -46,6 +46,7 @@ struct MongoBase : public BaseInfo {
struct Functions {
MONGO_DECLARE_JS_FUNCTION(auth);
MONGO_DECLARE_JS_FUNCTION(copyDatabaseWithSCRAM);
+ MONGO_DECLARE_JS_FUNCTION(close);
MONGO_DECLARE_JS_FUNCTION(cursorFromId);
MONGO_DECLARE_JS_FUNCTION(cursorHandleFromId);
MONGO_DECLARE_JS_FUNCTION(find);
@@ -63,7 +64,7 @@ struct MongoBase : public BaseInfo {
MONGO_DECLARE_JS_FUNCTION(getMaxWireVersion);
};
- static const JSFunctionSpec methods[18];
+ static const JSFunctionSpec methods[19];
static const char* const className;
static const unsigned classFlags = JSCLASS_HAS_PRIVATE;
diff --git a/src/mongo/scripting/utils.cpp b/src/mongo/scripting/utils.cpp
index 91bd67a5e0f..e9c2e4aa477 100644
--- a/src/mongo/scripting/utils.cpp
+++ b/src/mongo/scripting/utils.cpp
@@ -26,9 +26,12 @@
* then also delete it in the license file.
*/
+#include "mongo/platform/basic.h"
+
#include "mongo/bson/json.h"
#include "mongo/scripting/engine.h"
#include "mongo/util/md5.hpp"
+#include "mongo/util/time_support.h"
namespace mongo {
diff --git a/src/mongo/shell/shell_utils_launcher.cpp b/src/mongo/shell/shell_utils_launcher.cpp
index d69bdc6452b..b95e814777e 100644
--- a/src/mongo/shell/shell_utils_launcher.cpp
+++ b/src/mongo/shell/shell_utils_launcher.cpp
@@ -656,7 +656,10 @@ bool wait_for_pid(ProcessId pid, bool block = true, int* exit_code = NULL) {
}
#else
int tmp;
- bool ret = (pid.toNative() == waitpid(pid.toNative(), &tmp, (block ? 0 : WNOHANG)));
+ int ret;
+ do {
+ ret = waitpid(pid.toNative(), &tmp, (block ? 0 : WNOHANG));
+ } while (ret == -1 && errno == EINTR);
if (ret && exit_code) {
if (WIFEXITED(tmp)) {
*exit_code = WEXITSTATUS(tmp);
@@ -666,7 +669,7 @@ bool wait_for_pid(ProcessId pid, bool block = true, int* exit_code = NULL) {
MONGO_UNREACHABLE;
}
}
- return ret;
+ return ret == pid.toNative();
#endif
}
diff --git a/src/mongo/stdx/thread.h b/src/mongo/stdx/thread.h
index d81dc1bf315..c85c654445a 100644
--- a/src/mongo/stdx/thread.h
+++ b/src/mongo/stdx/thread.h
@@ -28,6 +28,8 @@
#pragma once
+#include <chrono>
+#include <ctime>
#include <exception>
#include <thread>
#include <type_traits>
@@ -105,7 +107,37 @@ inline void swap(thread& lhs, thread& rhs) noexcept {
lhs.swap(rhs);
}
-namespace this_thread = ::std::this_thread; // NOLINT
+namespace this_thread {
+using std::this_thread::get_id;
+using std::this_thread::yield;
+
+#ifdef _WIN32
+using std::this_thread::sleep_for;
+using std::this_thread::sleep_until;
+#else
+template <class Rep, class Period>
+inline void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration) {
+ if (sleep_duration <= sleep_duration.zero())
+ return;
+
+ const auto seconds = std::chrono::duration_cast<std::chrono::seconds>(sleep_duration);
+ const auto nanoseconds =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(sleep_duration - seconds);
+ struct timespec sleepVal = {static_cast<std::time_t>(seconds.count()),
+ static_cast<long>(nanoseconds.count())};
+ struct timespec remainVal;
+ while (nanosleep(&sleepVal, &remainVal) == -1 && errno == EINTR) {
+ sleepVal = remainVal;
+ }
+}
+
+template <class Clock, class Duration>
+void sleep_until(const std::chrono::time_point<Clock, Duration>& sleep_time) {
+ const auto now = Clock::now();
+ sleep_for(sleep_time - now);
+}
+#endif
+} // namespace this_thread
} // namespace stdx
} // namespace mongo
diff --git a/src/mongo/util/net/sock.cpp b/src/mongo/util/net/sock.cpp
index 9e172335663..8202c28d2fa 100644
--- a/src/mongo/util/net/sock.cpp
+++ b/src/mongo/util/net/sock.cpp
@@ -433,9 +433,7 @@ int Socket::_send(const char* data, int len, const char* context) {
}
#endif
int ret = ::send(_fd, data, len, portSendFlags);
- if (ret < 0) {
- handleSendError(ret, context);
- }
+
return ret;
}
@@ -449,11 +447,15 @@ void Socket::send(const char* data, int len, const char* context) {
#else
errno = ENETUNREACH;
#endif
- handleSendError(ret, context);
} else {
ret = _send(data, len, context);
}
+ if (ret < 0) {
+ handleSendError(ret, context);
+ continue;
+ }
+
_bytesOut += ret;
fassert(16507, ret <= len);
@@ -594,7 +596,7 @@ void Socket::handleSendError(int ret, const char* context) {
#endif
LOG(_logLevel) << "Socket " << context << " send() timed out " << remoteString();
throw SocketException(SocketException::SEND_TIMEOUT, remoteString());
- } else {
+ } else if (mongo_errno != EINTR) {
LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription(mongo_errno)
<< ' ' << remoteString();
throw SocketException(SocketException::SEND_ERROR, remoteString());
@@ -614,7 +616,6 @@ void Socket::handleRecvError(int ret, int len) {
int e = errno;
#if defined(EINTR)
if (e == EINTR) {
- LOG(_logLevel) << "EINTR returned from recv(), retrying";
return;
}
#endif
diff --git a/src/mongo/util/net/sock.h b/src/mongo/util/net/sock.h
index 3e4f0616ff9..44a83b6ef5b 100644
--- a/src/mongo/util/net/sock.h
+++ b/src/mongo/util/net/sock.h
@@ -232,7 +232,7 @@ public:
}
void handleRecvError(int ret, int len);
- MONGO_COMPILER_NORETURN void handleSendError(int ret, const char* context);
+ void handleSendError(int ret, const char* context);
std::string getSNIServerName() const;