0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-21 12:39:08 +01:00

SERVER-86818 Rename our custom Map implementation to BSONAwareMap

GitOrigin-RevId: bcf8bc34491d05927cd3574c3ee0ee8f7657ca2b
This commit is contained in:
Matt Broadstone 2024-02-29 17:46:29 +00:00 committed by MongoDB Bot
parent 0987c01261
commit c0908b9f75
24 changed files with 77 additions and 69 deletions

View File

@ -46,6 +46,7 @@ globals:
SessionOptions: true
CollInfos: true
CountDownLatch: true
BSONAwareMap: true
# FCV-related
latestFCV: true

View File

@ -78,7 +78,7 @@ export const $config = (function() {
}
function checkNumUpdatedByEachTransaction(documents) {
const updateCounts = new Map();
const updateCounts = new BSONAwareMap();
for (let doc of documents) {
for (let op of doc.order) {

View File

@ -1,6 +1,6 @@
function basic1(key, lookup, shouldFail) {
var m = new Map();
var m = new BSONAwareMap();
m.put(key, 17);
var out = m.get(lookup || key);

View File

@ -201,4 +201,4 @@ assert.eq(
"}\n" +
"return true;"
})
.itcount());
.itcount());

View File

@ -7,7 +7,7 @@ export function Graph() {
}
const nodes = new Set();
const adjList = new Map();
const adjList = new BSONAwareMap();
this.addEdge = function addEdge(fromNode, toNode) {
nodes.add(fromNode);
@ -44,7 +44,7 @@ export function Graph() {
* - http://www.cs.cornell.edu/courses/cs2112/2012sp/lectures/lec24/lec24-12sp.html
*/
this.findCycle = function findCycle() {
const state = new Map();
const state = new BSONAwareMap();
for (let node of nodes) {
state.put(node, State.kNotYetVisited);
}
@ -84,7 +84,7 @@ export function Graph() {
// A cycle has been detected during the recursive call to doDepthFirstSearch().
// Unless we've already closed the loop, the (node, otherNode) edge must be part
// of it. Note that we use friendlyEqual() to match the definition of sameness
// as the mongo shell's Map type.
// as the mongo shell's BSONAwareMap type.
if (!friendlyEqual(result[0], result[result.length - 1])) {
result.unshift(node);
}

View File

@ -447,7 +447,7 @@ const NamespaceString MapReduceCommandTest::outputNss =
void MapReduceCommandTest::setUp() {
ServiceContextMongoDTest::setUp();
ScriptEngine::setup();
ScriptEngine::setup(ExecutionEnvironment::Server);
auto service = getServiceContext();
DBDirectClientFactory::get(service).registerImplementation(
[](OperationContext* opCtx) { return std::make_unique<DBDirectClient>(opCtx); });

View File

@ -731,7 +731,7 @@ ExitCode _initAndListen(ServiceContext* serviceContext, int listenPort) {
startMongoDFTDC(serviceContext);
if (mongodGlobalParams.scriptingEnabled) {
ScriptEngine::setup();
ScriptEngine::setup(ExecutionEnvironment::Server);
}
const auto isStandalone =

View File

@ -79,7 +79,7 @@ private:
void MapReduceFixture::setUp() {
ServiceContextMongoDTest::setUp();
ScriptEngine::setup(false);
ScriptEngine::setup(ExecutionEnvironment::Server);
}
void MapReduceFixture::tearDown() {

View File

@ -90,7 +90,7 @@ private:
void MapReduceFixture::setUp() {
ServiceContextMongoDTest::setUp();
ScriptEngine::setup(false);
ScriptEngine::setup(ExecutionEnvironment::Server);
}
void MapReduceFixture::tearDown() {

View File

@ -57,8 +57,7 @@ public:
/**
* Create or get a pointer to a JsExecution instance, capable of invoking Javascript functions
* and reading the return value. If `loadStoredProcedures` is true, this will load all stored
* procedures from database unless 'disableLoadStored' is set on the global ScriptEngine. The
* JsExecution* returned is owned by 'opCtx'.
* procedures from database. The JsExecution* returned is owned by 'opCtx'.
*/
static JsExecution* get(OperationContext* opCtx,
const BSONObj& scope,

View File

@ -266,7 +266,7 @@ int dbtestsMain(int argc, char** argv) {
service, std::make_unique<repl::DropPendingCollectionReaper>(storageMock.get()));
AuthorizationManager::get(service->getService())->setAuthEnabled(false);
ScriptEngine::setup();
ScriptEngine::setup(ExecutionEnvironment::Server);
return mongo::dbtests::runDbTests(argc, argv);
}

View File

@ -910,7 +910,7 @@ ExitCode runMongosServer(ServiceContext* serviceContext) {
TimeElapsedBuilderScopedTimer scopedTimer(serviceContext->getFastClockSource(),
"Set up script engine",
&startupTimeElapsedBuilder);
ScriptEngine::setup();
ScriptEngine::setup(ExecutionEnvironment::Server);
}
{

View File

@ -96,10 +96,7 @@ static std::unique_ptr<ScriptEngine> globalScriptEngine;
} // namespace
ScriptEngine::ScriptEngine(bool disableLoadStored)
: _disableLoadStored(disableLoadStored), _scopeInitCallback() {}
ScriptEngine::~ScriptEngine() {}
ScriptEngine::ScriptEngine() : _scopeInitCallback() {}
Scope::Scope()
: _localDBName(DatabaseName::kEmpty),
@ -257,8 +254,6 @@ void Scope::validateObjectIdString(const string& str) {
}
void Scope::loadStored(OperationContext* opCtx, bool ignoreNotConnected) {
if (!getGlobalScriptEngine()->_disableLoadStored)
return;
if (_localDBName.isEmpty()) {
if (ignoreNotConnected)
return;

View File

@ -231,13 +231,15 @@ protected:
bool _lastRetIsNativeCode; // v8 only: set to true if eval'd script returns a native func
};
enum class ExecutionEnvironment { Server, TestRunner };
class ScriptEngine : public KillOpListenerInterface {
ScriptEngine(const ScriptEngine&) = delete;
ScriptEngine& operator=(const ScriptEngine&) = delete;
public:
ScriptEngine(bool disableLoadStored);
virtual ~ScriptEngine();
ScriptEngine();
virtual ~ScriptEngine() = default;
virtual Scope* newScope() {
return createScope();
@ -268,11 +270,9 @@ public:
virtual void setLoadPath(const std::string& loadPath) = 0;
/**
* Calls the constructor for the Global ScriptEngine. 'disableLoadStored' causes future calls to
* the function Scope::loadStored(), which would otherwise load stored procedures, to be
* ignored.
* Calls the constructor for the Global ScriptEngine.
*/
static void setup(bool disableLoadStored = true);
static void setup(ExecutionEnvironment environment);
static void dropScopeCache();
/** gets a scope from the pool or a new one if pool is empty
@ -285,6 +285,10 @@ public:
const DatabaseName& db,
const std::string& scopeType);
using ScopeCallback = void (*)(Scope&);
ScopeCallback getScopeInitCallback() {
return _scopeInitCallback;
};
void setScopeInitCallback(void (*func)(Scope&)) {
_scopeInitCallback = func;
}
@ -302,7 +306,6 @@ public:
virtual void interruptAll() {}
static std::string getInterpreterVersionString();
const bool _disableLoadStored;
protected:
virtual Scope* createScope() = 0;

View File

@ -32,7 +32,7 @@
#include "mongo/scripting/engine.h"
namespace mongo {
void ScriptEngine::setup(bool disableLoadStored) {
void ScriptEngine::setup(ExecutionEnvironment environment) {
// noop
}

View File

@ -66,11 +66,12 @@ void DisableExtraThreads();
namespace mongo {
void ScriptEngine::setup(bool disableLoadStored) {
if (getGlobalScriptEngine())
void ScriptEngine::setup(ExecutionEnvironment environment) {
if (getGlobalScriptEngine()) {
return;
}
setGlobalScriptEngine(new mozjs::MozJSScriptEngine(disableLoadStored));
setGlobalScriptEngine(new mozjs::MozJSScriptEngine(environment));
if (hasGlobalServiceContext()) {
getGlobalServiceContext()->registerKillOpListener(getGlobalScriptEngine());
@ -84,8 +85,8 @@ std::string ScriptEngine::getInterpreterVersionString() {
namespace mozjs {
MozJSScriptEngine::MozJSScriptEngine(bool disableLoadStored)
: ScriptEngine(disableLoadStored), _loadPath(boost::filesystem::current_path().string()) {
MozJSScriptEngine::MozJSScriptEngine(ExecutionEnvironment environment)
: _executionEnvironment(environment), _loadPath(boost::filesystem::current_path().string()) {
uassert(ErrorCodes::JSInterpreterFailure, "Failed to JS_Init()", JS_Init());
js::DisableExtraThreads();
}

View File

@ -37,7 +37,6 @@
#include "mongo/scripting/deadline_monitor.h"
#include "mongo/scripting/engine.h"
#include "mongo/stdx/unordered_map.h"
#include "mongo/util/concurrency/mutex.h"
namespace mongo {
namespace mozjs {
@ -50,22 +49,15 @@ class MozJSImplScope;
*/
class MozJSScriptEngine final : public mongo::ScriptEngine {
public:
MozJSScriptEngine(bool disableLoadStored);
MozJSScriptEngine(ExecutionEnvironment env);
~MozJSScriptEngine() override;
mongo::Scope* createScope() override;
mongo::Scope* createScopeForCurrentThread(boost::optional<int> jsHeapLimitMB) override;
void runTest() override {}
bool utf8Ok() const override {
return true;
}
void interrupt(unsigned opId) override;
void interruptAll() override;
void enableJIT(bool value) override;
bool isJITEnabled() const override;
@ -81,15 +73,21 @@ public:
void registerOperation(OperationContext* ctx, MozJSImplScope* scope);
void unregisterOperation(unsigned int opId);
using ScopeCallback = void (*)(Scope&);
ScopeCallback getScopeInitCallback() {
return _scopeInitCallback;
};
void interrupt(unsigned opId) override;
void interruptAll() override;
DeadlineMonitor<MozJSImplScope>& getDeadlineMonitor() {
return _deadlineMonitor;
}
ExecutionEnvironment executionEnvironment() const {
return _executionEnvironment;
}
protected:
mongo::Scope* createScope() override;
mongo::Scope* createScopeForCurrentThread(boost::optional<int> jsHeapLimitMB) override;
private:
/**
* This mutex protects _opToScopeMap
@ -101,6 +99,7 @@ private:
// _globalInterruptLock).
DeadlineMonitor<MozJSImplScope> _deadlineMonitor;
ExecutionEnvironment _executionEnvironment;
std::string _loadPath;
};

View File

@ -526,6 +526,13 @@ MozJSImplScope::MozJSImplScope(MozJSScriptEngine* engine, boost::optional<int> j
execSetup(JSFiles::assert);
execSetup(JSFiles::types);
if (_engine->executionEnvironment() == ExecutionEnvironment::Server) {
// For legacy support in server-side javascript execution, delete the ECMAScript defined
// `Map` type and replace it with our `BSONAwareMap` implementation.
ObjectWrapper(_context, _global).deleteProperty("Map");
ObjectWrapper(_context, _global).renameAndDeleteProperty("BSONAwareMap", "Map");
}
// install global utility functions
installGlobalUtils(*this);
_mongoHelpersProto.install(_global);
@ -1110,10 +1117,6 @@ void MozJSImplScope::installBSONTypes() {
_timestampProto.install(_global);
_uriProto.install(_global);
_statusProto.install(_global);
// This builtin map is a javascript 6 thing. We want our version. so
// take theirs out
ObjectWrapper(_context, _global).deleteProperty("Map");
}
void MozJSImplScope::installDBAccess() {

View File

@ -45,7 +45,7 @@ namespace mongo {
namespace mozjs {
TEST(ModuleLoaderTest, ImportBaseSpecifierFails) {
mongo::ScriptEngine::setup();
mongo::ScriptEngine::setup(ExecutionEnvironment::TestRunner);
std::unique_ptr<mongo::Scope> scope(mongo::getGlobalScriptEngine()->newScope());
auto code = "import * as test from \"base_specifier\""_sd;
@ -61,7 +61,7 @@ TEST(ModuleLoaderTest, ImportBaseSpecifierFails) {
#if !defined(_WIN32)
TEST(ModuleLoaderTest, ImportDirectoryFails) {
mongo::ScriptEngine::setup();
mongo::ScriptEngine::setup(ExecutionEnvironment::TestRunner);
std::unique_ptr<mongo::Scope> scope(mongo::getGlobalScriptEngine()->newScope());
auto code = fmt::format("import * as test from \"{}\"",
@ -78,7 +78,7 @@ TEST(ModuleLoaderTest, ImportDirectoryFails) {
#endif
TEST(ModuleLoaderTest, ImportInInteractiveFails) {
mongo::ScriptEngine::setup();
mongo::ScriptEngine::setup(ExecutionEnvironment::TestRunner);
std::unique_ptr<mongo::Scope> scope(mongo::getGlobalScriptEngine()->newScope());
auto code = "import * as test from \"some_module\""_sd;
@ -96,7 +96,7 @@ TEST(ModuleLoaderTest, ImportInInteractiveFails) {
}
TEST(ModuleLoaderTest, TopLevelAwaitWorks) {
mongo::ScriptEngine::setup();
mongo::ScriptEngine::setup(ExecutionEnvironment::TestRunner);
std::unique_ptr<mongo::Scope> scope(mongo::getGlobalScriptEngine()->newScope());
auto code = "async function test() { return 42; } await test();"_sd;
ASSERT_DOES_NOT_THROW(scope->exec(code,

View File

@ -546,6 +546,13 @@ void ObjectWrapper::rename(Key from, const char* to) {
setValue(from, undefValue);
}
void ObjectWrapper::renameAndDeleteProperty(Key from, const char* to) {
JS::RootedValue value(_context);
getValue(from, &value);
setValue(to, value);
from.del(_context, _object);
}
bool ObjectWrapper::hasField(Key key) {
return key.has(_context, _object);
}

View File

@ -164,6 +164,9 @@ public:
void rename(Key key, const char* to);
// Rename key and delete the original property
void renameAndDeleteProperty(Key key, const char* to);
// has field walks the prototype heirarchy
bool hasField(Key key);

View File

@ -617,7 +617,7 @@ DB.prototype.groupeval = function(parmsObj) {
var groupFunction = function() {
var parms = args[0]; // eslint-disable-line
var c = globalThis.db[parms.ns].find(parms.cond || {});
var map = new Map();
var map = new BSONAwareMap();
var pks = parms.key ? Object.keySet(parms.key) : null;
var pkl = pks ? pks.length : 0;
var key = {};

View File

@ -923,7 +923,7 @@ int mongo_main(int argc, char* argv[]) {
}
mongo::ScriptEngine::setConnectCallback(mongo::shell_utils::onConnect);
mongo::ScriptEngine::setup();
mongo::ScriptEngine::setup(ExecutionEnvironment::TestRunner);
mongo::getGlobalScriptEngine()->setJSHeapLimitMB(shellGlobalParams.jsHeapLimitMB);
mongo::getGlobalScriptEngine()->setScopeInitCallback(mongo::shell_utils::initScope);
mongo::getGlobalScriptEngine()->enableJIT(!shellGlobalParams.nojit);

View File

@ -546,15 +546,12 @@ if (typeof (BinData) != "undefined") {
print("warning: no BinData class");
}
// Map
if (typeof (Map) == "undefined") {
// eslint-disable-next-line
Map = function() {
this._data = {};
};
}
// BSONAwareMap
BSONAwareMap = function() {
this._data = {};
};
Map.hash = function(val) {
BSONAwareMap.hash = function(val) {
if (!val)
return val;
@ -575,19 +572,19 @@ Map.hash = function(val) {
throw Error("can't hash : " + typeof (val));
};
Map.prototype.put = function(key, value) {
BSONAwareMap.prototype.put = function(key, value) {
var o = this._get(key);
var old = o.value;
o.value = value;
return old;
};
Map.prototype.get = function(key) {
BSONAwareMap.prototype.get = function(key) {
return this._get(key).value;
};
Map.prototype._get = function(key) {
var h = Map.hash(key);
BSONAwareMap.prototype._get = function(key) {
var h = BSONAwareMap.hash(key);
var a = this._data[h];
if (!a) {
a = [];
@ -603,7 +600,7 @@ Map.prototype._get = function(key) {
return o;
};
Map.prototype.values = function() {
BSONAwareMap.prototype.values = function() {
var all = [];
for (var k in this._data) {
this._data[k].forEach(function(z) {