mirror of https://gitee.com/bigwinds/arangodb
issue #150
This commit is contained in:
parent
fa5712005f
commit
a667f633d5
|
@ -1,5 +1,5 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief MR enigne configuration
|
||||
/// @brief MR engine configuration
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
|
@ -28,6 +28,8 @@
|
|||
#include "ApplicationMR.h"
|
||||
|
||||
#include "Basics/ConditionLocker.h"
|
||||
#include "Basics/ReadLocker.h"
|
||||
#include "Basics/WriteLocker.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "MRServer/mr-actions.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
@ -58,16 +60,42 @@ namespace {
|
|||
public:
|
||||
MRGcThread (ApplicationMR* applicationMR)
|
||||
: Thread("mr-gc"),
|
||||
_applicationMR(applicationMR) {
|
||||
_applicationMR(applicationMR),
|
||||
_lock(),
|
||||
_lastGcStamp(TRI_microtime()) {
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief collect garbage in an endless loop (main functon of GC thread)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void run () {
|
||||
_applicationMR->collectGarbage();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the timestamp of the last GC
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double getLastGcStamp () {
|
||||
READ_LOCKER(_lock);
|
||||
return _lastGcStamp;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the global GC timestamp
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void updateGcStamp (double value) {
|
||||
WRITE_LOCKER(_lock);
|
||||
}
|
||||
|
||||
private:
|
||||
ApplicationMR* _applicationMR;
|
||||
ReadWriteLock _lock;
|
||||
double _lastGcStamp;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -99,6 +127,7 @@ ApplicationMR::ApplicationMR (string const& binaryPath)
|
|||
_startupModules(),
|
||||
_actionPath(),
|
||||
_gcInterval(1000),
|
||||
_gcFrequency(10.0),
|
||||
_startupLoader(),
|
||||
_actionLoader(),
|
||||
_vocbase(0),
|
||||
|
@ -171,16 +200,25 @@ ApplicationMR::MRContext* ApplicationMR::enterContext () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ApplicationMR::exitContext (MRContext* context) {
|
||||
MRGcThread* gc = dynamic_cast<MRGcThread*>(_gcThread);
|
||||
assert(gc != 0);
|
||||
double lastGc = gc->getLastGcStamp();
|
||||
|
||||
++context->_dirt;
|
||||
|
||||
{
|
||||
CONDITION_LOCKER(guard, _contextCondition);
|
||||
|
||||
if (context->_dirt < _gcInterval) {
|
||||
_freeContexts.push_back(context);
|
||||
if (context->_lastGcStamp + _gcFrequency < lastGc) {
|
||||
LOGGER_TRACE << "periodic gc interval reached";
|
||||
_dirtyContexts.push_back(context);
|
||||
}
|
||||
else if (context->_dirt >= _gcInterval) {
|
||||
LOGGER_TRACE << "maximum number of requests reached";
|
||||
_dirtyContexts.push_back(context);
|
||||
}
|
||||
else {
|
||||
_dirtyContexts.push_back(context);
|
||||
_freeContexts.push_back(context);
|
||||
}
|
||||
|
||||
guard.broadcast();
|
||||
|
@ -194,28 +232,47 @@ void ApplicationMR::exitContext (MRContext* context) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ApplicationMR::collectGarbage () {
|
||||
MRGcThread* gc = dynamic_cast<MRGcThread*>(_gcThread);
|
||||
assert(gc != 0);
|
||||
uint64_t waitTime = (uint64_t) (_gcFrequency * 1000.0 * 1000.0);
|
||||
|
||||
while (_stopping == 0) {
|
||||
MRContext* context = 0;
|
||||
bool gotSignal = false;
|
||||
|
||||
{
|
||||
CONDITION_LOCKER(guard, _contextCondition);
|
||||
|
||||
if (_dirtyContexts.empty()) {
|
||||
guard.wait();
|
||||
gotSignal = guard.wait(waitTime);
|
||||
}
|
||||
|
||||
if (! _dirtyContexts.empty()) {
|
||||
context = _dirtyContexts.back();
|
||||
_dirtyContexts.pop_back();
|
||||
}
|
||||
|
||||
if (context == 0 && ! gotSignal) {
|
||||
// we did not find a dirty context
|
||||
// so we'll pop one of the free contexts and clean it up
|
||||
context = _freeContexts.back();
|
||||
if (context != 0) {
|
||||
_freeContexts.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update last gc time
|
||||
double lastGc = TRI_microtime();
|
||||
gc->updateGcStamp(lastGc);
|
||||
|
||||
if (context != 0) {
|
||||
LOGGER_TRACE << "collecting MR garbage";
|
||||
|
||||
// TODO
|
||||
|
||||
context->_dirt = 0;
|
||||
context->_lastGcStamp = lastGc;
|
||||
|
||||
{
|
||||
CONDITION_LOCKER(guard, _contextCondition);
|
||||
|
@ -254,7 +311,8 @@ void ApplicationMR::disableActions () {
|
|||
|
||||
void ApplicationMR::setupOptions (map<string, basics::ProgramOptionsDescription>& options) {
|
||||
options["RUBY Options:help-admin"]
|
||||
("ruby.gc-interval", &_gcInterval, "Ruby garbage collection interval (each x requests)")
|
||||
("ruby.gc-interval", &_gcInterval, "Ruby request-based garbage collection interval (each x requests)")
|
||||
("ruby.gc-frequency", &_gcFrequency, "Ruby time-based garbage collection frequency (each x seconds)")
|
||||
;
|
||||
|
||||
options["RUBY Options:help-admin"]
|
||||
|
@ -407,6 +465,8 @@ bool ApplicationMR::prepareMRInstance (size_t i) {
|
|||
}
|
||||
}
|
||||
|
||||
context->_lastGcStamp = TRI_microtime();
|
||||
|
||||
// and return from the context
|
||||
LOGGER_TRACE << "initialised MR context #" << i;
|
||||
|
||||
|
|
|
@ -89,7 +89,19 @@ namespace triagens {
|
|||
|
||||
struct MRContext {
|
||||
MR_state_t* _mrs;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief number of requests since last GC of the context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t _dirt;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief timestamp of last GC for the context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double _lastGcStamp;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -287,16 +299,28 @@ namespace triagens {
|
|||
string _actionPath;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief JavaScript garbage collection interval (each x requests)
|
||||
/// @brief MRuby garbage collection interval (each x requests)
|
||||
///
|
||||
/// @CMDOPT{--ruby.gc-interval @CA{interval}}
|
||||
///
|
||||
/// Specifies the interval (approximately in number of requests) that the
|
||||
/// garbage collection for JavaScript objects will be run in each thread.
|
||||
/// garbage collection for MRuby objects will be run in each thread.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t _gcInterval;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief MRuby garbage collection frequency (each x seconds)
|
||||
///
|
||||
/// @CMDOPT{--ruby.gc-frequency @CA{frequency}}
|
||||
///
|
||||
/// Specifies the frequency in seconds for the automatic garbage collection of
|
||||
/// MRuby objects. This setting is useful to have the garbage collection
|
||||
/// still work in periods with no or little numbers of requests.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double _gcFrequency;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief MR startup loader
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief V8 enigne configuration
|
||||
/// @brief V8 engine configuration
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
|
@ -28,6 +28,8 @@
|
|||
#include "ApplicationV8.h"
|
||||
|
||||
#include "Basics/ConditionLocker.h"
|
||||
#include "Basics/ReadLocker.h"
|
||||
#include "Basics/WriteLocker.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "V8/v8-conv.h"
|
||||
#include "V8/v8-shell.h"
|
||||
|
@ -65,16 +67,43 @@ namespace {
|
|||
public:
|
||||
V8GcThread (ApplicationV8* applicationV8)
|
||||
: Thread("v8-gc"),
|
||||
_applicationV8(applicationV8) {
|
||||
_applicationV8(applicationV8),
|
||||
_lock(),
|
||||
_lastGcStamp(TRI_microtime()) {
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief collect garbage in an endless loop (main functon of GC thread)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void run () {
|
||||
_applicationV8->collectGarbage();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the timestamp of the last GC
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double getLastGcStamp () {
|
||||
READ_LOCKER(_lock);
|
||||
return _lastGcStamp;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the global GC timestamp
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void updateGcStamp (double value) {
|
||||
WRITE_LOCKER(_lock);
|
||||
_lastGcStamp = value;
|
||||
}
|
||||
|
||||
private:
|
||||
ApplicationV8* _applicationV8;
|
||||
ReadWriteLock _lock;
|
||||
double _lastGcStamp;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -107,6 +136,7 @@ ApplicationV8::ApplicationV8 (string const& binaryPath)
|
|||
_actionPath(),
|
||||
_useActions(true),
|
||||
_gcInterval(1000),
|
||||
_gcFrequency(10.0),
|
||||
_startupLoader(),
|
||||
_actionLoader(),
|
||||
_vocbase(0),
|
||||
|
@ -183,20 +213,29 @@ ApplicationV8::V8Context* ApplicationV8::enterContext () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ApplicationV8::exitContext (V8Context* context) {
|
||||
V8GcThread* gc = dynamic_cast<V8GcThread*>(_gcThread);
|
||||
assert(gc != 0);
|
||||
double lastGc = gc->getLastGcStamp();
|
||||
|
||||
context->_context->Exit();
|
||||
context->_isolate->Exit();
|
||||
delete context->_locker;
|
||||
|
||||
|
||||
++context->_dirt;
|
||||
|
||||
{
|
||||
CONDITION_LOCKER(guard, _contextCondition);
|
||||
|
||||
if (context->_dirt < _gcInterval) {
|
||||
_freeContexts.push_back(context);
|
||||
if (context->_lastGcStamp + _gcFrequency < lastGc) {
|
||||
LOGGER_TRACE << "periodic gc interval reached";
|
||||
_dirtyContexts.push_back(context);
|
||||
}
|
||||
else if (context->_dirt >= _gcInterval) {
|
||||
LOGGER_TRACE << "maximum number of requests reached";
|
||||
_dirtyContexts.push_back(context);
|
||||
}
|
||||
else {
|
||||
_dirtyContexts.push_back(context);
|
||||
_freeContexts.push_back(context);
|
||||
}
|
||||
|
||||
guard.broadcast();
|
||||
|
@ -210,21 +249,39 @@ void ApplicationV8::exitContext (V8Context* context) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ApplicationV8::collectGarbage () {
|
||||
V8GcThread* gc = dynamic_cast<V8GcThread*>(_gcThread);
|
||||
assert(gc != 0);
|
||||
uint64_t waitTime = (uint64_t) (_gcFrequency * 1000.0 * 1000.0);
|
||||
|
||||
while (_stopping == 0) {
|
||||
V8Context* context = 0;
|
||||
bool gotSignal = false;
|
||||
|
||||
{
|
||||
CONDITION_LOCKER(guard, _contextCondition);
|
||||
|
||||
if (_dirtyContexts.empty()) {
|
||||
guard.wait();
|
||||
gotSignal = guard.wait(waitTime);
|
||||
}
|
||||
|
||||
if (! _dirtyContexts.empty()) {
|
||||
context = _dirtyContexts.back();
|
||||
_dirtyContexts.pop_back();
|
||||
}
|
||||
|
||||
if (context == 0 && ! gotSignal) {
|
||||
// we did not find a dirty context
|
||||
// so we'll pop one of the free contexts and clean it up
|
||||
context = _freeContexts.back();
|
||||
if (context != 0) {
|
||||
_freeContexts.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update last gc time
|
||||
double lastGc = TRI_microtime();
|
||||
gc->updateGcStamp(lastGc);
|
||||
|
||||
if (context != 0) {
|
||||
LOGGER_TRACE << "collecting V8 garbage";
|
||||
|
@ -241,6 +298,7 @@ void ApplicationV8::collectGarbage () {
|
|||
delete context->_locker;
|
||||
|
||||
context->_dirt = 0;
|
||||
context->_lastGcStamp = lastGc;
|
||||
|
||||
{
|
||||
CONDITION_LOCKER(guard, _contextCondition);
|
||||
|
@ -279,7 +337,8 @@ void ApplicationV8::disableActions () {
|
|||
|
||||
void ApplicationV8::setupOptions (map<string, basics::ProgramOptionsDescription>& options) {
|
||||
options["JAVASCRIPT Options:help-admin"]
|
||||
("javascript.gc-interval", &_gcInterval, "JavaScript garbage collection interval (each x requests)")
|
||||
("javascript.gc-interval", &_gcInterval, "JavaScript request-based garbage collection interval (each x requests)")
|
||||
("javascript.gc-frequency", &_gcFrequency, "JavaScript time-based garbage collection frequency (each x seconds)")
|
||||
;
|
||||
|
||||
options["JAVASCRIPT Options:help-admin"]
|
||||
|
@ -475,6 +534,8 @@ bool ApplicationV8::prepareV8Instance (size_t i) {
|
|||
context->_context->Exit();
|
||||
context->_isolate->Exit();
|
||||
delete context->_locker;
|
||||
|
||||
context->_lastGcStamp = TRI_microtime();
|
||||
|
||||
LOGGER_TRACE << "initialised V8 context #" << i;
|
||||
|
||||
|
|
|
@ -91,7 +91,19 @@ namespace triagens {
|
|||
v8::Persistent<v8::Context> _context;
|
||||
v8::Isolate* _isolate;
|
||||
v8::Locker* _locker;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief number of requests since last GC of the context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t _dirt;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief timestamp of last GC for the context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double _lastGcStamp;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -305,6 +317,18 @@ namespace triagens {
|
|||
|
||||
uint64_t _gcInterval;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief JavaScript garbage collection frequency (each x seconds)
|
||||
///
|
||||
/// @CMDOPT{--javascript.gc-frequency @CA{frequency}}
|
||||
///
|
||||
/// Specifies the frequency in seconds for the automatic garbage collection of
|
||||
/// JavaScript objects. This setting is useful to have the garbage collection
|
||||
/// still work in periods with no or little numbers of requests.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double _gcFrequency;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief V8 startup loader
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -95,6 +95,14 @@ void ConditionLocker::wait () {
|
|||
_conditionVariable->wait();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief waits for an event to occur, with a timeout
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool ConditionLocker::wait (uint64_t delay) {
|
||||
return _conditionVariable->wait(delay);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief broadcasts an event
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -138,6 +138,12 @@ namespace triagens {
|
|||
|
||||
void wait ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief waits for an event to occur, using a timeout
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool wait (uint64_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief broadcasts an event
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue