summaryrefslogtreecommitdiff
path: root/src/mongo/scripting/engine.cpp
diff options
context:
space:
mode:
authorLaszlo Boszormenyi (GCS) <gcs@debian.org>2014-04-27 21:49:01 +0200
committerLaszlo Boszormenyi (GCS) <gcs@debian.org>2014-04-27 21:49:01 +0200
commit547377230880c8e9def9ee9458ae69d298918467 (patch)
tree2cb8394f8eb02c2499581cc1afd25d2929571983 /src/mongo/scripting/engine.cpp
parent65585c90b12d6523bea75a2aebaae2a2fdf9e641 (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.cpp135
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;