summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/core/list_collections1.js5
-rw-r--r--jstests/core/list_indexes.js5
-rw-r--r--src/mongo/scripting/SConscript1
-rw-r--r--src/mongo/scripting/mozjs/cursor_handle.cpp101
-rw-r--r--src/mongo/scripting/mozjs/cursor_handle.h72
-rw-r--r--src/mongo/scripting/mozjs/implscope.cpp2
-rw-r--r--src/mongo/scripting/mozjs/implscope.h6
-rw-r--r--src/mongo/scripting/mozjs/mongo.cpp29
-rw-r--r--src/mongo/scripting/mozjs/mongo.h3
-rw-r--r--src/mongo/shell/query.js10
10 files changed, 225 insertions, 9 deletions
diff --git a/jstests/core/list_collections1.js b/jstests/core/list_collections1.js
index 0a9a2d4c563..70ca144bfbd 100644
--- a/jstests/core/list_collections1.js
+++ b/jstests/core/list_collections1.js
@@ -214,10 +214,9 @@
//
// Test killCursors against a listCollections cursor.
- // TODO: re-enable after implementing SERVER-19570.
//
- /*assert.commandWorked(mydb.dropDatabase());
+ assert.commandWorked(mydb.dropDatabase());
assert.commandWorked(mydb.createCollection("foo"));
assert.commandWorked(mydb.createCollection("bar"));
assert.commandWorked(mydb.createCollection("baz"));
@@ -228,5 +227,5 @@
cursor = null;
gc(); // Shell will send a killCursors message when cleaning up underlying cursor.
cursor = new DBCommandCursor(mydb.getMongo(), res, 2);
- assert.throws(function() { cursor.hasNext(); });*/
+ assert.throws(function() { cursor.hasNext(); });
}());
diff --git a/jstests/core/list_indexes.js b/jstests/core/list_indexes.js
index 7f0a9e8a45c..db3f895bc20 100644
--- a/jstests/core/list_indexes.js
+++ b/jstests/core/list_indexes.js
@@ -151,10 +151,9 @@
//
// Test killCursors against a listCollections cursor.
- // TODO: re-enable after implementing SERVER-19570.
//
- /*coll.drop();
+ coll.drop();
assert.commandWorked(coll.getDB().createCollection(coll.getName()));
assert.commandWorked(coll.ensureIndex({a: 1}, {unique: true}));
assert.commandWorked(coll.ensureIndex({b: 1}, {unique: true}));
@@ -165,5 +164,5 @@
cursor = null;
gc(); // Shell will send a killCursors message when cleaning up underlying cursor.
cursor = new DBCommandCursor(coll.getDB().getMongo(), res, 2);
- assert.throws(function() { cursor.hasNext(); });*/
+ assert.throws(function() { cursor.hasNext(); });
}());
diff --git a/src/mongo/scripting/SConscript b/src/mongo/scripting/SConscript
index e81f2e4c705..25dd86201af 100644
--- a/src/mongo/scripting/SConscript
+++ b/src/mongo/scripting/SConscript
@@ -116,6 +116,7 @@ elif usemozjs:
'mozjs/bson.cpp',
'mozjs/countdownlatch.cpp',
'mozjs/cursor.cpp',
+ 'mozjs/cursor_handle.cpp',
'mozjs/dbcollection.cpp',
'mozjs/db.cpp',
'mozjs/dbpointer.cpp',
diff --git a/src/mongo/scripting/mozjs/cursor_handle.cpp b/src/mongo/scripting/mozjs/cursor_handle.cpp
new file mode 100644
index 00000000000..597ebe2ccd6
--- /dev/null
+++ b/src/mongo/scripting/mozjs/cursor_handle.cpp
@@ -0,0 +1,101 @@
+/**
+ * Copyright (C) 2015 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.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kQuery
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/scripting/mozjs/cursor_handle.h"
+
+#include "mongo/scripting/mozjs/implscope.h"
+#include "mongo/util/log.h"
+
+namespace mongo {
+namespace mozjs {
+
+const JSFunctionSpec CursorHandleInfo::methods[2] = {
+ MONGO_ATTACH_JS_FUNCTION(zeroCursorId), JS_FS_END,
+};
+
+const char* const CursorHandleInfo::className = "CursorHandle";
+
+namespace {
+
+long long* getCursorId(JSObject* thisv) {
+ CursorHandleInfo::CursorTracker* tracker =
+ static_cast<CursorHandleInfo::CursorTracker*>(JS_GetPrivate(thisv));
+ if (tracker) {
+ return &tracker->cursorId;
+ }
+
+ return nullptr;
+}
+
+long long* getCursorId(JS::CallArgs& args) {
+ return getCursorId(args.thisv().toObjectOrNull());
+}
+
+} // namespace
+
+void CursorHandleInfo::finalize(JSFreeOp* fop, JSObject* obj) {
+ auto cursorTracker = static_cast<CursorHandleInfo::CursorTracker*>(JS_GetPrivate(obj));
+ if (cursorTracker) {
+ const long long cursorId = cursorTracker->cursorId;
+ if (cursorId) {
+ try {
+ cursorTracker->client->killCursor(cursorId);
+ } catch (...) {
+ auto status = exceptionToStatus();
+
+ try {
+ LOG(0) << "Failed to kill cursor " << cursorId << " due to " << status;
+ } catch (...) {
+ // This is here in case logging fails.
+ }
+ }
+ }
+
+ delete cursorTracker;
+ }
+}
+
+void CursorHandleInfo::construct(JSContext* cx, JS::CallArgs args) {
+ auto scope = getScope(cx);
+
+ scope->getCursorHandleProto().newObject(args.rval());
+}
+
+void CursorHandleInfo::Functions::zeroCursorId(JSContext* cx, JS::CallArgs args) {
+ long long* cursorId = getCursorId(args);
+ if (cursorId) {
+ *cursorId = 0;
+ }
+}
+
+} // namespace mozjs
+} // namespace mongo
diff --git a/src/mongo/scripting/mozjs/cursor_handle.h b/src/mongo/scripting/mozjs/cursor_handle.h
new file mode 100644
index 00000000000..95f00a3d964
--- /dev/null
+++ b/src/mongo/scripting/mozjs/cursor_handle.h
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+#include "mongo/client/dbclientcursor.h"
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/scripting/mozjs/wraptype.h"
+
+namespace mongo {
+namespace mozjs {
+
+/**
+ * Wraps a DBClientCursor in javascript.
+ *
+ * Note that the install is private, so this class should only be constructible from C++. Current
+ * callers are all via the Mongo object.
+ */
+struct CursorHandleInfo : public BaseInfo {
+ static void construct(JSContext* cx, JS::CallArgs args);
+ static void finalize(JSFreeOp* fop, JSObject* obj);
+
+ struct Functions {
+ MONGO_DEFINE_JS_FUNCTION(zeroCursorId);
+ };
+
+ static const JSFunctionSpec methods[2];
+
+ static const char* const className;
+ static const unsigned classFlags = JSCLASS_HAS_PRIVATE;
+ static const InstallType installType = InstallType::Private;
+
+ /**
+ * We need this because the DBClientBase can go out of scope before all of its children (as
+ * in global shutdown). So we have to manage object lifetimes in C++ land.
+ */
+ struct CursorTracker {
+ CursorTracker(long long curId, std::shared_ptr<DBClientBase> client)
+ : client(std::move(client)), cursorId(curId) {}
+
+ std::shared_ptr<DBClientBase> client;
+ long long cursorId;
+ };
+};
+
+} // namespace mozjs
+} // namespace mongo
diff --git a/src/mongo/scripting/mozjs/implscope.cpp b/src/mongo/scripting/mozjs/implscope.cpp
index d594623a31e..398eb70c018 100644
--- a/src/mongo/scripting/mozjs/implscope.cpp
+++ b/src/mongo/scripting/mozjs/implscope.cpp
@@ -231,6 +231,7 @@ MozJSImplScope::MozJSImplScope(MozJSScriptEngine* engine)
_bsonProto(_context),
_countDownLatchProto(_context),
_cursorProto(_context),
+ _cursorHandleProto(_context),
_dbCollectionProto(_context),
_dbPointerProto(_context),
_dbQueryProto(_context),
@@ -672,6 +673,7 @@ void MozJSImplScope::installBSONTypes() {
void MozJSImplScope::installDBAccess() {
_cursorProto.install(_global);
+ _cursorHandleProto.install(_global);
_dbProto.install(_global);
_dbQueryProto.install(_global);
_dbCollectionProto.install(_global);
diff --git a/src/mongo/scripting/mozjs/implscope.h b/src/mongo/scripting/mozjs/implscope.h
index 30106006d43..b9a3e53c469 100644
--- a/src/mongo/scripting/mozjs/implscope.h
+++ b/src/mongo/scripting/mozjs/implscope.h
@@ -35,6 +35,7 @@
#include "mongo/scripting/mozjs/bson.h"
#include "mongo/scripting/mozjs/countdownlatch.h"
#include "mongo/scripting/mozjs/cursor.h"
+#include "mongo/scripting/mozjs/cursor_handle.h"
#include "mongo/scripting/mozjs/db.h"
#include "mongo/scripting/mozjs/dbcollection.h"
#include "mongo/scripting/mozjs/dbpointer.h"
@@ -159,6 +160,10 @@ public:
return _cursorProto;
}
+ WrapType<CursorHandleInfo>& getCursorHandleProto() {
+ return _cursorHandleProto;
+ }
+
WrapType<DBCollectionInfo>& getDbCollectionProto() {
return _dbCollectionProto;
}
@@ -306,6 +311,7 @@ private:
WrapType<BSONInfo> _bsonProto;
WrapType<CountDownLatchInfo> _countDownLatchProto;
WrapType<CursorInfo> _cursorProto;
+ WrapType<CursorHandleInfo> _cursorHandleProto;
WrapType<DBCollectionInfo> _dbCollectionProto;
WrapType<DBPointerInfo> _dbPointerProto;
WrapType<DBQueryInfo> _dbQueryProto;
diff --git a/src/mongo/scripting/mozjs/mongo.cpp b/src/mongo/scripting/mozjs/mongo.cpp
index ca8c5a35f93..2fcb59a7c35 100644
--- a/src/mongo/scripting/mozjs/mongo.cpp
+++ b/src/mongo/scripting/mozjs/mongo.cpp
@@ -49,6 +49,7 @@ const JSFunctionSpec MongoBase::methods[] = {
MONGO_ATTACH_JS_FUNCTION(auth),
MONGO_ATTACH_JS_FUNCTION(copyDatabaseWithSCRAM),
MONGO_ATTACH_JS_FUNCTION(cursorFromId),
+ MONGO_ATTACH_JS_FUNCTION(cursorHandleFromId),
MONGO_ATTACH_JS_FUNCTION(find),
MONGO_ATTACH_JS_FUNCTION(getClientRPCProtocols),
MONGO_ATTACH_JS_FUNCTION(getServerRPCProtocols),
@@ -83,6 +84,14 @@ void setCursor(JS::HandleObject target,
// Copy the client shared pointer to up the refcount
JS_SetPrivate(target, new CursorInfo::CursorHolder(std::move(cursor), *client));
}
+
+void setCursorHandle(JS::HandleObject target, long long cursorId, JS::CallArgs& args) {
+ auto client =
+ static_cast<std::shared_ptr<DBClientBase>*>(JS_GetPrivate(args.thisv().toObjectOrNull()));
+
+ // Copy the client shared pointer to up the refcount.
+ JS_SetPrivate(target, new CursorHandleInfo::CursorTracker(cursorId, *client));
+}
} // namespace
void MongoBase::finalize(JSFreeOp* fop, JSObject* obj) {
@@ -399,6 +408,26 @@ void MongoBase::Functions::cursorFromId(JSContext* cx, JS::CallArgs args) {
args.rval().setObjectOrNull(c);
}
+void MongoBase::Functions::cursorHandleFromId(JSContext* cx, JS::CallArgs args) {
+ auto scope = getScope(cx);
+
+ if (args.length() != 1) {
+ uasserted(ErrorCodes::BadValue, "cursorHandleFromId needs 1 arg");
+ }
+ if (!scope->getNumberLongProto().instanceOf(args.get(0))) {
+ uasserted(ErrorCodes::BadValue, "1st arg must be a NumberLong");
+ }
+
+ long long cursorId = NumberLongInfo::ToNumberLong(cx, args.get(0));
+
+ JS::RootedObject c(cx);
+ scope->getCursorHandleProto().newInstance(&c);
+
+ setCursorHandle(c, cursorId, args);
+
+ args.rval().setObjectOrNull(c);
+}
+
void MongoBase::Functions::copyDatabaseWithSCRAM(JSContext* cx, JS::CallArgs args) {
auto conn = getConnection(args);
diff --git a/src/mongo/scripting/mozjs/mongo.h b/src/mongo/scripting/mozjs/mongo.h
index 33ca0502018..bb9057cbd9d 100644
--- a/src/mongo/scripting/mozjs/mongo.h
+++ b/src/mongo/scripting/mozjs/mongo.h
@@ -47,6 +47,7 @@ struct MongoBase : public BaseInfo {
MONGO_DEFINE_JS_FUNCTION(auth);
MONGO_DEFINE_JS_FUNCTION(copyDatabaseWithSCRAM);
MONGO_DEFINE_JS_FUNCTION(cursorFromId);
+ MONGO_DEFINE_JS_FUNCTION(cursorHandleFromId);
MONGO_DEFINE_JS_FUNCTION(find);
MONGO_DEFINE_JS_FUNCTION(getClientRPCProtocols);
MONGO_DEFINE_JS_FUNCTION(getServerRPCProtocols);
@@ -59,7 +60,7 @@ struct MongoBase : public BaseInfo {
MONGO_DEFINE_JS_FUNCTION(update);
};
- static const JSFunctionSpec methods[14];
+ static const JSFunctionSpec methods[15];
static const char* const className;
static const unsigned classFlags = JSCLASS_HAS_PRIVATE;
diff --git a/src/mongo/shell/query.js b/src/mongo/shell/query.js
index 26f6ea4d43d..250a7013e73 100644
--- a/src/mongo/shell/query.js
+++ b/src/mongo/shell/query.js
@@ -648,8 +648,13 @@ function DBCommandCursor(mongo, cmdResult, batchSize) {
this._ns = cmdResult.cursor.ns;
this._db = mongo.getDB(this._ns.substr(0, this._ns.indexOf(".")));
this._collName = this._ns.substr(this._ns.indexOf(".") + 1);
- }
- else {
+
+ if (cmdResult.cursor.id) {
+ // Note that setting this._cursorid to 0 should be accompanied by
+ // this._cursorHandle.zeroCursorId().
+ this._cursorHandle = mongo.cursorHandleFromId(cmdResult.cursor.id);
+ }
+ } else {
this._cursor = mongo.cursorFromId(cmdResult.cursor.ns, cmdResult.cursor.id, batchSize);
}
}
@@ -683,6 +688,7 @@ DBCommandCursor.prototype._runGetMoreCommand = function() {
}
if (!cmdRes.cursor.id.compare(NumberLong("0"))) {
+ this._cursorHandle.zeroCursorId();
this._cursorid = NumberLong("0");
}
else if (this._cursorid.compare(cmdRes.cursor.id)) {