virtual bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string fromhost = cmdObj.getStringField("fromhost"); if ( fromhost.empty() ) { /* copy from self */ stringstream ss; ss << "localhost:" << cmdLine.port; fromhost = ss.str(); } string fromdb = cmdObj.getStringField("fromdb"); string todb = cmdObj.getStringField("todb"); if ( fromhost.empty() || todb.empty() || fromdb.empty() ) { errmsg = "parms missing - {copydb: 1, fromhost: <hostname>, fromdb: <db>, todb: <db>}"; return false; } Cloner c; string username = cmdObj.getStringField( "username" ); string nonce = cmdObj.getStringField( "nonce" ); string key = cmdObj.getStringField( "key" ); if ( !username.empty() && !nonce.empty() && !key.empty() ) { uassert( 13008, "must call copydbgetnonce first", authConn_.get() ); BSONObj ret; { dbtemprelease t; if ( !authConn_->runCommand( fromdb, BSON( "authenticate" << 1 << "user" << username << "nonce" << nonce << "key" << key ), ret ) ) { errmsg = "unable to login " + string( ret ); return false; } } c.setConnection( authConn_.release() ); } Client::Context ctx(todb); bool res = c.go(fromhost.c_str(), errmsg, fromdb, /*logForReplication=*/!fromRepl, /*slaveok*/false, /*replauth*/false, /*snapshot*/true); return res; }
virtual bool run(OperationContext* txn, const string&, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result) { string fromhost = cmdObj.getStringField("fromhost"); if ( fromhost.empty() ) { /* copy from self */ stringstream ss; ss << "localhost:" << serverGlobalParams.port; fromhost = ss.str(); } const ConnectionString cs(uassertStatusOK(ConnectionString::parse(fromhost))); authConn_.reset(cs.connect(errmsg)); if (!authConn_.get()) { return false; } BSONObj ret; if( !authConn_->runCommand( "admin", BSON( "getnonce" << 1 ), ret ) ) { errmsg = "couldn't get nonce " + ret.toString(); return false; } result.appendElements( ret ); return true; }
static ClientConnections* threadInstance() { ClientConnections* cc = _perThread.get(); if ( ! cc ) { cc = new ClientConnections(); _perThread.reset( cc ); } return cc; }
disable_syscall_interruption() { if (_syscalls_interruptable.get() == NULL) { last_value = true; _syscalls_interruptable.reset(new bool(false)); } else { last_value = *_syscalls_interruptable; *_syscalls_interruptable = false; } }
std::shared_ptr<CoreContext> CoreContext::CurrentContext(void) { if(!autoCurrentContext.get()) return std::static_pointer_cast<CoreContext, GlobalCoreContext>(GetGlobalContext()); std::shared_ptr<CoreContext>* retVal = autoCurrentContext.get(); assert(retVal); assert(*retVal); return *retVal; }
ostream & operator()() { ThreadOutputStream * tos( threadOutputStream_.get() ); if( tos == nullptr ) { tos = new ThreadOutputStream(); threadOutputStream_.reset( tos ); } return (*tos) << boost::posix_time::microsec_clock::universal_time() << ' ' << format("%014s") % boost::this_thread::get_id() << " [ " << format("%-20.20s") % name_ << " ] "; };
inline void worker( std::uint64_t updates ) { global_scratch.reset(new double); for (double i = 0.; i < updates; ++i) *global_scratch += 1. / (2. * i + 1.); global_scratch.reset(); }
virtual bool run(OperationContext* txn, const string&, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result) { const string fromDb = cmdObj.getStringField("fromdb"); string fromHost = cmdObj.getStringField("fromhost"); if ( fromHost.empty() ) { /* copy from self */ stringstream ss; ss << "localhost:" << serverGlobalParams.port; fromHost = ss.str(); } const ConnectionString cs(uassertStatusOK(ConnectionString::parse(fromHost))); BSONElement mechanismElement; Status status = bsonExtractField(cmdObj, saslCommandMechanismFieldName, &mechanismElement); if (!status.isOK()) { return appendCommandStatus(result, status); } BSONElement payloadElement; status = bsonExtractField(cmdObj, saslCommandPayloadFieldName, &payloadElement); if (!status.isOK()) { log() << "Failed to extract payload: " << status; return false; } authConn_.reset(cs.connect(errmsg)); if (!authConn_.get()) { return false; } BSONObj ret; if( !authConn_->runCommand( fromDb, BSON( "saslStart" << 1 << mechanismElement << payloadElement), ret ) ) { return appendCommandStatus(result, Command::getStatusFromCommandResult(ret)); } result.appendElements( ret ); return true; }
/** Get a scope from the pool of scopes matching the supplied pool name */ auto_ptr<Scope> ScriptEngine::getPooledScope(const string& pool) { if (!scopeCache.get()) scopeCache.reset(new ScopeCache()); Scope* s = scopeCache->get(pool); if (!s) s = newScope(); auto_ptr<Scope> p; p.reset(new PooledScope(pool, s)); return p; }
void checkTSSInit() { if(m_transactionInProgress.get() == 0) { m_transactionInProgress.reset(new bool); (*m_transactionInProgress) = false; } if(m_transaction.get() == 0) { m_transaction.reset(new DbTxn *); (*m_transaction) = NULL; } }
/** Get a scope from the pool of scopes matching the supplied pool name */ auto_ptr<Scope> ScriptEngine::getPooledScope(const string& pool, const string& scopeType) { if (!scopeCache.get()) scopeCache.reset(new ScopeCache()); Scope* s = scopeCache->get(pool + scopeType); if (!s) s = newScope(); auto_ptr<Scope> p; p.reset(new PooledScope(pool + scopeType, s)); p->setLocalDB(pool); p->loadStored(true); return p; }
std::shared_ptr<CoreContext> CoreContext::SetCurrent(const std::shared_ptr<CoreContext>& ctxt) { const auto& currentContext = CurrentContextOrNull(); // Short-circuit test, no need to proceed if we aren't changing the context: if (currentContext == ctxt) return currentContext; // Value is changing, update: auto retVal = currentContext; if (ctxt) autoCurrentContext.reset(new std::shared_ptr<CoreContext>(ctxt)); else autoCurrentContext.reset(); return retVal; }
Glob::Glob(const std::string& pattern, GlobFlags flags) { globObject.reset(this); posix::glob_t glob; posix::glob(pattern.c_str(), flags, &onGlobError, &glob); globObject.release(); if (glob.gl_pathc) { for (char** p = glob.gl_pathv; *p != NULL; ++p) { pathNames_.push_back(*p); } } posix::globfree(&glob); }
extern "C" int onGlobError(const char *epath, int eerrno) { std::string pathName(epath); std::error_code errorCode(eerrno, std::system_category()); globObject->errors_.push_back(std::make_pair(pathName, errorCode)); return globObject->onError(pathName, errorCode); }
virtual ~PooledScope(){ ScopeCache * sc = scopeCache.get(); if ( sc ){ sc->done( _pool , _real ); _real = 0; } else { log() << "warning: scopeCache is empty!" << endl; delete _real; _real = 0; } }
virtual bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string fromhost = cmdObj.getStringField("fromhost"); if ( fromhost.empty() ) { /* copy from self */ stringstream ss; ss << "localhost:" << cmdLine.port; fromhost = ss.str(); } authConn_.reset( new DBClientConnection() ); BSONObj ret; { dbtemprelease t; if ( !authConn_->connect( fromhost, errmsg ) ) return false; if( !authConn_->runCommand( "admin", BSON( "getnonce" << 1 ), ret ) ) { errmsg = "couldn't get nonce " + string( ret ); return false; } } result.appendElements( ret ); return true; }
virtual ~PooledScope() { ScopeCache* sc = scopeCache.get(); if (sc) { sc->done(_pool, _real); _real = NULL; } else { // this means that the Scope was killed from a different thread // for example a cursor got timed out that has a $where clause LOG(3) << "warning: scopeCache is empty!" << endl; delete _real; _real = 0; } }
namespace mongo { long long Scope::_lastVersion = 1; static const unsigned kMaxJsFileLength = std::numeric_limits<unsigned>::max() - 1; ScriptEngine::ScriptEngine() : _scopeInitCallback() { } ScriptEngine::~ScriptEngine() { } Scope::Scope() : _localDBName(""), _loadedVersion(0), _numTimeUsed(0), _lastRetIsNativeCode(false) { } Scope::~Scope() { } void Scope::append(BSONObjBuilder& builder, const char* fieldName, const char* scopeName) { int t = type(scopeName); switch (t) { case Object: builder.append(fieldName, getObject(scopeName)); break; case Array: builder.appendArray(fieldName, getObject(scopeName)); break; case NumberDouble: builder.append(fieldName, getNumber(scopeName)); break; case NumberInt: builder.append(fieldName, getNumberInt(scopeName)); break; case NumberLong: builder.append(fieldName, getNumberLongLong(scopeName)); break; case String: builder.append(fieldName, getString(scopeName)); break; case Bool: builder.appendBool(fieldName, getBoolean(scopeName)); break; case jstNULL: case Undefined: builder.appendNull(fieldName); break; case Date: // TODO: make signed builder.appendDate(fieldName, Date_t((unsigned long long)getNumber(scopeName))); break; case Code: builder.appendCode(fieldName, getString(scopeName)); break; default: uassert(10206, str::stream() << "can't append type from: " << t, 0); } } int Scope::invoke(const char* code, const BSONObj* args, const BSONObj* recv, int timeoutMs) { ScriptingFunction func = createFunction(code); uassert(10207, "compile failed", func); return invoke(func, args, recv, timeoutMs); } bool Scope::execFile(const string& filename, bool printResult, bool reportError, int timeoutMs) { boost::filesystem::path p(filename); if (!exists(p)) { log() << "file [" << filename << "] doesn't exist" << endl; return false; } // iterate directories and recurse using all *.js files in the directory if (boost::filesystem::is_directory(p)) { boost::filesystem::directory_iterator end; bool empty = true; for (boost::filesystem::directory_iterator it (p); it != end; it++) { empty = false; boost::filesystem::path sub(*it); if (!endsWith(sub.string().c_str(), ".js")) continue; if (!execFile(sub.string().c_str(), printResult, reportError, timeoutMs)) return false; } if (empty) { log() << "directory [" << filename << "] doesn't have any *.js files" << endl; return false; } return true; } File f; f.open(filename.c_str(), true); fileofs fo = f.len(); if (fo > kMaxJsFileLength) { warning() << "attempted to execute javascript file larger than 2GB" << endl; return false; } unsigned len = static_cast<unsigned>(fo); boost::scoped_array<char> data (new char[len+1]); data[len] = 0; f.read(0, data.get(), len); int offset = 0; if (data[0] == '#' && data[1] == '!') { const char* newline = strchr(data.get(), '\n'); if (!newline) return true; // file of just shebang treated same as empty file offset = newline - data.get(); } StringData code(data.get() + offset, len - offset); return exec(code, filename, printResult, reportError, timeoutMs); } void Scope::storedFuncMod() { _lastVersion++; } void Scope::validateObjectIdString(const string& str) { uassert(10448, "invalid object id: length", str.size() == 24); for (size_t i = 0; i < str.size(); i++) uassert(10430, "invalid object id: not hex", std::isxdigit(str.at(i))); } void Scope::loadStored(bool ignoreNotConnected) { if (_localDBName.size() == 0) { if (ignoreNotConnected) return; uassert(10208, "need to have locallyConnected already", _localDBName.size()); } if (_loadedVersion == _lastVersion) return; _loadedVersion = _lastVersion; string coll = _localDBName + ".system.js"; static DBClientBase* db = createDirectClient(); auto_ptr<DBClientCursor> c = db->query(coll, Query(), 0, 0, NULL, QueryOption_SlaveOk, 0); massert(16669, "unable to get db client cursor from query", c.get()); set<string> thisTime; while (c->more()) { BSONObj o = c->nextSafe(); BSONElement n = o["_id"]; BSONElement v = o["value"]; uassert(10209, str::stream() << "name has to be a string: " << n, n.type() == String); uassert(10210, "value has to be set", v.type() != EOO); try { setElement(n.valuestr(), v); thisTime.insert(n.valuestr()); _storedNames.insert(n.valuestr()); } catch (const DBException& setElemEx) { log() << "unable to load stored JavaScript function " << n.valuestr() << "(): " << setElemEx.what() << endl; } } // remove things from scope that were removed from the system.js collection for (set<string>::iterator i = _storedNames.begin(); i != _storedNames.end(); ) { if (thisTime.count(*i) == 0) { string toDelete = str::stream() << "delete " << *i; _storedNames.erase(i++); execSetup(toDelete, "clean up scope"); } else { ++i; } } } ScriptingFunction Scope::createFunction(const char* code) { if (code[0] == '/' && code [1] == '*') { code += 2; while (code[0] && code[1]) { if (code[0] == '*' && code[1] == '/') { code += 2; break; } code++; } } map<string, ScriptingFunction>::iterator i = _cachedFunctions.find(code); if (i != _cachedFunctions.end()) return i->second; // NB: we calculate the function number for v8 so the cache can be utilized to // lookup the source on an exception, but SpiderMonkey uses the value // returned by JS_CompileFunction. ScriptingFunction functionNumber = getFunctionCache().size() + 1; _cachedFunctions[code] = functionNumber; ScriptingFunction f = _createFunction(code, functionNumber); return f; } namespace JSFiles { extern const JSFile collection; extern const JSFile db; extern const JSFile mongo; extern const JSFile mr; extern const JSFile query; extern const JSFile utils; extern const JSFile utils_sh; } void Scope::execCoreFiles() { execSetup(JSFiles::utils); execSetup(JSFiles::utils_sh); execSetup(JSFiles::db); execSetup(JSFiles::mongo); execSetup(JSFiles::mr); execSetup(JSFiles::query); execSetup(JSFiles::collection); } /** install BenchRunner suite */ void Scope::installBenchRun() { injectNative("benchRun", BenchRunner::benchRunSync); injectNative("benchRunSync", BenchRunner::benchRunSync); injectNative("benchStart", BenchRunner::benchStart); injectNative("benchFinish", BenchRunner::benchFinish); } typedef map<string, list<Scope*> > PoolToScopes; class ScopeCache { public: ScopeCache() : _mutex("ScopeCache") { } ~ScopeCache() { if (inShutdown()) return; clear(); } void done(const string& pool, Scope* s) { scoped_lock lk(_mutex); list<Scope*>& l = _pools[pool]; bool oom = s->hasOutOfMemoryException(); // do not keep too many contexts, or use them for too long if (l.size() > 10 || s->getTimeUsed() > 10 || oom || !s->getError().empty()) { delete s; } else { l.push_back(s); s->reset(); } if (oom) { // out of mem, make some room log() << "Clearing all idle JS contexts due to out of memory" << endl; clear(); } } Scope* get(const string& pool) { scoped_lock lk(_mutex); list<Scope*>& l = _pools[pool]; if (l.size() == 0) return 0; Scope* s = l.back(); l.pop_back(); s->reset(); s->incTimeUsed(); return s; } void clear() { set<Scope*> seen; for (PoolToScopes::iterator i = _pools.begin(); i != _pools.end(); ++i) { for (list<Scope*>::iterator j = i->second.begin(); j != i->second.end(); ++j) { Scope* s = *j; fassert(16652, seen.insert(s).second); delete s; } } _pools.clear(); } private: PoolToScopes _pools; mongo::mutex _mutex; }; thread_specific_ptr<ScopeCache> scopeCache; class PooledScope : public Scope { public: PooledScope(const std::string& pool, Scope* real) : _pool(pool), _real(real) { _real->loadStored(true); }; virtual ~PooledScope() { ScopeCache* sc = scopeCache.get(); if (sc) { sc->done(_pool, _real); _real = NULL; } else { // this means that the Scope was killed from a different thread // for example a cursor got timed out that has a $where clause LOG(3) << "warning: scopeCache is empty!" << endl; delete _real; _real = 0; } } // wrappers for the derived (_real) scope void reset() { _real->reset(); } void init(const BSONObj* data) { _real->init(data); } void localConnect(const char* dbName) { _real->localConnect(dbName); } void setLocalDB(const string& dbName) { _real->setLocalDB(dbName); } void loadStored(bool ignoreNotConnected = false) { _real->loadStored(ignoreNotConnected); } void externalSetup() { _real->externalSetup(); } void gc() { _real->gc(); } bool isKillPending() const { return _real->isKillPending(); } int type(const char* field) { return _real->type(field); } string getError() { return _real->getError(); } bool hasOutOfMemoryException() { return _real->hasOutOfMemoryException(); } void rename(const char* from, const char* to) { _real->rename(from, to); } double getNumber(const char* field) { return _real->getNumber(field); } string getString(const char* field) { return _real->getString(field); } bool getBoolean(const char* field) { return _real->getBoolean(field); } BSONObj getObject(const char* field) { return _real->getObject(field); } void setNumber(const char* field, double val) { _real->setNumber(field, val); } void setString(const char* field, const char* val) { _real->setString(field, val); } void setElement(const char* field, const BSONElement& val) { _real->setElement(field, val); } void setObject(const char* field, const BSONObj& obj, bool readOnly = true) { _real->setObject(field, obj, readOnly); } bool isLastRetNativeCode() { return _real->isLastRetNativeCode(); } void setBoolean(const char* field, bool val) { _real->setBoolean(field, val); } void setFunction(const char* field, const char* code) { _real->setFunction(field, code); } ScriptingFunction createFunction(const char* code) { return _real->createFunction(code); } int invoke(ScriptingFunction func, const BSONObj* args, const BSONObj* recv, int timeoutMs, bool ignoreReturn, bool readOnlyArgs, bool readOnlyRecv) { return _real->invoke(func, args, recv, timeoutMs, ignoreReturn, readOnlyArgs, readOnlyRecv); } bool exec(const StringData& code, const string& name, bool printResult, bool reportError, bool assertOnError, int timeoutMs = 0) { return _real->exec(code, name, printResult, reportError, assertOnError, timeoutMs); } bool execFile(const string& filename, bool printResult, bool reportError, int timeoutMs = 0) { return _real->execFile(filename, printResult, reportError, timeoutMs); } void injectNative(const char* field, NativeFunction func, void* data) { _real->injectNative(field, func, data); } void append(BSONObjBuilder& builder, const char* fieldName, const char* scopeName) { _real->append(builder, fieldName, scopeName); } protected: FunctionCacheMap& getFunctionCache() { return _real->getFunctionCache(); } ScriptingFunction _createFunction(const char* code, ScriptingFunction functionNumber = 0) { return _real->_createFunction(code, functionNumber); } private: string _pool; Scope* _real; }; /** Get a scope from the pool of scopes matching the supplied pool name */ auto_ptr<Scope> ScriptEngine::getPooledScope(const string& pool, const string& scopeType) { if (!scopeCache.get()) scopeCache.reset(new ScopeCache()); Scope* s = scopeCache->get(pool + scopeType); if (!s) s = newScope(); auto_ptr<Scope> p; p.reset(new PooledScope(pool + scopeType, s)); p->setLocalDB(pool); p->loadStored(true); return p; } void ScriptEngine::threadDone() { ScopeCache* sc = scopeCache.get(); if (sc) sc->clear(); } void (*ScriptEngine::_connectCallback)(DBClientWithCommands&) = 0; const char* (*ScriptEngine::_checkInterruptCallback)() = 0; unsigned (*ScriptEngine::_getCurrentOpIdCallback)() = 0; ScriptEngine* globalScriptEngine = 0; bool hasJSReturn(const string& code) { size_t x = code.find("return"); if (x == string::npos) return false; return (x == 0 || !isalpha(code[x-1])) && !isalpha(code[x+6]); } const char* jsSkipWhiteSpace(const char* raw) { while (raw[0]) { while (isspace(*raw)) { ++raw; } if (raw[0] != '/' || raw[1] != '/') break; while (raw[0] && raw[0] != '\n') raw++; } return raw; } }
namespace this_thread { /** * @intern */ extern thread_specific_ptr<bool> _syscalls_interruptable; /** * Check whether system calls should be interruptable in * the calling thread. */ bool syscalls_interruptable(); class restore_syscall_interruption; /** * Create this struct on the stack to temporarily enable system * call interruption, until the object goes out of scope. */ class enable_syscall_interruption { private: bool last_value; public: enable_syscall_interruption() { if (_syscalls_interruptable.get() == NULL) { last_value = true; _syscalls_interruptable.reset(new bool(true)); } else { last_value = *_syscalls_interruptable; *_syscalls_interruptable = true; } } ~enable_syscall_interruption() { *_syscalls_interruptable = last_value; } }; /** * Create this struct on the stack to temporarily disable system * call interruption, until the object goes out of scope. * While system call interruption is disabled, the functions in * InterruptableCalls will try until the return code is not EINTR. */ class disable_syscall_interruption { private: friend class restore_syscall_interruption; bool last_value; public: disable_syscall_interruption() { if (_syscalls_interruptable.get() == NULL) { last_value = true; _syscalls_interruptable.reset(new bool(false)); } else { last_value = *_syscalls_interruptable; *_syscalls_interruptable = false; } } ~disable_syscall_interruption() { *_syscalls_interruptable = last_value; } }; /** * Creating an object of this class on the stack will restore the * system call interruption state to what it was before. */ class restore_syscall_interruption { private: int last_value; public: restore_syscall_interruption(const disable_syscall_interruption &intr) { assert(_syscalls_interruptable.get() != NULL); last_value = *_syscalls_interruptable; *_syscalls_interruptable = intr.last_value; } ~restore_syscall_interruption() { *_syscalls_interruptable = last_value; } }; } // namespace this_thread
void unlock () { this_thread_hierarchy_value.reset(new unsigned long(previous_hierarchy_value)); internal_mutex.unlock (); }
void update_hierarchy_value () { previous_hierarchy_value = *this_thread_hierarchy_value; this_thread_hierarchy_value.reset(new unsigned long(hierarchy_value)); }
void ScriptEngine::threadDone(){ ScopeCache * sc = scopeCache.get(); if ( sc ){ sc->clear(); } }
namespace mongo { long long Scope::_lastVersion = 1; int Scope::_numScopes = 0; Scope::Scope() : _localDBName("") , _loadedVersion(0){ _numScopes++; } Scope::~Scope(){ _numScopes--; } ScriptEngine::ScriptEngine() : _scopeInitCallback() { } ScriptEngine::~ScriptEngine(){ } void Scope::append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName ){ int t = type( scopeName ); switch ( t ){ case Object: builder.append( fieldName , getObject( scopeName ) ); break; case Array: builder.appendArray( fieldName , getObject( scopeName ) ); break; case NumberDouble: builder.append( fieldName , getNumber( scopeName ) ); break; case NumberInt: builder.append( fieldName , getNumberInt( scopeName ) ); break; case NumberLong: builder.append( fieldName , getNumberLongLong( scopeName ) ); break; case String: builder.append( fieldName , getString( scopeName ).c_str() ); break; case Bool: builder.appendBool( fieldName , getBoolean( scopeName ) ); break; case jstNULL: case Undefined: builder.appendNull( fieldName ); break; case Date: // TODO: make signed builder.appendDate( fieldName , Date_t((unsigned long long)getNumber( scopeName )) ); break; default: stringstream temp; temp << "can't append type from:"; temp << t; uassert( 10206 , temp.str() , 0 ); } } int Scope::invoke( const char* code , const BSONObj& args, int timeoutMs ){ ScriptingFunction func = createFunction( code ); uassert( 10207 , "compile failed" , func ); return invoke( func , args, timeoutMs ); } bool Scope::execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs ){ path p( filename ); if ( ! exists( p ) ){ cout << "file [" << filename << "] doesn't exist" << endl; if ( assertOnError ) assert( 0 ); return false; } // iterate directories and recurse using all *.js files in the directory if ( is_directory( p ) ){ directory_iterator end; bool empty = true; for (directory_iterator it (p); it != end; it++){ empty = false; path sub (*it); if (!endsWith(sub.string().c_str(), ".js")) continue; if (!execFile(sub.string().c_str(), printResult, reportError, assertOnError, timeoutMs)) return false; } if (empty){ cout << "directory [" << filename << "] doesn't have any *.js files" << endl; if ( assertOnError ) assert( 0 ); return false; } return true; } File f; f.open( filename.c_str() , true ); fileofs L = f.len(); assert( L <= 0x7ffffffe ); char * data = (char*)malloc( (size_t) L+1 ); data[L] = 0; f.read( 0 , data , (size_t) L ); return exec( data , filename , printResult , reportError , assertOnError, timeoutMs ); } void Scope::storedFuncMod(){ _lastVersion++; } void Scope::validateObjectIdString( const string &str ) { massert( 10448 , "invalid object id: length", str.size() == 24 ); for ( string::size_type i=0; i<str.size(); i++ ){ char c = str[i]; if ( ( c >= '0' && c <= '9' ) || ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) ){ continue; } massert( 10430 , "invalid object id: not hex", false ); } } void Scope::loadStored( bool ignoreNotConnected ){ if ( _localDBName.size() == 0 ){ if ( ignoreNotConnected ) return; uassert( 10208 , "need to have locallyConnected already" , _localDBName.size() ); } if ( _loadedVersion == _lastVersion ) return; _loadedVersion = _lastVersion; string coll = _localDBName + ".system.js"; static DBClientBase * db = createDirectClient(); auto_ptr<DBClientCursor> c = db->query( coll , Query() ); set<string> thisTime; while ( c->more() ){ BSONObj o = c->next(); BSONElement n = o["_id"]; BSONElement v = o["value"]; uassert( 10209 , "name has to be a string" , n.type() == String ); uassert( 10210 , "value has to be set" , v.type() != EOO ); setElement( n.valuestr() , v ); thisTime.insert( n.valuestr() ); _storedNames.insert( n.valuestr() ); } // --- remove things from scope that were removed list<string> toremove; for ( set<string>::iterator i=_storedNames.begin(); i!=_storedNames.end(); i++ ){ string n = *i; if ( thisTime.count( n ) == 0 ) toremove.push_back( n ); } for ( list<string>::iterator i=toremove.begin(); i!=toremove.end(); i++ ){ string n = *i; _storedNames.erase( n ); execSetup( (string)"delete " + n , "clean up scope" ); } } ScriptingFunction Scope::createFunction( const char * code ){ if ( code[0] == '/' && code [1] == '*' ){ code += 2; while ( code[0] && code[1] ){ if ( code[0] == '*' && code[1] == '/' ){ code += 2; break; } code++; } } map<string,ScriptingFunction>::iterator i = _cachedFunctions.find( code ); if ( i != _cachedFunctions.end() ) return i->second; ScriptingFunction f = _createFunction( code ); _cachedFunctions[code] = f; return f; } typedef map< string , list<Scope*> > PoolToScopes; class ScopeCache { public: ScopeCache(){ _magic = 17; } ~ScopeCache(){ assert( _magic == 17 ); _magic = 1; if ( inShutdown() ) return; clear(); } void done( const string& pool , Scope * s ){ scoped_lock lk( _mutex ); list<Scope*> & l = _pools[pool]; if ( l.size() > 10 ){ delete s; } else { l.push_back( s ); s->reset(); } } Scope * get( const string& pool ){ scoped_lock lk( _mutex ); list<Scope*> & l = _pools[pool]; if ( l.size() == 0 ) return 0; Scope * s = l.back(); l.pop_back(); s->reset(); return s; } void clear(){ set<Scope*> seen; for ( PoolToScopes::iterator i=_pools.begin() ; i != _pools.end(); i++ ){ for ( list<Scope*>::iterator j=i->second.begin(); j != i->second.end(); j++ ){ Scope * s = *j; assert( ! seen.count( s ) ); delete s; seen.insert( s ); } } _pools.clear(); } private: PoolToScopes _pools; mongo::mutex _mutex; int _magic; }; thread_specific_ptr<ScopeCache> scopeCache; class PooledScope : public Scope { public: PooledScope( const string pool , Scope * real ) : _pool( pool ) , _real( real ){ _real->loadStored( true ); }; virtual ~PooledScope(){ ScopeCache * sc = scopeCache.get(); if ( sc ){ sc->done( _pool , _real ); _real = 0; } else { log() << "warning: scopeCache is empty!" << endl; delete _real; _real = 0; } } void reset(){ _real->reset(); } void init( BSONObj * data ){ _real->init( data ); } void localConnect( const char * dbName ){ _real->localConnect( dbName ); } void externalSetup(){ _real->externalSetup(); } double getNumber( const char *field ){ return _real->getNumber( field ); } string getString( const char *field ){ return _real->getString( field ); } bool getBoolean( const char *field ){ return _real->getBoolean( field ); } BSONObj getObject( const char *field ){ return _real->getObject( field ); } int type( const char *field ){ return _real->type( field ); } void setElement( const char *field , const BSONElement& val ){ _real->setElement( field , val ); } void setNumber( const char *field , double val ){ _real->setNumber( field , val ); } void setString( const char *field , const char * val ){ _real->setString( field , val ); } void setObject( const char *field , const BSONObj& obj , bool readOnly=true ){ _real->setObject( field , obj , readOnly ); } void setBoolean( const char *field , bool val ){ _real->setBoolean( field , val ); } void setThis( const BSONObj * obj ){ _real->setThis( obj ); } ScriptingFunction createFunction( const char * code ){ return _real->createFunction( code ); } ScriptingFunction _createFunction( const char * code ){ return _real->createFunction( code ); } /** * @return 0 on success */ int invoke( ScriptingFunction func , const BSONObj& args, int timeoutMs , bool ignoreReturn ){ return _real->invoke( func , args , timeoutMs , ignoreReturn ); } string getError(){ return _real->getError(); } bool exec( const string& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ){ return _real->exec( code , name , printResult , reportError , assertOnError , timeoutMs ); } bool execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ){ return _real->execFile( filename , printResult , reportError , assertOnError , timeoutMs ); } void injectNative( const char *field, NativeFunction func ){ _real->injectNative( field , func ); } void gc(){ _real->gc(); } private: string _pool; Scope * _real; }; auto_ptr<Scope> ScriptEngine::getPooledScope( const string& pool ){ if ( ! scopeCache.get() ){ scopeCache.reset( new ScopeCache() ); } Scope * s = scopeCache->get( pool ); if ( ! s ){ s = newScope(); } auto_ptr<Scope> p; p.reset( new PooledScope( pool , s ) ); return p; } void ScriptEngine::threadDone(){ ScopeCache * sc = scopeCache.get(); if ( sc ){ sc->clear(); } } void ( *ScriptEngine::_connectCallback )( DBClientWithCommands & ) = 0; ScriptEngine * globalScriptEngine; bool hasJSReturn( const string& code ){ size_t x = code.find( "return" ); if ( x == string::npos ) return false; return ( x == 0 || ! isalpha( code[x-1] ) ) && ! isalpha( code[x+6] ); } }
CoreContext::~CoreContext(void) { // Evict from the parent's child list first, if we have a parent: if(m_pParent) { expiredContext(); // Also clear out any parent pointers: std::lock_guard<std::mutex> lk(m_pParent->m_stateBlock->m_lock); m_pParent->m_children.erase(m_backReference); } // The autoCurrentContext pointer holds a shared_ptr to this--if we're in a dtor, and our caller // still holds a reference to us, then we have a serious problem. assert( !autoCurrentContext.get() || !autoCurrentContext.get()->use_count() || autoCurrentContext.get()->get() != this ); // Notify all ContextMember instances that their parent is going away onTeardown(*this); // Tell all context members that we're tearing down: for(ContextMember* q : m_contextMembers) q->NotifyContextTeardown(); // Perform unlinking, if requested: if(m_unlinkOnTeardown) for (const auto& ccType : m_concreteTypes) { uint8_t* pBase = (uint8_t*)ccType.value.ptr(); // Enumerate all slots and unlink them one at a time for (auto cur = ccType.stump->pHead; cur; cur = cur->pFlink) { if (cur->autoRequired) // Only unlink slots that were Autowired. AutoRequired slots will never participate // in a cycle (because we would wind up with constructive chaos) so we don't really // need to worry about them. Furthermore, there are cases where users may want to // refer to a context member in their destructor; in that case, they should use // AutoRequired to enforce the relationship. continue; auto& slot = *reinterpret_cast<DeferrableAutowiring*>(pBase + cur->slotOffset); if (!slot.IsAutowired()) // Nothing to do here, just short-circuit continue; auto q = m_typeMemos.find(slot.GetType()); if (q == m_typeMemos.end()) // Weird. A slot is present on a member of this context, but the wired type doesn't // have a memo entry anywhere. continue; if (!q->second.m_local) // Entry exists, but was not locally satisfied. We can circle around. continue; // OK, interior pointer and context teardown is underway, clear it out slot.reset(); } } }
void CoreContext::EvictCurrent(void) { autoCurrentContext.reset(); }
restore_syscall_interruption(const disable_syscall_interruption &intr) { assert(_syscalls_interruptable.get() != NULL); last_value = *_syscalls_interruptable; *_syscalls_interruptable = intr.last_value; }
namespace mongo { // SERVER-4328 todo review for concurrency // :( thread_specific_ptr<DBClientBase> authConn_; /* Usage: * admindb.$cmd.findOne( { copydbgetnonce: 1, fromhost: <connection string> } ); * * Run against the mongod that is the intended target for the "copydb" command. Used to get a * nonce from the source of a "copydb" operation for authentication purposes. See the * description of the "copydb" command below. */ class CmdCopyDbGetNonce : public Command { public: CmdCopyDbGetNonce() : Command("copydbgetnonce") { } virtual bool adminOnly() const { return true; } virtual bool slaveOk() const { return false; } virtual bool isWriteCommandForConfigServer() const { return false; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { // No auth required } virtual void help( stringstream &help ) const { help << "get a nonce for subsequent copy db request from secure server\n"; help << "usage: {copydbgetnonce: 1, fromhost: <hostname>}"; } virtual bool run(OperationContext* txn, const string&, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string fromhost = cmdObj.getStringField("fromhost"); if ( fromhost.empty() ) { /* copy from self */ stringstream ss; ss << "localhost:" << serverGlobalParams.port; fromhost = ss.str(); } BSONObj ret; ConnectionString cs = ConnectionString::parse(fromhost, errmsg); if (!cs.isValid()) { return false; } authConn_.reset(cs.connect(errmsg)); if (!authConn_.get()) { return false; } if( !authConn_->runCommand( "admin", BSON( "getnonce" << 1 ), ret ) ) { errmsg = "couldn't get nonce " + ret.toString(); return false; } result.appendElements( ret ); return true; } } cmdCopyDBGetNonce; } // namespace mongo
namespace mongo { long long Scope::_lastVersion = 1; int Scope::_numScopes = 0; Scope::Scope() : _localDBName("") , _loadedVersion(0){ _numScopes++; } Scope::~Scope(){ _numScopes--; } ScriptEngine::ScriptEngine(){ } ScriptEngine::~ScriptEngine(){ } void Scope::append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName ){ int t = type( scopeName ); switch ( t ){ case Object: builder.append( fieldName , getObject( scopeName ) ); break; case Array: builder.appendArray( fieldName , getObject( scopeName ) ); break; case NumberDouble: builder.append( fieldName , getNumber( scopeName ) ); break; case NumberInt: builder.append( fieldName , getNumberInt( scopeName ) ); break; case NumberLong: builder.append( fieldName , getNumberLongLong( scopeName ) ); break; case String: builder.append( fieldName , getString( scopeName ).c_str() ); break; case Bool: builder.appendBool( fieldName , getBoolean( scopeName ) ); break; case jstNULL: case Undefined: builder.appendNull( fieldName ); break; case Date: builder.appendDate( fieldName , (unsigned long long) getNumber( scopeName ) ); break; default: stringstream temp; temp << "can't append type from:"; temp << t; uassert( temp.str() , 0 ); } } int Scope::invoke( const char* code , const BSONObj& args, int timeoutMs ){ ScriptingFunction func = createFunction( code ); uassert( "compile failed" , func ); return invoke( func , args, timeoutMs ); } bool Scope::execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs ){ path p( filename ); if ( ! exists( p ) ){ cout << "file [" << filename << "] doesn't exist" << endl; if ( assertOnError ) assert( 0 ); return false; } if ( is_directory( p ) ){ cout << "can't read directory [" << filename << "]" << endl; if ( assertOnError ) assert( 0 ); return false; } File f; f.open( filename.c_str() ); fileofs L = f.len(); assert( L <= 0x7ffffffe ); char * data = (char*)malloc( (size_t) L+1 ); data[L] = 0; f.read( 0 , data , (size_t) L ); return exec( data , filename , printResult , reportError , assertOnError, timeoutMs ); } void Scope::storedFuncMod(){ _lastVersion++; } void Scope::loadStored( bool ignoreNotConnected ){ if ( _localDBName.size() == 0 ){ if ( ignoreNotConnected ) return; uassert( "need to have locallyConnected already" , _localDBName.size() ); } if ( _loadedVersion == _lastVersion ) return; _loadedVersion = _lastVersion; static DBClientBase * db = createDirectClient(); auto_ptr<DBClientCursor> c = db->query( _localDBName + ".system.js" , Query() ); while ( c->more() ){ BSONObj o = c->next(); BSONElement n = o["_id"]; BSONElement v = o["value"]; uassert( "name has to be a string" , n.type() == String ); uassert( "value has to be set" , v.type() != EOO ); setElement( n.valuestr() , v ); } } ScriptingFunction Scope::createFunction( const char * code ){ if ( code[0] == '/' && code [1] == '*' ){ code += 2; while ( code[0] && code[1] ){ if ( code[0] == '*' && code[1] == '/' ){ code += 2; break; } code++; } } map<string,ScriptingFunction>::iterator i = _cachedFunctions.find( code ); if ( i != _cachedFunctions.end() ) return i->second; ScriptingFunction f = _createFunction( code ); _cachedFunctions[code] = f; return f; } typedef map< string , list<Scope*> > PoolToScopes; class ScopeCache { public: ScopeCache(){ _magic = 17; } ~ScopeCache(){ assert( _magic == 17 ); _magic = 1; if ( inShutdown() ) return; clear(); } void done( const string& pool , Scope * s ){ boostlock lk( _mutex ); list<Scope*> & l = _pools[pool]; if ( l.size() > 10 ){ delete s; } else { l.push_back( s ); s->reset(); } } Scope * get( const string& pool ){ boostlock lk( _mutex ); list<Scope*> & l = _pools[pool]; if ( l.size() == 0 ) return 0; Scope * s = l.back(); l.pop_back(); s->reset(); return s; } void clear(){ set<Scope*> seen; for ( PoolToScopes::iterator i=_pools.begin() ; i != _pools.end(); i++ ){ for ( list<Scope*>::iterator j=i->second.begin(); j != i->second.end(); j++ ){ Scope * s = *j; assert( ! seen.count( s ) ); delete s; seen.insert( s ); } } _pools.clear(); } private: PoolToScopes _pools; boost::mutex _mutex; int _magic; }; thread_specific_ptr<ScopeCache> scopeCache; class PooledScope : public Scope { public: PooledScope( const string pool , Scope * real ) : _pool( pool ) , _real( real ){ _real->loadStored( true ); }; virtual ~PooledScope(){ ScopeCache * sc = scopeCache.get(); if ( sc ){ sc->done( _pool , _real ); _real = 0; } else { log() << "warning: scopeCache is empty!" << endl; delete _real; _real = 0; } } void reset(){ _real->reset(); } void init( BSONObj * data ){ _real->init( data ); } void localConnect( const char * dbName ){ _real->localConnect( dbName ); } void externalSetup(){ _real->externalSetup(); } double getNumber( const char *field ){ return _real->getNumber( field ); } string getString( const char *field ){ return _real->getString( field ); } bool getBoolean( const char *field ){ return _real->getBoolean( field ); } BSONObj getObject( const char *field ){ return _real->getObject( field ); } int type( const char *field ){ return _real->type( field ); } void setElement( const char *field , const BSONElement& val ){ _real->setElement( field , val ); } void setNumber( const char *field , double val ){ _real->setNumber( field , val ); } void setString( const char *field , const char * val ){ _real->setString( field , val ); } void setObject( const char *field , const BSONObj& obj , bool readOnly=true ){ _real->setObject( field , obj , readOnly ); } void setBoolean( const char *field , bool val ){ _real->setBoolean( field , val ); } void setThis( const BSONObj * obj ){ _real->setThis( obj ); } ScriptingFunction createFunction( const char * code ){ return _real->createFunction( code ); } ScriptingFunction _createFunction( const char * code ){ return _real->createFunction( code ); } /** * @return 0 on success */ int invoke( ScriptingFunction func , const BSONObj& args, int timeoutMs , bool ignoreReturn ){ return _real->invoke( func , args , timeoutMs , ignoreReturn ); } string getError(){ return _real->getError(); } bool exec( const string& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ){ return _real->exec( code , name , printResult , reportError , assertOnError , timeoutMs ); } bool execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ){ return _real->execFile( filename , printResult , reportError , assertOnError , timeoutMs ); } void injectNative( const char *field, NativeFunction func ){ _real->injectNative( field , func ); } void gc(){ _real->gc(); } private: string _pool; Scope * _real; }; auto_ptr<Scope> ScriptEngine::getPooledScope( const string& pool ){ if ( ! scopeCache.get() ){ scopeCache.reset( new ScopeCache() ); } Scope * s = scopeCache->get( pool ); if ( ! s ){ s = createScope(); } auto_ptr<Scope> p; p.reset( new PooledScope( pool , s ) ); return p; } void ScriptEngine::threadDone(){ ScopeCache * sc = scopeCache.get(); if ( sc ){ sc->clear(); } } ScriptEngine * globalScriptEngine; }
namespace mongo { using std::string; using std::stringstream; // SERVER-4328 todo review for concurrency // :( thread_specific_ptr<DBClientBase> authConn_; /* Usage: * admindb.$cmd.findOne( { copydbgetnonce: 1, fromhost: <connection string> } ); * * Run against the mongod that is the intended target for the "copydb" command. Used to get a * nonce from the source of a "copydb" operation for authentication purposes. See the * description of the "copydb" command below. */ class CmdCopyDbGetNonce : public Command { public: CmdCopyDbGetNonce() : Command("copydbgetnonce") { } virtual bool adminOnly() const { return true; } virtual bool slaveOk() const { return false; } virtual bool isWriteCommandForConfigServer() const { return false; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { // No auth required } virtual void help( stringstream &help ) const { help << "get a nonce for subsequent copy db request from secure server\n"; help << "usage: {copydbgetnonce: 1, fromhost: <hostname>}"; } virtual bool run(OperationContext* txn, const string&, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result) { string fromhost = cmdObj.getStringField("fromhost"); if ( fromhost.empty() ) { /* copy from self */ stringstream ss; ss << "localhost:" << serverGlobalParams.port; fromhost = ss.str(); } const ConnectionString cs(uassertStatusOK(ConnectionString::parse(fromhost))); authConn_.reset(cs.connect(errmsg)); if (!authConn_.get()) { return false; } BSONObj ret; if( !authConn_->runCommand( "admin", BSON( "getnonce" << 1 ), ret ) ) { errmsg = "couldn't get nonce " + ret.toString(); return false; } result.appendElements( ret ); return true; } } cmdCopyDBGetNonce; /* Usage: * admindb.$cmd.findOne( { copydbsaslstart: 1, * fromhost: <connection string>, * mechanism: <String>, * payload: <BinaryOrString> } ); * * Run against the mongod that is the intended target for the "copydb" command. Used to * initialize a SASL auth session for a "copydb" operation for authentication purposes. */ class CmdCopyDbSaslStart : public Command { public: CmdCopyDbSaslStart() : Command("copydbsaslstart") { } virtual bool adminOnly() const { return true; } virtual bool slaveOk() const { return false; } virtual bool isWriteCommandForConfigServer() const { return false; } virtual Status checkAuthForCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { // No auth required return Status::OK(); } virtual void help( stringstream &help ) const { help << "Initialize a SASL auth session for subsequent copy db request " "from secure server\n"; } virtual bool run(OperationContext* txn, const string&, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result) { const string fromDb = cmdObj.getStringField("fromdb"); string fromHost = cmdObj.getStringField("fromhost"); if ( fromHost.empty() ) { /* copy from self */ stringstream ss; ss << "localhost:" << serverGlobalParams.port; fromHost = ss.str(); } const ConnectionString cs(uassertStatusOK(ConnectionString::parse(fromHost))); BSONElement mechanismElement; Status status = bsonExtractField(cmdObj, saslCommandMechanismFieldName, &mechanismElement); if (!status.isOK()) { return appendCommandStatus(result, status); } BSONElement payloadElement; status = bsonExtractField(cmdObj, saslCommandPayloadFieldName, &payloadElement); if (!status.isOK()) { log() << "Failed to extract payload: " << status; return false; } authConn_.reset(cs.connect(errmsg)); if (!authConn_.get()) { return false; } BSONObj ret; if( !authConn_->runCommand( fromDb, BSON( "saslStart" << 1 << mechanismElement << payloadElement), ret ) ) { return appendCommandStatus(result, Command::getStatusFromCommandResult(ret)); } result.appendElements( ret ); return true; } } cmdCopyDBSaslStart; } // namespace mongo
const std::shared_ptr<CoreContext>& CoreContext::CurrentContextOrNull(void) { static const std::shared_ptr<CoreContext> empty; auto retVal = autoCurrentContext.get(); return retVal ? *retVal : empty; }