1
0
Fork 0

Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel

This commit is contained in:
Oreste Panaia 2012-09-05 16:30:16 +08:00
commit fcc5e20a1a
1 changed files with 256 additions and 0 deletions

256
Documentation/issue188.diff Normal file
View File

@ -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
////////////////////////////////////////////////////////////////////////////////