diff options
| author | Laszlo Boszormenyi (GCS) <gcs@debian.org> | 2014-04-27 21:49:01 +0200 |
|---|---|---|
| committer | Laszlo Boszormenyi (GCS) <gcs@debian.org> | 2014-04-27 21:49:01 +0200 |
| commit | 547377230880c8e9def9ee9458ae69d298918467 (patch) | |
| tree | 2cb8394f8eb02c2499581cc1afd25d2929571983 /src/mongo/scripting/engine.cpp | |
| parent | 65585c90b12d6523bea75a2aebaae2a2fdf9e641 (diff) | |
Imported Upstream version 2.4.9upstream/2.4.9
Diffstat (limited to 'src/mongo/scripting/engine.cpp')
| -rw-r--r-- | src/mongo/scripting/engine.cpp | 135 |
1 files changed, 59 insertions, 76 deletions
diff --git a/src/mongo/scripting/engine.cpp b/src/mongo/scripting/engine.cpp index fc4d042c2af..e6bb8be819e 100644 --- a/src/mongo/scripting/engine.cpp +++ b/src/mongo/scripting/engine.cpp @@ -39,7 +39,7 @@ namespace mongo { Scope::Scope() : _localDBName(""), _loadedVersion(0), - _numTimeUsed(0), + _numTimesUsed(0), _lastRetIsNativeCode(false) { } @@ -259,90 +259,80 @@ namespace mongo { injectNative("benchFinish", BenchRunner::benchFinish); } - typedef map<string, list<Scope*> > PoolToScopes; - +namespace { class ScopeCache { public: - ScopeCache() : _mutex("ScopeCache") { - } + ScopeCache() : _mutex("ScopeCache") {} - ~ScopeCache() { - if (inShutdown()) - return; - clear(); - } - - void done(const string& pool, Scope* s) { + void release(const string& poolName, const boost::shared_ptr<Scope>& scope) { 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 (scope->hasOutOfMemoryException()) { + // make some room + log() << "Clearing all idle JS contexts due to out of memory" << endl; + _pools.clear(); + return; } - if (oom) { - // out of mem, make some room - log() << "Clearing all idle JS contexts due to out of memory" << endl; - clear(); + if (scope->getTimesUsed() > kMaxScopeReuse) + return; // used too many times to save + + if (!scope->getError().empty()) + return; // not saving errored scopes + + if (_pools.size() >= kMaxPoolSize) { + // prefer to keep recently-used scopes + _pools.pop_back(); } + + ScopeAndPool toStore = {scope, poolName}; + _pools.push_front(toStore); } - Scope* get(const string& pool) { + boost::shared_ptr<Scope> tryAcquire(const string& poolName) { 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; + for (Pools::iterator it = _pools.begin(); it != _pools.end(); ++it) { + if (it->poolName == poolName) { + boost::shared_ptr<Scope> scope = it->scope; + _pools.erase(it); + scope->incTimesUsed(); + scope->reset(); + return scope; } } - _pools.clear(); + + return boost::shared_ptr<Scope>(); } private: - PoolToScopes _pools; + struct ScopeAndPool { + boost::shared_ptr<Scope> scope; + string poolName; + }; + + // Note: if these numbers change, reconsider choice of datastructure for _pools + static const unsigned kMaxPoolSize = 10; + static const int kMaxScopeReuse = 10; + + typedef deque<ScopeAndPool> Pools; // More-recently used Scopes are kept at the front. + Pools _pools; // protected by _mutex mongo::mutex _mutex; }; - thread_specific_ptr<ScopeCache> scopeCache; + ScopeCache scopeCache; +} // anonymous namespace class PooledScope : public Scope { public: - PooledScope(const std::string& pool, Scope* real) : _pool(pool), _real(real) { + PooledScope(const std::string& pool, const boost::shared_ptr<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; - } + scopeCache.release(_pool, _real); } // wrappers for the derived (_real) scope @@ -404,31 +394,24 @@ namespace mongo { private: string _pool; - Scope* _real; + boost::shared_ptr<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> ScriptEngine::getPooledScope(const string& db, const string& scopeType) { + const string fullPoolName = db + scopeType; + boost::shared_ptr<Scope> s = scopeCache.tryAcquire(fullPoolName); + if (!s) { + s.reset(newScope()); + } auto_ptr<Scope> p; - p.reset(new PooledScope(pool + scopeType, s)); - p->setLocalDB(pool); + p.reset(new PooledScope(fullPoolName, s)); + p->setLocalDB(db); 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; |
