1
0
Fork 0
arangodb/Documentation/issue188.diff

2058 lines
78 KiB
Diff

diff --git a/arangod/Ahuacatl/ahuacatl-codegen.c b/arangod/Ahuacatl/ahuacatl-codegen.c
index 737ea0f..f390315 100644
--- a/arangod/Ahuacatl/ahuacatl-codegen.c
+++ b/arangod/Ahuacatl/ahuacatl-codegen.c
@@ -2253,9 +2253,12 @@ char* TRI_GenerateCodeAql (TRI_aql_context_t* const context) {
char* code;
assert(context);
+
+ TRI_AQL_LOG("generating code");
generator = CreateGenerator(context);
if (generator == NULL) {
+ TRI_AQL_LOG("could not create code generator");
return NULL;
}
@@ -2272,6 +2275,7 @@ char* TRI_GenerateCodeAql (TRI_aql_context_t* const context) {
OutputString(&generator->_buffer, "})()");
if (generator->_error) {
+ TRI_AQL_LOG("generating code failed");
FreeGenerator(generator);
return NULL;
@@ -2283,9 +2287,11 @@ char* TRI_GenerateCodeAql (TRI_aql_context_t* const context) {
FreeGenerator(generator);
if (code) {
- TRI_AQL_DUMP("generated code: %s\n", code);
+ TRI_AQL_LOG("generated code: %s\n", code);
}
+ TRI_AQL_LOG("generating code successful");
+
return code;
}
diff --git a/arangod/Ahuacatl/ahuacatl-collections.c b/arangod/Ahuacatl/ahuacatl-collections.c
index 3113434..4d63eb8 100644
--- a/arangod/Ahuacatl/ahuacatl-collections.c
+++ b/arangod/Ahuacatl/ahuacatl-collections.c
@@ -399,15 +399,19 @@ bool TRI_ReadLockCollectionsAql (TRI_aql_context_t* const context) {
TRI_AQL_LOG("read-locking collection '%s'", collection->_name);
+ LOG_TRACE("before beginRead");
lockResult = documentCollection->beginRead(documentCollection);
+ LOG_TRACE("after beginRead");
if (lockResult != TRI_ERROR_NO_ERROR) {
// couldn't acquire the read lock
+ LOG_WARNING("read-locking collection '%s' failed", collection->_name);
result = false;
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_COLLECTION_LOCK_FAILED, collection->_name);
break;
}
else {
collection->_readLocked = true;
+ TRI_AQL_LOG("read-locked collection '%s'", collection->_name);
}
}
@@ -447,7 +451,9 @@ void TRI_ReadUnlockCollectionsAql (TRI_aql_context_t* const context) {
TRI_AQL_LOG("read-unlocking collection '%s'", collection->_name);
+ LOG_TRACE("before endRead");
documentCollection->endRead(documentCollection);
+ LOG_TRACE("after endRead");
collection->_readLocked = false;
}
}
@@ -484,6 +490,7 @@ bool TRI_AddBarrierCollectionsAql (TRI_aql_context_t* const context) {
if (!ce) {
// couldn't create the barrier
result = false;
+ LOG_WARNING("adding barrier for collection '%s' failed", collection->_name);
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL);
break;
}
diff --git a/arangod/Ahuacatl/ahuacatl-context.c b/arangod/Ahuacatl/ahuacatl-context.c
index b4a426c..b5e107a 100644
--- a/arangod/Ahuacatl/ahuacatl-context.c
+++ b/arangod/Ahuacatl/ahuacatl-context.c
@@ -279,21 +279,30 @@ void TRI_FreeContextAql (TRI_aql_context_t* const context) {
////////////////////////////////////////////////////////////////////////////////
bool TRI_ValidateQueryContextAql (TRI_aql_context_t* const context) {
+ TRI_AQL_LOG("validating query context");
+
if (context->_parser->_length == 0) {
// query is empty, no need to parse it
+ TRI_AQL_LOG("validating query context failed");
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_EMPTY, NULL);
return false;
}
+
+ TRI_AQL_LOG("validating query context parse");
// parse the query
if (!TRI_ParseAql(context)) {
// lexing/parsing failed
+ TRI_AQL_LOG("validating query context parse failed");
return false;
}
if (context->_error._code) {
+ TRI_AQL_LOG("validating query context failed with error %d", (int) context->_error._code);
return false;
}
+
+ TRI_AQL_LOG("validating query context successful");
return true;
}
@@ -335,19 +344,26 @@ bool TRI_BindQueryContextAql (TRI_aql_context_t* const context,
////////////////////////////////////////////////////////////////////////////////
bool TRI_OptimiseQueryContextAql (TRI_aql_context_t* const context) {
+ TRI_AQL_LOG("performing query optimisations");
+
// do some basic optimisations in the AST
if (!TRI_OptimiseAql(context)) {
- // constant folding failed
+ // optimisations failed
+ TRI_AQL_LOG("performing query optimisations failed");
+
return false;
}
if (context->_error._code) {
+ TRI_AQL_LOG("performing query optimisations failed with error code %d", (int) context->_error._code);
return false;
}
+ TRI_AQL_LOG("performing query optimisations compacting");
TRI_CompactStatementListAql(context->_statements);
+ TRI_AQL_LOG("performing query optimisations compacting successful");
- // TRI_DumpStatementsAql(context->_statements);
+ TRI_AQL_LOG("performing query optimisations successful");
return true;
}
@@ -357,24 +373,35 @@ bool TRI_OptimiseQueryContextAql (TRI_aql_context_t* const context) {
////////////////////////////////////////////////////////////////////////////////
bool TRI_LockQueryContextAql (TRI_aql_context_t* const context) {
+ TRI_AQL_LOG("performing query locking");
+
// mark all used collections as being used
if (!TRI_LockCollectionsAql(context)) {
return false;
}
+ TRI_AQL_LOG("performing query locking read");
+
// acquire read locks on all collections used
if (!TRI_ReadLockCollectionsAql(context)) {
+ TRI_AQL_LOG("performing query locking read failed");
return false;
}
+ TRI_AQL_LOG("performing query locking barrier");
+
// add barriers for all collections used
if (!TRI_AddBarrierCollectionsAql(context)) {
+ TRI_AQL_LOG("performing query locking barrier failed");
return false;
}
if (context->_error._code) {
+ TRI_AQL_LOG("performing query locking failed with error code %d", (int) context->_error._code);
return false;
}
+
+ TRI_AQL_LOG("performing query locking successful");
return true;
}
diff --git a/arangod/Ahuacatl/ahuacatl-log.h b/arangod/Ahuacatl/ahuacatl-log.h
index f8e92b7..aa5cf5e 100644
--- a/arangod/Ahuacatl/ahuacatl-log.h
+++ b/arangod/Ahuacatl/ahuacatl-log.h
@@ -35,7 +35,7 @@ extern "C" {
#endif
#undef TRI_DEBUG_AQL
-//#define TRI_DEBUG_AQL 1
+#define TRI_DEBUG_AQL 1
// -----------------------------------------------------------------------------
// --SECTION-- public macros
@@ -52,10 +52,8 @@ extern "C" {
#ifdef TRI_DEBUG_AQL
#define TRI_AQL_LOG(...) LOG_INFO(__VA_ARGS__);
-#define TRI_AQL_DUMP(format, ...) printf(format, __VA_ARGS__);
#else
#define TRI_AQL_LOG(...) LOG_TRACE(__VA_ARGS__);
-#define TRI_AQL_DUMP(...) { };
#endif
////////////////////////////////////////////////////////////////////////////////
diff --git a/arangod/Ahuacatl/ahuacatl-optimiser.c b/arangod/Ahuacatl/ahuacatl-optimiser.c
index 49437aa..43d905b 100644
--- a/arangod/Ahuacatl/ahuacatl-optimiser.c
+++ b/arangod/Ahuacatl/ahuacatl-optimiser.c
@@ -1076,14 +1076,22 @@ static bool DetermineIndexes (TRI_aql_context_t* const context) {
////////////////////////////////////////////////////////////////////////////////
bool TRI_OptimiseAql (TRI_aql_context_t* const context) {
+ LOG_TRACE("optimising");
+
+ LOG_TRACE("optimising AST");
if (!OptimiseAst(context)) {
+ LOG_TRACE("optimising AST failed");
return false;
}
+ LOG_TRACE("determining indexes");
if (!DetermineIndexes(context)) {
+ LOG_TRACE("determining indexes failed");
return false;
}
+ LOG_TRACE("optimising successful");
+
return true;
}
diff --git a/arangod/RestHandler/RestDocumentHandler.cpp b/arangod/RestHandler/RestDocumentHandler.cpp
index e8fb467..026654d 100644
--- a/arangod/RestHandler/RestDocumentHandler.cpp
+++ b/arangod/RestHandler/RestDocumentHandler.cpp
@@ -270,13 +270,18 @@ bool RestDocumentHandler::createDocument () {
// inside write transaction
// .............................................................................
- _documentCollection->beginWrite(_documentCollection);
+ LOG_TRACE("before beginWrite");
+ int lockResult = _documentCollection->beginWrite(_documentCollection);
+ LOG_TRACE("after beginWrite");
+ LOGGER_TRACE << "result of beginWrite: " << lockResult;
bool waitForSync = _documentCollection->base._waitForSync;
TRI_voc_cid_t cid = _documentCollection->base._cid;
// note: unlocked is performed by createJson()
+ LOGGER_TRACE << "creating document";
TRI_doc_mptr_t const mptr = _documentCollection->createJson(_documentCollection, TRI_DOC_MARKER_DOCUMENT, json, 0, reuseId, true);
+ LOGGER_TRACE << "finished creating document";
// .............................................................................
// outside write transaction
@@ -284,6 +289,7 @@ bool RestDocumentHandler::createDocument () {
// release collection and free json
releaseCollection();
+ LOGGER_TRACE << "released collection again";
// generate result
if (mptr._did != 0) {
@@ -415,12 +421,17 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) {
// inside read transaction
// .............................................................................
- _documentCollection->beginRead(_documentCollection);
+ LOG_TRACE("before beginRead");
+ int lockResult = _documentCollection->beginRead(_documentCollection);
+ LOG_TRACE("after beginRead");
+ LOGGER_TRACE << "result of beginRead: " << lockResult;
TRI_voc_cid_t cid = _documentCollection->base._cid;
TRI_doc_mptr_t const document = findDocument(did);
+ LOG_TRACE("before endRead");
_documentCollection->endRead(_documentCollection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside read transaction
@@ -511,7 +522,10 @@ bool RestDocumentHandler::readAllDocuments () {
vector<TRI_voc_did_t> ids;
- _documentCollection->beginRead(_documentCollection);
+ LOG_DEBUG("before beginRead");
+ int lockResult = _documentCollection->beginRead(_documentCollection);
+ LOG_DEBUG("after beginRead");
+ LOGGER_TRACE << "result of beginRead: " << lockResult;
TRI_voc_cid_t cid = _documentCollection->base._cid;
@@ -537,7 +551,9 @@ bool RestDocumentHandler::readAllDocuments () {
// necessary so we will always remove the read lock
}
+ LOG_TRACE("before endRead");
_documentCollection->endRead(_documentCollection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside read transaction
@@ -715,7 +731,10 @@ bool RestDocumentHandler::updateDocument () {
// inside write transaction
// .............................................................................
- _documentCollection->beginWrite(_documentCollection);
+ LOG_DEBUG("before beginWrite");
+ int lockResult = _documentCollection->beginWrite(_documentCollection);
+ LOG_DEBUG("after beginWrite");
+ LOGGER_TRACE << "result of beginWrite: " << lockResult;
// unlocking is performed in updateJson()
TRI_voc_rid_t rid = 0;
@@ -860,7 +879,10 @@ bool RestDocumentHandler::deleteDocument () {
// inside write transaction
// .............................................................................
- _documentCollection->beginWrite(_documentCollection);
+ LOG_TRACE("before beginWrite");
+ int lockResult = _documentCollection->beginWrite(_documentCollection);
+ LOG_TRACE("after beginWrite");
+ LOGGER_TRACE << "result of beginWrite: " << lockResult;
TRI_voc_rid_t rid = 0;
TRI_voc_cid_t cid = _documentCollection->base._cid;
diff --git a/arangod/RestHandler/RestVocbaseBaseHandler.cpp b/arangod/RestHandler/RestVocbaseBaseHandler.cpp
index de40357..6e04545 100644
--- a/arangod/RestHandler/RestVocbaseBaseHandler.cpp
+++ b/arangod/RestHandler/RestVocbaseBaseHandler.cpp
@@ -600,7 +600,9 @@ TRI_doc_mptr_t const RestVocbaseBaseHandler::findDocument (string const& doc) {
// inside read transaction
// .............................................................................
+ LOG_TRACE("before beginRead");
_documentCollection->beginRead(_documentCollection);
+ LOG_TRACE("after beginRead");
document = _documentCollection->read(_documentCollection, id);
@@ -609,7 +611,9 @@ TRI_doc_mptr_t const RestVocbaseBaseHandler::findDocument (string const& doc) {
_barrier = TRI_CreateBarrierElement(&_documentCollection->_barrierList);
}
+ LOG_TRACE("before endRead");
_documentCollection->endRead(_documentCollection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside read transaction
diff --git a/arangod/V8Server/ApplicationV8.cpp b/arangod/V8Server/ApplicationV8.cpp
index d200d55..80185d3 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;
};
}
@@ -106,6 +135,7 @@ ApplicationV8::ApplicationV8 (string const& binaryPath)
_startupModules("js/modules"),
_actionPath(),
_gcInterval(1000),
+ _gcFrequency(10.0),
_startupLoader(),
_actionLoader(),
_vocbase(0),
@@ -230,21 +260,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();
}
@@ -253,25 +292,112 @@ void ApplicationV8::exitContext (V8Context* context) {
}
////////////////////////////////////////////////////////////////////////////////
+/// @brief determine which of the free contexts should be picked for the GC
+////////////////////////////////////////////////////////////////////////////////
+
+ApplicationV8::V8Context* ApplicationV8::pickContextForGc () {
+ size_t n = _freeContexts.size();
+
+ if (n == 0) {
+ // this is easy...
+ return 0;
+ }
+
+ V8GcThread* gc = dynamic_cast<V8GcThread*>(_gcThread);
+ V8Context* context = 0;
+
+ // we got more than 1 context to clean up, pick the one with the "oldest" GC stamp
+ size_t pickedContextNr = 0; // index of context with lowest GC stamp
+
+ for (size_t i = 0; i < n; ++i) {
+ // compare last GC stamp
+ if (_freeContexts[i]->_lastGcStamp <= _freeContexts[pickedContextNr]->_lastGcStamp) {
+ pickedContextNr = i;
+ }
+ }
+ // we now have the context to clean up in pickedContextNr
+
+ // this is the context to clean up
+ context = _freeContexts[pickedContextNr];
+ assert(context != 0);
+
+ // now compare its last GC timestamp with the last global GC stamp
+ if (context->_lastGcStamp + _gcFrequency >= gc->getLastGcStamp()) {
+ // no need yet to clean up the context
+ return 0;
+ }
+
+ // we'll pop the context from the vector. the context might be at any position in the vector
+ // so we need to move the other elements around
+ if (n > 1) {
+ for (size_t i = pickedContextNr; i < n - 1; ++i) {
+ _freeContexts[i] = _freeContexts[i + 1];
+ }
+ }
+ _freeContexts.pop_back();
+
+ return context;
+}
+
+////////////////////////////////////////////////////////////////////////////////
/// @brief runs the garbage collection
////////////////////////////////////////////////////////////////////////////////
void ApplicationV8::collectGarbage () {
+ V8GcThread* gc = dynamic_cast<V8GcThread*>(_gcThread);
+ assert(gc != 0);
+
+ // this flag will be set to true if we timed out waiting for a GC signal
+ // if set to true, the next cycle will use a reduced wait time so the GC
+ // can be performed more early for all dirty contexts. The flag is set
+ // to false again once all contexts have been cleaned up and there is nothing
+ // more to do
+ bool useReducedWait = false;
+
+ // the time we'll wait for a signal
+ uint64_t regularWaitTime = (uint64_t) (_gcFrequency * 1000.0 * 1000.0);
+
+ // the time we'll wait for a signal when the previous wait timed out
+ uint64_t reducedWaitTime = (uint64_t) (_gcFrequency * 1000.0 * 100.0);
+
while (_stopping == 0) {
V8Context* context = 0;
+ bool gotSignal = false;
{
CONDITION_LOCKER(guard, _contextCondition);
if (_dirtyContexts.empty()) {
- guard.wait();
+ uint64_t waitTime = useReducedWait ? reducedWaitTime : regularWaitTime;
+ // we'll wait for a signal or a timeout
+ gotSignal = guard.wait(waitTime);
+
+ // use a reduced wait time in the next round because we seem to be idle
+ // the reduced wait time will allow use to perfom GC for more contexts
+ useReducedWait = ! gotSignal;
}
if (! _dirtyContexts.empty()) {
context = _dirtyContexts.back();
_dirtyContexts.pop_back();
+ useReducedWait = false;
+ }
+ else if (! gotSignal && ! _freeContexts.empty()) {
+ // we timed out waiting for a signal, so we have idle time that we can
+ // spend on running the GC pro-actively
+ // We'll pick one of the free contexts and clean it up
+ context = pickContextForGc();
+
+ // there is no context to clean up, probably they all have been cleaned up
+ // already. increase the wait time so we don't cycle to much in the GC loop
+ // and waste CPU unnecessary
+ useReducedWait = (context != 0);
}
}
+
+ // update last gc time
+ double lastGc = TRI_microtime();
+ gc->updateGcStamp(lastGc);
if (context != 0) {
LOGGER_TRACE << "collecting V8 garbage";
@@ -288,6 +414,7 @@ void ApplicationV8::collectGarbage () {
delete context->_locker;
context->_dirt = 0;
+ context->_lastGcStamp = lastGc;
{
CONDITION_LOCKER(guard, _contextCondition);
@@ -326,7 +453,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"]
@@ -341,6 +469,7 @@ void ApplicationV8::setupOptions (map<string, basics::ProgramOptionsDescription>
////////////////////////////////////////////////////////////////////////////////
bool ApplicationV8::prepare () {
+ LOGGER_DEBUG << "V8 version: " << v8::V8::GetVersion();
LOGGER_INFO << "using JavaScript modules path '" << _startupModules << "'";
// set up the startup loader
@@ -527,6 +656,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 62b0474..f6d485e 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;
+
};
////////////////////////////////////////////////////////////////////////////////
@@ -241,6 +253,12 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
+/// @brief determine which of the free contexts should be picked for the GC
+////////////////////////////////////////////////////////////////////////////////
+
+ V8Context* pickContextForGc ();
+
+////////////////////////////////////////////////////////////////////////////////
/// @brief prepares a V8 instance
////////////////////////////////////////////////////////////////////////////////
@@ -312,6 +330,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/arangod/V8Server/v8-query.cpp b/arangod/V8Server/v8-query.cpp
index 0ca033a..0cad75a 100755
--- a/arangod/V8Server/v8-query.cpp
+++ b/arangod/V8Server/v8-query.cpp
@@ -35,6 +35,7 @@
#include "V8/v8-conv.h"
#include "V8/v8-utils.h"
#include "V8Server/v8-vocbase.h"
+#include "Logger/Logger.h"
// -----------------------------------------------------------------------------
// --SECTION-- HELPER FUNCTIONS
@@ -639,20 +640,26 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, st
// inside a read transaction
// .............................................................................
+ LOG_TRACE("before beginRead");
collection->_collection->beginRead(collection->_collection);
+ LOG_TRACE("after beginRead");
// extract the index
TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, &err);
if (idx == 0) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(err));
}
if (idx->_type != TRI_IDX_TYPE_SKIPLIST_INDEX) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a skiplist index")));
@@ -668,7 +675,9 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, st
}
if (!skiplistOperator) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "setting up skiplist operator failed")));
@@ -699,7 +708,9 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, st
}
}
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside a write transaction
@@ -836,7 +847,9 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
// inside a read transaction
// .............................................................................
+ LOG_TRACE("before beginRead");
collection->_collection->beginRead(collection->_collection);
+ LOG_TRACE("after beginRead");
// .............................................................................
@@ -846,7 +859,9 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, &err);
if (idx == 0) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(err));
@@ -854,7 +869,9 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
if (idx->_type != TRI_IDX_TYPE_BITARRAY_INDEX) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a skiplist index")));
@@ -872,7 +889,9 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
if (indexOperator == 0) { // something wrong
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "setting up skiplist operator failed")));
@@ -925,7 +944,9 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
LOG_WARNING("index iterator returned with a NULL value in ExecuteBitarrayQuery");
}
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside a write transaction
@@ -1097,7 +1118,9 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
// inside a read transaction
// .............................................................................
+ LOG_TRACE("before beginRead");
collection->_collection->beginRead(collection->_collection);
+ LOG_TRACE("after beginRead");
TRI_barrier_t* barrier = 0;
uint32_t count = 0;
@@ -1157,7 +1180,9 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
TRI_ReleaseCollection(vertexCollection);
}
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(errMsg));
@@ -1180,7 +1205,9 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
TRI_DestroyVectorPointer(&edges);
}
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside a write transaction
@@ -1210,6 +1237,7 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
v8::HandleScope scope;
+ LOGGER_TRACE << "executing ALL query";
// extract and use the simple collection
v8::Handle<v8::Object> err;
TRI_vocbase_col_t const* collection;
@@ -1243,10 +1271,17 @@ static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
// inside a read transaction
// .............................................................................
- collection->_collection->beginRead(collection->_collection);
+ LOGGER_TRACE << "acquiring lock in allquery";
+ LOG_TRACE("before beginRead");
+ int lockResult = collection->_collection->beginRead(collection->_collection);
+ LOG_TRACE("after beginRead");
+ LOGGER_TRACE << "result of beginRead: " << lockResult;
size_t total = sim->_primaryIndex._nrUsed;
uint32_t count = 0;
+ LOGGER_TRACE << "number of documents: " << total;
+ LOGGER_TRACE << "skip: " << skip;
+ LOGGER_TRACE << "limit: " << limit;
if (0 < total && 0 < limit) {
TRI_barrier_t* barrier = 0;
@@ -1254,6 +1289,9 @@ static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
void** beg = sim->_primaryIndex._table;
void** end = sim->_primaryIndex._table + sim->_primaryIndex._nrAlloc;
void** ptr = beg;
+ LOGGER_TRACE << "nrAlloc: " << sim->_primaryIndex._nrAlloc;
+ LOGGER_TRACE << "begin: " << beg;
+ LOGGER_TRACE << "end: " << beg;
// skip from the beginning
if (0 < skip) {
@@ -1291,6 +1329,7 @@ static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
}
}
+ LOGGER_TRACE << "beginning extraction. ptr: " << ptr << ", end: " << end << ", range: " << (end - ptr) << ", count: " << count << ", limit: " << limit;
// limit
for (; ptr < end && count < limit; ++ptr) {
if (*ptr) {
@@ -1307,9 +1346,12 @@ static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
}
}
}
+ LOGGER_TRACE << "finished extraction. count is " << count;
}
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside a write transaction
@@ -1386,7 +1428,9 @@ static v8::Handle<v8::Value> JS_ByExampleQuery (v8::Arguments const& argv) {
// inside a read transaction
// .............................................................................
+ LOG_TRACE("before beginRead");
collection->_collection->beginRead(collection->_collection);
+ LOG_TRACE("after beginRead");
// find documents by example
TRI_vector_t filtered = TRI_SelectByExample(sim, n, pids, values);
@@ -1418,7 +1462,9 @@ static v8::Handle<v8::Value> JS_ByExampleQuery (v8::Arguments const& argv) {
TRI_DestroyVector(&filtered);
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside a write transaction
@@ -1483,20 +1529,26 @@ static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
// inside a read transaction
// .............................................................................
+ LOG_TRACE("before beginRead");
collection->_collection->beginRead(collection->_collection);
+ LOG_TRACE("after beginRead");
// extract the index
TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, &err);
if (idx == 0) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(err));
}
if (idx->_type != TRI_IDX_TYPE_HASH_INDEX) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a hash index")));
@@ -1512,7 +1564,9 @@ static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
int res = SetupExampleObjectIndex(hashIndex, example, shaper, n, values, &err);
if (res != TRI_ERROR_NO_ERROR) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(err));
@@ -1542,7 +1596,9 @@ static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
}
}
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside a write transaction
@@ -1667,20 +1723,26 @@ static v8::Handle<v8::Value> JS_NearQuery (v8::Arguments const& argv) {
// inside a read transaction
// .............................................................................
+ LOG_TRACE("before beginRead");
collection->_collection->beginRead(collection->_collection);
+ LOG_TRACE("after beginRead");
// extract the index
TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, &err);
if (idx == 0) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(err));
}
if (idx->_type != TRI_IDX_TYPE_GEO1_INDEX && idx->_type != TRI_IDX_TYPE_GEO2_INDEX) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a geo-index")));
@@ -1708,7 +1770,9 @@ static v8::Handle<v8::Value> JS_NearQuery (v8::Arguments const& argv) {
StoreGeoResult(collection, cors, documents, distances);
}
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside a write transaction
@@ -1769,20 +1833,26 @@ static v8::Handle<v8::Value> JS_WithinQuery (v8::Arguments const& argv) {
// inside a read transaction
// .............................................................................
+ LOG_TRACE("before beginRead");
collection->_collection->beginRead(collection->_collection);
+ LOG_TRACE("after beginRead");
// extract the index
TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, &err);
if (idx == 0) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(err));
}
if (idx->_type != TRI_IDX_TYPE_GEO1_INDEX && idx->_type != TRI_IDX_TYPE_GEO2_INDEX) {
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a geo-index")));
@@ -1809,8 +1879,10 @@ static v8::Handle<v8::Value> JS_WithinQuery (v8::Arguments const& argv) {
if (cors != 0) {
StoreGeoResult(collection, cors, documents, distances);
}
-
+
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after endRead");
// .............................................................................
// outside a write transaction
diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp
index 9bd6923..4b37d5d 100755
--- a/arangod/V8Server/v8-vocbase.cpp
+++ b/arangod/V8Server/v8-vocbase.cpp
@@ -48,6 +48,7 @@
#include "VocBase/general-cursor.h"
#include "VocBase/simple-collection.h"
#include "VocBase/voc-shaper.h"
+#include "Logger/Logger.h"
using namespace std;
using namespace triagens::basics;
@@ -119,6 +120,71 @@ static int32_t const WRP_SHAPED_JSON_TYPE = 4;
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
+// --SECTION-- HELPER CLASSES
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// --SECTION-- AhuacatlContextHolder
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup VocBase
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief wraps a C++ into a v8::Object
+////////////////////////////////////////////////////////////////////////////////
+
+class AhuacatlContextGuard {
+ public:
+ AhuacatlContextGuard (TRI_vocbase_t* vocbase, const string& query) :
+ _context(0) {
+ LOGGER_DEBUG << "context guard created";
+ _context = TRI_CreateContextAql(vocbase, query.c_str());
+
+ if (_context == 0) {
+ LOGGER_DEBUG << "failed to create context for query %s" << query;
+ }
+ }
+
+ ~AhuacatlContextGuard () {
+ this->free();
+ LOGGER_DEBUG << "context guard destroyed";
+ }
+
+ void free () {
+ if (_context != 0) {
+ TRI_FreeContextAql(_context);
+ _context = 0;
+ }
+ }
+
+ inline TRI_aql_context_t* operator() () const {
+ return _context;
+ }
+
+ inline TRI_aql_context_t* ptr () const {
+ return _context;
+ }
+
+ inline const TRI_aql_context_t* const_ptr () const {
+ return _context;
+ }
+
+ inline const bool valid () const {
+ return _context != 0;
+ }
+
+ private:
+ TRI_aql_context_t* _context;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+/// @}
+////////////////////////////////////////////////////////////////////////////////
+
+// -----------------------------------------------------------------------------
// --SECTION-- HELPER FUNCTIONS
// -----------------------------------------------------------------------------
@@ -513,7 +579,9 @@ static v8::Handle<v8::Value> DocumentVocbaseCol (TRI_vocbase_t* vocbase,
// inside a read transaction
// .............................................................................
+ LOG_TRACE("before beginRead");
collection->_collection->beginRead(collection->_collection);
+ LOG_TRACE("after beginRead");
document = collection->_collection->read(collection->_collection, did);
@@ -524,7 +592,9 @@ static v8::Handle<v8::Value> DocumentVocbaseCol (TRI_vocbase_t* vocbase,
result = TRI_WrapShapedJson(collection, &document, barrier);
}
+ LOG_TRACE("before endRead");
collection->_collection->endRead(collection->_collection);
+ LOG_TRACE("after beginRead");
// .............................................................................
// outside a write transaction
@@ -610,7 +680,9 @@ static v8::Handle<v8::Value> ReplaceVocbaseCol (TRI_vocbase_t* vocbase,
// inside a write transaction
// .............................................................................
+ LOG_TRACE("before beginWrite");
collection->_collection->beginWrite(collection->_collection);
+ LOG_TRACE("after beginWrite");
TRI_voc_rid_t oldRid = 0;
TRI_doc_mptr_t mptr = doc->update(doc, shaped, did, rid, &oldRid, policy, true);
@@ -1006,6 +1078,7 @@ static v8::Handle<v8::Value> ExecuteQueryNativeAhuacatl (TRI_aql_context_t* cons
const TRI_json_t* const parameters) {
v8::HandleScope scope;
+ LOGGER_DEBUG << "executing native query";
// parse & validate
// bind values
// optimise
@@ -1014,21 +1087,28 @@ static v8::Handle<v8::Value> ExecuteQueryNativeAhuacatl (TRI_aql_context_t* cons
!TRI_BindQueryContextAql(context, parameters) ||
!TRI_LockQueryContextAql(context) ||
!TRI_OptimiseQueryContextAql(context)) {
+ LOGGER_DEBUG << "executing native query failed";
v8::Handle<v8::Object> errorObject = CreateErrorObjectAhuacatl(&context->_error);
return scope.Close(v8::ThrowException(errorObject));
}
+ LOGGER_DEBUG << "generating code for native query";
// generate code
char* code = TRI_GenerateCodeAql(context);
+ LOGGER_DEBUG << "generating code finished";
if (!code) {
+ LOGGER_DEBUG << "generating code failed";
v8::Handle<v8::Object> errorObject = CreateErrorObjectAhuacatl(&context->_error);
return scope.Close(v8::ThrowException(errorObject));
}
+ LOGGER_DEBUG << "generating code succeeded";
// execute code
+ LOGGER_DEBUG << "executing generated Javascript code";
v8::Handle<v8::Value> result = TRI_ExecuteJavaScriptString(v8::Context::GetCurrent(), v8::String::New(code), v8::String::New("query"), false);
+ LOGGER_DEBUG << "finished executing generated Javascript code";
TRI_Free(TRI_UNKNOWN_MEM_ZONE, code);
// return the result as a javascript array
@@ -1048,14 +1128,18 @@ static v8::Handle<v8::Value> ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vo
v8::HandleScope scope;
v8::TryCatch tryCatch;
+ LOGGER_DEBUG << "executing query cursor";
v8::Handle<v8::Value> result = ExecuteQueryNativeAhuacatl(context, parameters);
+ LOGGER_DEBUG << "finished executing query cursor";
if (tryCatch.HasCaught()) {
+ LOGGER_DEBUG << "executing query cursor failed";
return scope.Close(v8::ThrowException(tryCatch.Exception()));
}
if (allowDirectReturn || !result->IsArray()) {
// return the value we got as it is. this is a performance optimisation
+ LOGGER_DEBUG << "executing query cursor returned directly";
return scope.Close(result);
}
@@ -1063,6 +1147,7 @@ static v8::Handle<v8::Value> ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vo
TRI_json_t* json = TRI_JsonObject(result);
if (!json) {
+ LOGGER_DEBUG << "executing query cursor failed with out-of-memory";
v8::Handle<v8::Object> errorObject = TRI_CreateErrorObject(TRI_ERROR_OUT_OF_MEMORY, "out of memory");
return scope.Close(v8::ThrowException(errorObject));
@@ -1073,6 +1158,7 @@ static v8::Handle<v8::Value> ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vo
if (!cursorResult) {
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
+ LOGGER_DEBUG << "executing query cursor failed with out-of-memory at cursor result";
v8::Handle<v8::Object> errorObject = TRI_CreateErrorObject(TRI_ERROR_OUT_OF_MEMORY, "out of memory");
return scope.Close(v8::ThrowException(errorObject));
@@ -1083,6 +1169,7 @@ static v8::Handle<v8::Value> ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vo
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
+ LOGGER_DEBUG << "creating general cursor failed";
v8::Handle<v8::Object> errorObject = TRI_CreateErrorObject(TRI_ERROR_OUT_OF_MEMORY, "out of memory");
return scope.Close(v8::ThrowException(errorObject));
@@ -1091,6 +1178,7 @@ static v8::Handle<v8::Value> ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vo
assert(cursor);
TRI_StoreShadowData(vocbase->_cursors, (const void* const) cursor);
+ LOGGER_DEBUG << "returning general cursor";
return scope.Close(WrapGeneralCursor(cursor));
}
@@ -1299,12 +1387,10 @@ static v8::Handle<v8::Value> JS_DisposeGeneralCursor (v8::Arguments const& argv)
bool found = TRI_DeleteDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (found) {
- return scope.Close(v8::True());
- }
-
- return scope.Close(v8::ThrowException(
- TRI_CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
- "disposed or unknown cursor")));
+ return scope.Close(v8::True());
+ }
+
+ return scope.Close(v8::False());
}
////////////////////////////////////////////////////////////////////////////////
@@ -1365,7 +1451,7 @@ static v8::Handle<v8::Value> JS_CountGeneralCursor (v8::Arguments const& argv) {
cursor = (TRI_general_cursor_t*) TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (cursor) {
- size_t length = (size_t) cursor->_length;
+ size_t length = (size_t) cursor->_length;
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
return scope.Close(v8::Number::New(length));
}
@@ -1666,6 +1752,32 @@ static v8::Handle<v8::Value> JS_HasNextGeneralCursor (v8::Arguments const& argv)
}
////////////////////////////////////////////////////////////////////////////////
+/// @brief unuse a general cursor
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_UnuseGeneralCursor (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ if (argv.Length() != 0) {
+ return scope.Close(v8::ThrowException(
+ TRI_CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
+ "usage: unuse()")));
+ }
+
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+
+ if (!vocbase) {
+ return scope.Close(v8::ThrowException(
+ TRI_CreateErrorObject(TRI_ERROR_INTERNAL,
+ "corrupted vocbase")));
+ }
+
+ TRI_EndUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
+
+ return scope.Close(v8::Undefined());
+}
+
+////////////////////////////////////////////////////////////////////////////////
/// @brief get a (persistent) cursor by its id
////////////////////////////////////////////////////////////////////////////////
@@ -1707,7 +1819,7 @@ static v8::Handle<v8::Value> JS_Cursor (v8::Arguments const& argv) {
TRI_CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
-
+
return scope.Close(WrapGeneralCursor(cursor));
}
@@ -1776,16 +1888,16 @@ static v8::Handle<v8::Value> JS_RunAhuacatl (v8::Arguments const& argv) {
// bind parameters
triagens::rest::JsonContainer parameters(TRI_UNKNOWN_MEM_ZONE, argc > 1 ? TRI_JsonObject(argv[1]) : 0);
- TRI_aql_context_t* context = TRI_CreateContextAql(vocbase, queryString.c_str());
- if (!context) {
+ AhuacatlContextGuard context(vocbase, queryString);
+ if (! context.valid()) {
v8::Handle<v8::Object> errorObject = TRI_CreateErrorObject(TRI_ERROR_OUT_OF_MEMORY, "out of memory");
return scope.Close(v8::ThrowException(errorObject));
}
v8::Handle<v8::Value> result;
- result = ExecuteQueryCursorAhuacatl(vocbase, context, parameters.ptr(), doCount, batchSize, allowDirectReturn);
- TRI_FreeContextAql(context);
+ result = ExecuteQueryCursorAhuacatl(vocbase, context.ptr(), parameters.ptr(), doCount, batchSize, allowDirectReturn);
+ context.free();
if (tryCatch.HasCaught()) {
if (tryCatch.Exception()->IsObject() && v8::Handle<v8::Array>::Cast(tryCatch.Exception())->HasOwnProperty(v8::String::New("errorNum"))) {
@@ -1798,6 +1910,8 @@ static v8::Handle<v8::Value> JS_RunAhuacatl (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(errorObject));
}
+ LOGGER_DEBUG << "returning cursor result";
+
return scope.Close(result);
}
@@ -1834,8 +1948,8 @@ static v8::Handle<v8::Value> JS_ExplainAhuacatl (v8::Arguments const& argv) {
// bind parameters
triagens::rest::JsonContainer parameters(TRI_UNKNOWN_MEM_ZONE, argc > 1 ? TRI_JsonObject(argv[1]) : 0);
- TRI_aql_context_t* context = TRI_CreateContextAql(vocbase, queryString.c_str());
- if (!context) {
+ AhuacatlContextGuard context(vocbase, queryString);
+ if (! context.valid()) {
v8::Handle<v8::Object> errorObject = TRI_CreateErrorObject(TRI_ERROR_OUT_OF_MEMORY, "out of memory");
return scope.Close(v8::ThrowException(errorObject));
@@ -1849,13 +1963,12 @@ static v8::Handle<v8::Value> JS_ExplainAhuacatl (v8::Arguments const& argv) {
TRI_json_t* explain = 0;
- if (!TRI_ValidateQueryContextAql(context) ||
- !TRI_BindQueryContextAql(context, parameters.ptr()) ||
- !TRI_LockQueryContextAql(context) ||
- (performOptimisations && !TRI_OptimiseQueryContextAql(context)) ||
- !(explain = TRI_ExplainAql(context))) {
- v8::Handle<v8::Object> errorObject = CreateErrorObjectAhuacatl(&context->_error);
- TRI_FreeContextAql(context);
+ if (!TRI_ValidateQueryContextAql(context.ptr()) ||
+ !TRI_BindQueryContextAql(context.ptr(), parameters.ptr()) ||
+ !TRI_LockQueryContextAql(context.ptr()) ||
+ (performOptimisations && !TRI_OptimiseQueryContextAql(context.ptr())) ||
+ !(explain = TRI_ExplainAql(context.ptr()))) {
+ v8::Handle<v8::Object> errorObject = CreateErrorObjectAhuacatl(&(context.ptr())->_error);
return scope.Close(v8::ThrowException(errorObject));
}
@@ -1863,8 +1976,8 @@ static v8::Handle<v8::Value> JS_ExplainAhuacatl (v8::Arguments const& argv) {
v8::Handle<v8::Value> result;
result = TRI_ObjectJson(explain);
- TRI_FreeContextAql(context);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, explain);
+ context.free();
if (tryCatch.HasCaught()) {
if (tryCatch.Exception()->IsObject() && v8::Handle<v8::Array>::Cast(tryCatch.Exception())->HasOwnProperty(v8::String::New("errorNum"))) {
@@ -1906,17 +2019,16 @@ static v8::Handle<v8::Value> JS_ParseAhuacatl (v8::Arguments const& argv) {
}
string queryString = TRI_ObjectToString(queryArg);
- TRI_aql_context_t* context = TRI_CreateContextAql(vocbase, queryString.c_str());
- if (!context) {
+ AhuacatlContextGuard context(vocbase, queryString);
+ if (! context.valid()) {
v8::Handle<v8::Object> errorObject = TRI_CreateErrorObject(TRI_ERROR_OUT_OF_MEMORY, "out of memory");
return scope.Close(v8::ThrowException(errorObject));
}
// parse & validate
- if (!TRI_ValidateQueryContextAql(context)) {
- v8::Handle<v8::Object> errorObject = CreateErrorObjectAhuacatl(&context->_error);
- TRI_FreeContextAql(context);
+ if (!TRI_ValidateQueryContextAql(context.ptr())) {
+ v8::Handle<v8::Object> errorObject = CreateErrorObjectAhuacatl(&(context.ptr())->_error);
return scope.Close(v8::ThrowException(errorObject));
}
@@ -1927,11 +2039,10 @@ static v8::Handle<v8::Value> JS_ParseAhuacatl (v8::Arguments const& argv) {
result->Set(v8::String::New("parsed"), v8::True());
// return the bind parameter names
- result->Set(v8::String::New("parameters"), TRI_ArrayAssociativePointer(&context->_parameters._names));
+ result->Set(v8::String::New("parameters"), TRI_ArrayAssociativePointer(&(context.ptr())->_parameters._names));
// return the collection names
- result->Set(v8::String::New("collections"), TRI_ArrayAssociativePointer(&context->_collectionNames));
+ result->Set(v8::String::New("collections"), TRI_ArrayAssociativePointer(&(context.ptr())->_collectionNames));
- TRI_FreeContextAql(context);
if (tryCatch.HasCaught()) {
if (tryCatch.Exception()->IsObject() && v8::Handle<v8::Array>::Cast(tryCatch.Exception())->HasOwnProperty(v8::String::New("errorNum"))) {
// we already have an ArangoError object
@@ -2987,9 +3098,13 @@ static v8::Handle<v8::Value> JS_FiguresVocbaseCol (v8::Arguments const& argv) {
TRI_doc_collection_t* doc = collection->_collection;
+ LOG_TRACE("before beginRead");
doc->beginRead(doc);
+ LOG_TRACE("after beginRead");
TRI_doc_collection_info_t* info = doc->figures(doc);
+ LOG_TRACE("before endRead");
doc->endRead(doc);
+ LOG_TRACE("after endRead");
if (info == NULL) {
TRI_READ_UNLOCK_STATUS_VOCBASE_COL(collection);
@@ -3464,7 +3579,9 @@ static v8::Handle<v8::Value> JS_SaveVocbaseCol (v8::Arguments const& argv) {
// inside a write transaction
// .............................................................................
+ LOG_TRACE("before beginWrite");
collection->_collection->beginWrite(collection->_collection);
+ LOG_TRACE("after beginWrite");
// the lock is freed in create
TRI_doc_mptr_t mptr = doc->create(doc, TRI_DOC_MARKER_DOCUMENT, shaped, 0, did, rid, true);
@@ -3705,7 +3822,9 @@ static v8::Handle<v8::Value> JS_SaveEdgesCol (v8::Arguments const& argv) {
// inside a write transaction
// .............................................................................
+ LOG_TRACE("before beginWrite");
collection->_collection->beginWrite(collection->_collection);
+ LOG_TRACE("after beginWrite");
TRI_doc_mptr_t mptr = doc->create(doc, TRI_DOC_MARKER_EDGE, shaped, &edge, did, rid, true);
@@ -4907,6 +5026,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocba
v8::Handle<v8::String> StatusFuncName = v8::Persistent<v8::String>::New(v8::String::New("status"));
v8::Handle<v8::String> TruncateDatafileFuncName = v8::Persistent<v8::String>::New(v8::String::New("truncateDatafile"));
v8::Handle<v8::String> UnloadFuncName = v8::Persistent<v8::String>::New(v8::String::New("unload"));
+ v8::Handle<v8::String> UnuseFuncName = v8::Persistent<v8::String>::New(v8::String::New("unuse"));
v8::Handle<v8::String> _CollectionFuncName = v8::Persistent<v8::String>::New(v8::String::New("_collection"));
v8::Handle<v8::String> _CollectionsFuncName = v8::Persistent<v8::String>::New(v8::String::New("_collections"));
@@ -5165,12 +5285,17 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocba
rt->Set(IdFuncName, v8::FunctionTemplate::New(JS_IdGeneralCursor));
rt->Set(NextFuncName, v8::FunctionTemplate::New(JS_NextGeneralCursor));
rt->Set(PersistFuncName, v8::FunctionTemplate::New(JS_PersistGeneralCursor));
+ rt->Set(UnuseFuncName, v8::FunctionTemplate::New(JS_UnuseGeneralCursor));
v8g->GeneralCursorTempl = v8::Persistent<v8::ObjectTemplate>::New(rt);
// must come after SetInternalFieldCount
context->Global()->Set(v8::String::New("ArangoCursor"), ft->GetFunction());
+ // .............................................................................
+ // create some global functions
+ // .............................................................................
+
context->Global()->Set(v8::String::New("CURSOR"),
v8::FunctionTemplate::New(JS_Cursor)->GetFunction(),
v8::ReadOnly);
diff --git a/arangod/VocBase/compactor.c b/arangod/VocBase/compactor.c
index 2809b17..206d9ec 100644
--- a/arangod/VocBase/compactor.c
+++ b/arangod/VocBase/compactor.c
@@ -538,8 +538,6 @@ static void CleanupSimCollection (TRI_sim_collection_t* sim) {
////////////////////////////////////////////////////////////////////////////////
static void CleanupShadows (TRI_vocbase_t* const vocbase, bool force) {
- LOG_TRACE("cleaning shadows");
-
// clean unused cursors
TRI_CleanupShadowData(vocbase->_cursors, SHADOW_CURSOR_MAX_AGE, force);
}
diff --git a/arangod/VocBase/shadow-data.c b/arangod/VocBase/shadow-data.c
index b664156..1d08927 100644
--- a/arangod/VocBase/shadow-data.c
+++ b/arangod/VocBase/shadow-data.c
@@ -82,13 +82,14 @@ static TRI_shadow_t* CreateShadow (const void* const data) {
////////////////////////////////////////////////////////////////////////////////
static void DecreaseRefCount (TRI_shadow_store_t* const store, TRI_shadow_t* const shadow) {
- LOG_TRACE("decreasing refcount for shadow %p with data ptr %p and id %lu",
+ LOG_TRACE("decreasing refcount for shadow %p with data ptr %p and id %lu to %d",
shadow,
shadow->_data,
- (unsigned long) shadow->_id);
+ (unsigned long) shadow->_id,
+ (int) (shadow->_rc - 1));
if (--shadow->_rc <= 0 && shadow->_type == SHADOW_TRANSIENT) {
- LOG_TRACE("deleting shadow %p", shadow);
+ LOG_TRACE("deleting transient shadow %p", shadow);
TRI_RemoveKeyAssociativePointer(&store->_ids, &shadow->_id);
TRI_RemoveKeyAssociativePointer(&store->_pointers, shadow->_data);
@@ -102,12 +103,15 @@ static void DecreaseRefCount (TRI_shadow_store_t* const store, TRI_shadow_t* con
////////////////////////////////////////////////////////////////////////////////
static void IncreaseRefCount (TRI_shadow_store_t* const store, TRI_shadow_t* const shadow) {
- LOG_TRACE("increasing refcount for shadow %p with data ptr %p and id %lu",
+ LOG_TRACE("increasing refcount for shadow %p with data ptr %p and id %lu to %d",
shadow,
shadow->_data,
- (unsigned long) shadow->_id);
+ (unsigned long) shadow->_id,
+ (int) (shadow->_rc + 1));
- ++shadow->_rc;
+ if (++shadow->_rc <= 0) {
+ shadow->_rc = 1;
+ }
UpdateTimestampShadow(shadow);
}
@@ -255,7 +259,7 @@ void TRI_FreeShadowStore (TRI_shadow_store_t* const store) {
assert(store);
// force deletion of all remaining shadows
- TRI_CleanupShadowData(store, 0, true);
+ TRI_CleanupShadowData(store, 0.0, true);
TRI_DestroyMutex(&store->_lock);
TRI_DestroyAssociativePointer(&store->_ids);
@@ -376,7 +380,7 @@ void TRI_EndUsageDataShadowData (TRI_shadow_store_t* const store,
TRI_LockMutex(&store->_lock);
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
- if (shadow && !shadow->_deleted) {
+ if (shadow) {
DecreaseRefCount(store, shadow); // this might delete the shadow
}
@@ -523,6 +527,14 @@ void TRI_CleanupShadowData (TRI_shadow_store_t* const store,
// we need an exclusive lock on the index
TRI_LockMutex(&store->_lock);
+ if (store->_ids._nrUsed == 0) {
+ // store is empty, nothing to do!
+ TRI_UnlockMutex(&store->_lock);
+ return;
+ }
+
+ LOG_TRACE("cleaning shadows. in store: %ld", (unsigned long) store->_ids._nrUsed);
+
// loop until there's nothing to delete or
// we have deleted SHADOW_MAX_DELETE elements
while (deleteCount++ < SHADOW_MAX_DELETE || force) {
@@ -539,9 +551,14 @@ void TRI_CleanupShadowData (TRI_shadow_store_t* const store,
// check if shadow is unused and expired
if (shadow->_rc < 1 || force) {
if (shadow->_type == SHADOW_TRANSIENT ||
- shadow->_timestamp < compareStamp ||
+ shadow->_timestamp < compareStamp ||
+ shadow->_deleted ||
force) {
- LOG_TRACE("cleaning expired shadow %p", shadow);
+ LOG_TRACE("cleaning shadow %p, rc: %d, expired: %d, deleted: %d",
+ shadow,
+ (int) shadow->_rc,
+ (int) (shadow->_timestamp < compareStamp),
+ (int) shadow->_deleted);
TRI_RemoveKeyAssociativePointer(&store->_ids, &shadow->_id);
TRI_RemoveKeyAssociativePointer(&store->_pointers, shadow->_data);
diff --git a/arangod/VocBase/simple-collection.c b/arangod/VocBase/simple-collection.c
index 3e28a19..d4c44e3 100644
--- a/arangod/VocBase/simple-collection.c
+++ b/arangod/VocBase/simple-collection.c
@@ -323,6 +323,8 @@ static TRI_doc_mptr_t CreateDocument (TRI_sim_collection_t* sim,
TRI_voc_size_t total;
TRI_doc_datafile_info_t* dfi;
int res;
+
+ LOG_TRACE("CreateDocument. release flag is: %d", (int) release);
// .............................................................................
// create header
@@ -349,7 +351,9 @@ static TRI_doc_mptr_t CreateDocument (TRI_sim_collection_t* sim,
if (journal == NULL) {
if (release) {
+ LOG_DEBUG("before endWrite");
sim->base.endWrite(&sim->base);
+ LOG_DEBUG("after endWrite");
}
memset(&mptr, 0, sizeof(mptr));
@@ -440,7 +444,9 @@ static TRI_doc_mptr_t CreateDocument (TRI_sim_collection_t* sim,
// release lock, header might be invalid after this
if (release) {
+ LOG_DEBUG("before endWrite");
sim->base.endWrite(&sim->base);
+ LOG_DEBUG("after endWrite");
}
// wait for sync
@@ -451,7 +457,9 @@ static TRI_doc_mptr_t CreateDocument (TRI_sim_collection_t* sim,
}
else {
if (release) {
+ LOG_DEBUG("before endWrite");
sim->base.endWrite(&sim->base);
+ LOG_DEBUG("after endWrite");
}
mptr._did = 0;
@@ -461,7 +469,9 @@ static TRI_doc_mptr_t CreateDocument (TRI_sim_collection_t* sim,
}
else {
if (release) {
+ LOG_DEBUG("before endWrite");
sim->base.endWrite(&sim->base);
+ LOG_DEBUG("after endWrite");
}
LOG_ERROR("cannot write element: %s", TRI_last_error());
@@ -565,6 +575,8 @@ static TRI_doc_mptr_t UpdateDocument (TRI_sim_collection_t* collection,
TRI_doc_mptr_t resUpd;
TRI_voc_size_t total;
int res;
+
+ LOG_TRACE("UpdateDocument. release flag is: %d", (int) release);
originalMarker = header->_data;
@@ -581,7 +593,9 @@ static TRI_doc_mptr_t UpdateDocument (TRI_sim_collection_t* collection,
if (rid != 0) {
if (rid != header->_rid) {
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
TRI_set_errno(TRI_ERROR_ARANGO_CONFLICT);
@@ -597,7 +611,9 @@ static TRI_doc_mptr_t UpdateDocument (TRI_sim_collection_t* collection,
case TRI_DOC_UPDATE_CONFLICT:
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
TRI_set_errno(TRI_ERROR_NOT_IMPLEMENTED);
@@ -606,7 +622,9 @@ static TRI_doc_mptr_t UpdateDocument (TRI_sim_collection_t* collection,
case TRI_DOC_UPDATE_ILLEGAL:
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
TRI_set_errno(TRI_ERROR_INTERNAL);
@@ -629,7 +647,9 @@ static TRI_doc_mptr_t UpdateDocument (TRI_sim_collection_t* collection,
collection->base.base._lastError = TRI_set_errno(TRI_ERROR_ARANGO_NO_JOURNAL);
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
mptr._did = 0;
@@ -699,7 +719,9 @@ static TRI_doc_mptr_t UpdateDocument (TRI_sim_collection_t* collection,
// release lock, header might be invalid after this
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
// wait for sync
@@ -710,7 +732,9 @@ static TRI_doc_mptr_t UpdateDocument (TRI_sim_collection_t* collection,
}
else {
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
mptr._did = 0;
@@ -720,7 +744,9 @@ static TRI_doc_mptr_t UpdateDocument (TRI_sim_collection_t* collection,
}
else {
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
LOG_ERROR("cannot write element");
@@ -744,13 +770,17 @@ static int DeleteDocument (TRI_sim_collection_t* collection,
TRI_doc_mptr_t const* header;
TRI_voc_size_t total;
int res;
+
+ LOG_TRACE("DeleteDocument. release flag is: %d", (int) release);
// get an existing header pointer
header = TRI_LookupByKeyAssociativePointer(&collection->_primaryIndex, &marker->_did);
if (header == NULL || header->_deletion != 0) {
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
return TRI_set_errno(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND);
@@ -766,7 +796,9 @@ static int DeleteDocument (TRI_sim_collection_t* collection,
if (rid != 0) {
if (rid != header->_rid) {
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
return TRI_set_errno(TRI_ERROR_ARANGO_CONFLICT);
@@ -780,14 +812,18 @@ static int DeleteDocument (TRI_sim_collection_t* collection,
case TRI_DOC_UPDATE_CONFLICT:
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
return TRI_set_errno(TRI_ERROR_NOT_IMPLEMENTED);
case TRI_DOC_UPDATE_ILLEGAL:
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
return TRI_set_errno(TRI_ERROR_INTERNAL);
@@ -804,7 +840,9 @@ static int DeleteDocument (TRI_sim_collection_t* collection,
collection->base.base._lastError = TRI_set_errno(TRI_ERROR_ARANGO_NO_JOURNAL);
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
return TRI_ERROR_ARANGO_NO_JOURNAL;
@@ -840,7 +878,9 @@ static int DeleteDocument (TRI_sim_collection_t* collection,
// release lock
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
// wait for sync
@@ -848,7 +888,9 @@ static int DeleteDocument (TRI_sim_collection_t* collection,
}
else {
if (release) {
+ LOG_DEBUG("before endWrite");
collection->base.endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
LOG_ERROR("cannot delete element");
@@ -973,6 +1015,8 @@ static TRI_doc_mptr_t CreateShapedJson (TRI_doc_collection_t* document,
bool release) {
TRI_df_marker_t* result;
TRI_sim_collection_t* collection;
+
+ LOG_TRACE("CreateShapedJson. release flag is: %d", (int) release);
collection = (TRI_sim_collection_t*) document;
@@ -1069,6 +1113,8 @@ static TRI_doc_mptr_t UpdateShapedJson (TRI_doc_collection_t* document,
TRI_doc_mptr_t mptr;
TRI_doc_mptr_t const* header;
TRI_sim_collection_t* collection;
+
+ LOG_TRACE("UpdateShapedJson. release flag is: %d", (int) release);
collection = (TRI_sim_collection_t*) document;
@@ -1077,7 +1123,9 @@ static TRI_doc_mptr_t UpdateShapedJson (TRI_doc_collection_t* document,
if (header == NULL || header->_deletion != 0) {
if (release) {
+ LOG_DEBUG("before endWrite");
document->endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
TRI_set_errno(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND);
@@ -1150,7 +1198,9 @@ static TRI_doc_mptr_t UpdateShapedJson (TRI_doc_collection_t* document,
// do not know
else {
if (release) {
+ LOG_DEBUG("before endWrite");
document->endWrite(&collection->base);
+ LOG_DEBUG("after endWrite");
}
LOG_FATAL("unknown marker type %lu", (unsigned long) original->_type);
@@ -1170,6 +1220,8 @@ static int DeleteShapedJson (TRI_doc_collection_t* doc,
bool release) {
TRI_sim_collection_t* sim;
TRI_doc_deletion_marker_t marker;
+
+ LOG_TRACE("DeleteShapedJson. release flag is: %d", (int) release);
sim = (TRI_sim_collection_t*) doc;
@@ -1191,6 +1243,7 @@ static int DeleteShapedJson (TRI_doc_collection_t* doc,
static int BeginRead (TRI_doc_collection_t* doc) {
TRI_sim_collection_t* sim;
+ LOG_TRACE("BeginRead %p", doc);
sim = (TRI_sim_collection_t*) doc;
TRI_READ_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim);
@@ -1204,6 +1257,7 @@ static int BeginRead (TRI_doc_collection_t* doc) {
static int EndRead (TRI_doc_collection_t* doc) {
TRI_sim_collection_t* sim;
+ LOG_TRACE("EndRead %p", doc);
sim = (TRI_sim_collection_t*) doc;
TRI_READ_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim);
@@ -1217,6 +1271,7 @@ static int EndRead (TRI_doc_collection_t* doc) {
static int BeginWrite (TRI_doc_collection_t* doc) {
TRI_sim_collection_t* sim;
+ LOG_TRACE("BeginWrite %p", doc);
sim = (TRI_sim_collection_t*) doc;
TRI_WRITE_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim);
@@ -1230,6 +1285,7 @@ static int BeginWrite (TRI_doc_collection_t* doc) {
static int EndWrite (TRI_doc_collection_t* document) {
TRI_sim_collection_t* sim;
+ LOG_TRACE("EndWrite %p", document);
sim = (TRI_sim_collection_t*) document;
TRI_WRITE_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim);
diff --git a/arangod/VocBase/simple-collection.h b/arangod/VocBase/simple-collection.h
index 1a8c2e7..5385cc8 100644
--- a/arangod/VocBase/simple-collection.h
+++ b/arangod/VocBase/simple-collection.h
@@ -85,28 +85,36 @@ extern "C" {
////////////////////////////////////////////////////////////////////////////////
#define TRI_READ_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(a) \
- TRI_ReadLockReadWriteLock(&(a)->_lock)
+ LOG_TRACE("RWLock READ-LOCK %p", a); \
+ TRI_ReadLockReadWriteLock(&(a)->_lock); \
+ LOG_TRACE("RWLock READ-LOCK %p SUCCESS", a)
////////////////////////////////////////////////////////////////////////////////
/// @brief read unlocks the documents and indexes
////////////////////////////////////////////////////////////////////////////////
#define TRI_READ_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(a) \
- TRI_ReadUnlockReadWriteLock(&(a)->_lock)
+ LOG_TRACE("RWLock READ-UNLOCK %p", a); \
+ TRI_ReadUnlockReadWriteLock(&(a)->_lock); \
+ LOG_TRACE("RWLock READ-UNLOCK %p SUCCESS", a)
////////////////////////////////////////////////////////////////////////////////
/// @brief write locks the documents and indexes
////////////////////////////////////////////////////////////////////////////////
#define TRI_WRITE_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(a) \
- TRI_WriteLockReadWriteLock(&(a)->_lock)
+ LOG_TRACE("RWLock WRITE-LOCK %p", a); \
+ TRI_WriteLockReadWriteLock(&(a)->_lock); \
+ LOG_TRACE("RWLock WRITE-LOCK %p SUCCESS", a)
////////////////////////////////////////////////////////////////////////////////
/// @brief write unlocks the documents and indexes
////////////////////////////////////////////////////////////////////////////////
#define TRI_WRITE_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(a) \
- TRI_WriteUnlockReadWriteLock(&(a)->_lock)
+ LOG_TRACE("RWLock WRITE-UNLOCK %p", a); \
+ TRI_WriteUnlockReadWriteLock(&(a)->_lock); \
+ LOG_TRACE("RWLock WRITE-UNLOCK %p SUCCESS", a)
////////////////////////////////////////////////////////////////////////////////
/// @brief locks the journal entries
diff --git a/html/admin/js/modules/simple-query-basics.js b/html/admin/js/modules/simple-query-basics.js
index fcbe6f4..5f6b0ca 100644
--- a/html/admin/js/modules/simple-query-basics.js
+++ b/html/admin/js/modules/simple-query-basics.js
@@ -151,6 +151,7 @@ GeneralArrayCursor.prototype._PRINT = function () {
////////////////////////////////////////////////////////////////////////////////
GeneralArrayCursor.prototype.hasNext = function () {
+ require("console").log("hasNext called. current: " + this._current + ", stop: " + this._stop);
return this._current < this._stop;
}
@@ -177,7 +178,8 @@ GeneralArrayCursor.prototype.dispose = function() {
this._limit = null;
this._countTotal = null;
this._countQuery = null;
- this.current = null;
+ this._current = null;
+ this._stop = null;
}
////////////////////////////////////////////////////////////////////////////////
@@ -664,7 +666,9 @@ SimpleQueryArray.prototype.execute = function () {
this._skip = 0;
}
+ require("console").log("creating GeneralArrayCursor with " + this._documents.length + " docs, skip: " + this._skip + ", limit: " + this._limit);
this._execution = new GeneralArrayCursor(this._documents, this._skip, this._limit);
+ require("console").log("created GeneralArrayCursor");
}
}
diff --git a/js/actions/system/api-cursor.js b/js/actions/system/api-cursor.js
index c2d1107..6b1ec42 100644
--- a/js/actions/system/api-cursor.js
+++ b/js/actions/system/api-cursor.js
@@ -216,8 +216,15 @@ function PUT_api_cursor(req, res) {
return;
}
- // note: this might dispose or persist the cursor
- actions.resultCursor(req, res, cursor, actions.HTTP_OK);
+ try {
+ // note: this might dispose or persist the cursor
+ actions.resultCursor(req, res, cursor, actions.HTTP_OK);
+ }
+ catch (e) {
+ }
+ cursor.unuse();
+ cursor = null;
+ internal.wait(0.0);
}
catch (err) {
actions.resultException(req, res, err);
@@ -269,7 +276,9 @@ function DELETE_api_cursor(req, res) {
}
cursor.dispose();
+ cursor = null;
actions.resultOk(req, res, actions.HTTP_ACCEPTED, { "id" : cursorId });
+ internal.wait(0.0);
}
catch (err) {
actions.resultException(req, res, err);
diff --git a/js/common/modules/simple-query-basics.js b/js/common/modules/simple-query-basics.js
index 0840c2c..ed5daa1 100644
--- a/js/common/modules/simple-query-basics.js
+++ b/js/common/modules/simple-query-basics.js
@@ -150,6 +150,7 @@ GeneralArrayCursor.prototype._PRINT = function () {
////////////////////////////////////////////////////////////////////////////////
GeneralArrayCursor.prototype.hasNext = function () {
+ require("console").log("hasNext called. current: " + this._current + ", stop: " + this._stop);
return this._current < this._stop;
}
@@ -176,7 +177,8 @@ GeneralArrayCursor.prototype.dispose = function() {
this._limit = null;
this._countTotal = null;
this._countQuery = null;
- this.current = null;
+ this._current = null;
+ this._stop = null;
}
////////////////////////////////////////////////////////////////////////////////
@@ -663,7 +665,9 @@ SimpleQueryArray.prototype.execute = function () {
this._skip = 0;
}
+ require("console").log("creating GeneralArrayCursor with " + this._documents.length + " docs, skip: " + this._skip + ", limit: " + this._limit);
this._execution = new GeneralArrayCursor(this._documents, this._skip, this._limit);
+ require("console").log("created GeneralArrayCursor");
}
}
diff --git a/js/server/ahuacatl.js b/js/server/ahuacatl.js
index 665f723..1707ab4 100644
--- a/js/server/ahuacatl.js
+++ b/js/server/ahuacatl.js
@@ -385,7 +385,11 @@ function AHUACATL_LIST (value) {
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_GET_DOCUMENTS (collection) {
- return internal.db[collection].all().toArray();
+ require("console").log("AHUACATL_GET_DOCUMENTS called for " + collection);
+ var result = internal.db[collection].ALL(0, null).documents;
+ require("console").log("AHUACATL_GET_DOCUMENTS finished for " + collection);
+
+ return result;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/js/server/js-ahuacatl.h b/js/server/js-ahuacatl.h
index 7bf2dd5..7ab98bc 100644
--- a/js/server/js-ahuacatl.h
+++ b/js/server/js-ahuacatl.h
@@ -386,7 +386,11 @@ static string JS_server_ahuacatl =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_GET_DOCUMENTS (collection) {\n"
- " return internal.db[collection].all().toArray();\n"
+ " require(\"console\").log(\"AHUACATL_GET_DOCUMENTS called for \" + collection);\n"
+ " var result = internal.db[collection].ALL(0, null).documents;\n"
+ " require(\"console\").log(\"AHUACATL_GET_DOCUMENTS finished for \" + collection);\n"
+ "\n"
+ " return result;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
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
////////////////////////////////////////////////////////////////////////////////
diff --git a/lib/BasicsC/memory.c b/lib/BasicsC/memory.c
index 71b4d69..12b53a6 100644
--- a/lib/BasicsC/memory.c
+++ b/lib/BasicsC/memory.c
@@ -181,6 +181,7 @@ void* TRI_Allocate (TRI_memory_zone_t* zone, uint64_t n, bool set) {
if (m == NULL) {
if (zone->_failable) {
+ LOG_TRACE("malloc returned 0");
return NULL;
}