mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel
This commit is contained in:
commit
fcc5e20a1a
|
@ -0,0 +1,256 @@
|
|||
diff --git a/arangod/V8Server/ApplicationV8.cpp b/arangod/V8Server/ApplicationV8.cpp
|
||||
index e1b246d..c381f4e 100644
|
||||
--- a/arangod/V8Server/ApplicationV8.cpp
|
||||
+++ b/arangod/V8Server/ApplicationV8.cpp
|
||||
@@ -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,21 +213,30 @@ 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 {
|
||||
+ else if (context->_dirt >= _gcInterval) {
|
||||
+ LOGGER_TRACE << "maximum number of requests reached";
|
||||
_dirtyContexts.push_back(context);
|
||||
}
|
||||
+ else {
|
||||
+ _freeContexts.push_back(context);
|
||||
+ }
|
||||
|
||||
guard.broadcast();
|
||||
}
|
||||
@@ -210,21 +249,40 @@ 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();
|
||||
+ // check whether we got a wait timeout or a signal
|
||||
+ gotSignal = guard.wait(waitTime);
|
||||
}
|
||||
|
||||
if (! _dirtyContexts.empty()) {
|
||||
context = _dirtyContexts.back();
|
||||
_dirtyContexts.pop_back();
|
||||
}
|
||||
+
|
||||
+ if (context == 0 && ! gotSignal && ! _freeContexts.empty()) {
|
||||
+ // we timed out waiting for a signal
|
||||
+ // so we'll pop one of the free contexts and clean it up pro-actively
|
||||
+ 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 +299,7 @@ void ApplicationV8::collectGarbage () {
|
||||
delete context->_locker;
|
||||
|
||||
context->_dirt = 0;
|
||||
+ context->_lastGcStamp = lastGc;
|
||||
|
||||
{
|
||||
CONDITION_LOCKER(guard, _contextCondition);
|
||||
@@ -279,7 +338,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 +535,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;
|
||||
|
||||
diff --git a/arangod/V8Server/ApplicationV8.h b/arangod/V8Server/ApplicationV8.h
|
||||
index a4fa6bd..e91304d 100644
|
||||
--- a/arangod/V8Server/ApplicationV8.h
|
||||
+++ b/arangod/V8Server/ApplicationV8.h
|
||||
@@ -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;
|
||||
+
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -306,6 +318,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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
diff --git a/lib/Basics/ConditionLocker.cpp b/lib/Basics/ConditionLocker.cpp
|
||||
index e9469e6..097ef7b 100644
|
||||
--- a/lib/Basics/ConditionLocker.cpp
|
||||
+++ b/lib/Basics/ConditionLocker.cpp
|
||||
@@ -96,6 +96,14 @@ void ConditionLocker::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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
diff --git a/lib/Basics/ConditionLocker.h b/lib/Basics/ConditionLocker.h
|
||||
index 4114fe3..543f389 100644
|
||||
--- a/lib/Basics/ConditionLocker.h
|
||||
+++ b/lib/Basics/ConditionLocker.h
|
||||
@@ -139,6 +139,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