1
0
Fork 0
arangodb/Documentation/issue188.diff

2334 lines
100 KiB
Diff

diff --git a/arangod/V8Server/ApplicationV8.cpp b/arangod/V8Server/ApplicationV8.cpp
index d200d55..629fe3f 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,6 +260,10 @@ 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;
@@ -239,12 +273,17 @@ void ApplicationV8::exitContext (V8Context* context) {
{
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
@@ -528,6 +657,8 @@ bool ApplicationV8::prepareV8Instance (size_t i) {
context->_isolate->Exit();
delete context->_locker;
+ context->_lastGcStamp = TRI_microtime();
+
LOGGER_TRACE << "initialised V8 context #" << i;
_freeContexts.push_back(context);
diff --git a/arangod/V8Server/ApplicationV8.h b/arangod/V8Server/ApplicationV8.h
index 62b0474..0ee5356 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;
- size_t _dirt;
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief number of requests since last GC of the context
+////////////////////////////////////////////////////////////////////////////////
+
+ size_t _dirt;
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief timestamp of last GC for the context
+////////////////////////////////////////////////////////////////////////////////
+
+ double _lastGcStamp;
+
};
////////////////////////////////////////////////////////////////////////////////
@@ -239,6 +251,14 @@ namespace triagens {
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief determine which of the free contexts should be picked for the GC
+////////////////////////////////////////////////////////////////////////////////
+
+ V8Context* pickContextForGc ();
+
+////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief prepares a V8 instance
@@ -312,6 +332,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..e567349 100755
--- a/arangod/V8Server/v8-query.cpp
+++ b/arangod/V8Server/v8-query.cpp
@@ -584,13 +584,23 @@ static int SetupExampleObjectIndex (TRI_hash_index_t* hashIndex,
/// @brief execute a skiplist query (by condition or by example)
////////////////////////////////////////////////////////////////////////////////
-static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, std::string const& signature, const query_t type) {
+static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv,
+ std::string const& signature,
+ const query_t type,
+ const bool lock) {
v8::HandleScope scope;
// extract and use the simple collection
v8::Handle<v8::Object> err;
TRI_vocbase_col_t const* collection;
- TRI_sim_collection_t* sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
+ TRI_sim_collection_t* sim = 0;
+
+ if (lock) {
+ sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
+ }
+ else {
+ sim = TRI_ExtractSimpleCollection(argv, collection, &err);
+ }
if (sim == 0) {
return scope.Close(v8::ThrowException(err));
@@ -598,7 +608,9 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, st
// expecting index, example, skip, and limit
if (argv.Length() < 2) {
- TRI_ReleaseCollection(collection);
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
std::string usage("Usage: ");
usage += signature;
@@ -608,7 +620,9 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, st
}
if (! argv[1]->IsObject()) {
- TRI_ReleaseCollection(collection);
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
std::string msg;
if (type == QUERY_EXAMPLE) {
@@ -639,7 +653,9 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, st
// inside a read transaction
// .............................................................................
- collection->_collection->beginRead(collection->_collection);
+ if (lock) {
+ collection->_collection->beginRead(collection->_collection);
+ }
// extract the index
TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, &err);
@@ -647,14 +663,18 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, st
if (idx == 0) {
collection->_collection->endRead(collection->_collection);
- TRI_ReleaseCollection(collection);
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
return scope.Close(v8::ThrowException(err));
}
if (idx->_type != TRI_IDX_TYPE_SKIPLIST_INDEX) {
- collection->_collection->endRead(collection->_collection);
+ if (lock) {
+ collection->_collection->endRead(collection->_collection);
- TRI_ReleaseCollection(collection);
+ TRI_ReleaseCollection(collection);
+ }
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a skiplist index")));
}
@@ -668,9 +688,11 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, st
}
if (!skiplistOperator) {
- collection->_collection->endRead(collection->_collection);
+ if (lock) {
+ collection->_collection->endRead(collection->_collection);
- TRI_ReleaseCollection(collection);
+ TRI_ReleaseCollection(collection);
+ }
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "setting up skiplist operator failed")));
}
@@ -699,7 +721,9 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, st
}
}
- collection->_collection->endRead(collection->_collection);
+ if (lock) {
+ collection->_collection->endRead(collection->_collection);
+ }
// .............................................................................
// outside a write transaction
@@ -711,18 +735,17 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv, st
result->Set(v8::String::New("total"), v8::Number::New((double) total));
result->Set(v8::String::New("count"), v8::Number::New(count));
- TRI_ReleaseCollection(collection);
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
return scope.Close(result);
}
-
-
////////////////////////////////////////////////////////////////////////////////
/// @brief execute a bitarray index query (by condition or by example)
////////////////////////////////////////////////////////////////////////////////
-
////////////////////////////////////////////////////////////////////////////////
// Example of a filter associated with an interator
////////////////////////////////////////////////////////////////////////////////
@@ -755,7 +778,10 @@ static bool BitarrayFilterExample(TRI_index_iterator_t* indexIterator) {
return true;
}
-static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, std::string const& signature, const query_t type) {
+static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
+ std::string const& signature,
+ const query_t type,
+ const bool lock) {
v8::HandleScope scope;
v8::Handle<v8::Object> err;
const TRI_vocbase_col_t* collection;
@@ -766,8 +792,14 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
// extract and use the simple collection
// ...........................................................................
-
- TRI_sim_collection_t* sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
+
+ TRI_sim_collection_t* sim = 0;
+ if (lock) {
+ sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
+ }
+ else {
+ sim = TRI_ExtractSimpleCollection(argv, collection, &err);
+ }
if (sim == 0) {
return scope.Close(v8::ThrowException(err));
@@ -781,7 +813,9 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
// ...........................................................................
if (argv.Length() < 2) {
- TRI_ReleaseCollection(collection);
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
std::string usage("Usage: ");
usage += signature;
@@ -794,7 +828,9 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
// ...........................................................................
if (! argv[1]->IsObject()) {
- TRI_ReleaseCollection(collection);
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
std::string msg;
if (type == QUERY_EXAMPLE) {
@@ -836,8 +872,9 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
// inside a read transaction
// .............................................................................
- collection->_collection->beginRead(collection->_collection);
-
+ if (lock) {
+ collection->_collection->beginRead(collection->_collection);
+ }
// .............................................................................
// extract the index
@@ -848,15 +885,19 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
if (idx == 0) {
collection->_collection->endRead(collection->_collection);
- TRI_ReleaseCollection(collection);
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
return scope.Close(v8::ThrowException(err));
}
if (idx->_type != TRI_IDX_TYPE_BITARRAY_INDEX) {
- collection->_collection->endRead(collection->_collection);
+ if (lock) {
+ collection->_collection->endRead(collection->_collection);
- TRI_ReleaseCollection(collection);
+ TRI_ReleaseCollection(collection);
+ }
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a skiplist index")));
}
@@ -872,9 +913,11 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
if (indexOperator == 0) { // something wrong
- collection->_collection->endRead(collection->_collection);
+ if (lock) {
+ collection->_collection->endRead(collection->_collection);
- TRI_ReleaseCollection(collection);
+ TRI_ReleaseCollection(collection);
+ }
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "setting up skiplist operator failed")));
}
@@ -924,8 +967,10 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
else {
LOG_WARNING("index iterator returned with a NULL value in ExecuteBitarrayQuery");
}
-
- collection->_collection->endRead(collection->_collection);
+
+ if (lock) {
+ collection->_collection->endRead(collection->_collection);
+ }
// .............................................................................
// outside a write transaction
@@ -935,12 +980,13 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
result->Set(v8::String::New("total"), v8::Number::New((double) total));
result->Set(v8::String::New("count"), v8::Number::New(count));
- TRI_ReleaseCollection(collection);
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
return scope.Close(result);
}
-
////////////////////////////////////////////////////////////////////////////////
/// @brief sorts geo coordinates
////////////////////////////////////////////////////////////////////////////////
@@ -1114,7 +1160,7 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
TRI_voc_rid_t rid;
TRI_vocbase_col_t const* vertexCollection = 0;
- v8::Handle<v8::Value> errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, vertexCollection, did, rid, vertices->Get(i));
+ v8::Handle<v8::Value> errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, vertexCollection, did, rid, true, vertices->Get(i));
if (! errMsg.IsEmpty()) {
if (vertexCollection != 0) {
@@ -1150,7 +1196,7 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
TRI_voc_rid_t rid;
TRI_vocbase_col_t const* vertexCollection = 0;
- v8::Handle<v8::Value> errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, vertexCollection, did, rid, argv[0]);
+ v8::Handle<v8::Value> errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, vertexCollection, did, rid, true, argv[0]);
if (! errMsg.IsEmpty()) {
if (vertexCollection != 0) {
@@ -1204,24 +1250,18 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
-/// @brief selects all elements
+/// @brief executes an ALL query, without any locking
+///
+/// the caller must ensure all relevant locks are acquired and freed
////////////////////////////////////////////////////////////////////////////////
-static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
+static v8::Handle<v8::Value> AllQuery (TRI_sim_collection_t* sim,
+ TRI_vocbase_col_t const* collection,
+ v8::Arguments const& argv) {
v8::HandleScope scope;
-
- // extract and use the simple collection
- v8::Handle<v8::Object> err;
- TRI_vocbase_col_t const* collection;
- TRI_sim_collection_t* sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
-
- if (sim == 0) {
- return scope.Close(v8::ThrowException(err));
- }
-
+
// expecting two arguments
if (argv.Length() != 2) {
- TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
"usage: ALL(<skip>, <limit>)")));
@@ -1239,12 +1279,6 @@ static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
v8::Handle<v8::Array> documents = v8::Array::New();
result->Set(v8::String::New("documents"), documents);
- // .............................................................................
- // inside a read transaction
- // .............................................................................
-
- collection->_collection->beginRead(collection->_collection);
-
size_t total = sim->_primaryIndex._nrUsed;
uint32_t count = 0;
@@ -1309,8 +1343,6 @@ static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
}
}
- collection->_collection->endRead(collection->_collection);
-
// .............................................................................
// outside a write transaction
// .............................................................................
@@ -1318,7 +1350,64 @@ static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
result->Set(v8::String::New("total"), v8::Number::New((double) total));
result->Set(v8::String::New("count"), v8::Number::New(count));
+ return scope.Close(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief selects all elements, acquiring all required locks
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ // extract and use the simple collection
+ v8::Handle<v8::Object> err;
+ TRI_vocbase_col_t const* collection;
+ TRI_sim_collection_t* sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
+
+ if (sim == 0) {
+ return scope.Close(v8::ThrowException(err));
+ }
+
+ // .............................................................................
+ // inside a read transaction
+ // .............................................................................
+
+ collection->_collection->beginRead(collection->_collection);
+
+ v8::Handle<v8::Value> result = AllQuery(sim, collection, argv);
+
+ collection->_collection->endRead(collection->_collection);
+
+ // .............................................................................
+ // outside a write transaction
+ // .............................................................................
+
TRI_ReleaseCollection(collection);
+
+ return scope.Close(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief selects all elements, without acquiring any locks
+///
+/// It is the callers responsibility to acquire and free the required locks
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_AllNLQuery (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ // extract and use the simple collection
+ v8::Handle<v8::Object> err;
+ TRI_vocbase_col_t const* collection;
+ TRI_sim_collection_t* sim = TRI_ExtractSimpleCollection(argv, collection, &err);
+
+ if (sim == 0) {
+ return scope.Close(v8::ThrowException(err));
+ }
+
+ v8::Handle<v8::Value> result = AllQuery(sim, collection, argv);
+
return scope.Close(result);
}
@@ -1435,23 +1524,18 @@ static v8::Handle<v8::Value> JS_ByExampleQuery (v8::Arguments const& argv) {
////////////////////////////////////////////////////////////////////////////////
/// @brief selects elements by example using a hash index
+///
+/// It is the callers responsibility to acquire and free the required locks
////////////////////////////////////////////////////////////////////////////////
-static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
+static v8::Handle<v8::Value> ByExampleHashIndexQuery (TRI_sim_collection_t* sim,
+ TRI_vocbase_col_t const* collection,
+ v8::Handle<v8::Object>* err,
+ v8::Arguments const& argv) {
v8::HandleScope scope;
- // extract and use the simple collection
- v8::Handle<v8::Object> err;
- TRI_vocbase_col_t const* collection;
- TRI_sim_collection_t* sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
-
- if (sim == 0) {
- return scope.Close(v8::ThrowException(err));
- }
-
// expecting index, example, skip, and limit
if (argv.Length() < 2) {
- TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
"usage: BY_EXAMPLE_HASH(<index>, <example>, <skip>, <limit>)")));
@@ -1459,7 +1543,6 @@ static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
// extract the example
if (! argv[1]->IsObject()) {
- TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
"<example> must be an object")));
@@ -1479,26 +1562,14 @@ static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
v8::Handle<v8::Array> documents = v8::Array::New();
result->Set(v8::String::New("documents"), documents);
- // .............................................................................
- // inside a read transaction
- // .............................................................................
-
- collection->_collection->beginRead(collection->_collection);
-
// extract the index
- TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, &err);
+ TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, err);
if (idx == 0) {
- collection->_collection->endRead(collection->_collection);
-
- TRI_ReleaseCollection(collection);
- return scope.Close(v8::ThrowException(err));
+ return scope.Close(v8::ThrowException(*err));
}
if (idx->_type != TRI_IDX_TYPE_HASH_INDEX) {
- collection->_collection->endRead(collection->_collection);
-
- TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a hash index")));
}
@@ -1509,13 +1580,10 @@ static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
TRI_shaped_json_t** values;
TRI_shaper_t* shaper = sim->base._shaper;
- int res = SetupExampleObjectIndex(hashIndex, example, shaper, n, values, &err);
+ int res = SetupExampleObjectIndex(hashIndex, example, shaper, n, values, err);
if (res != TRI_ERROR_NO_ERROR) {
- collection->_collection->endRead(collection->_collection);
-
- TRI_ReleaseCollection(collection);
- return scope.Close(v8::ThrowException(err));
+ return scope.Close(v8::ThrowException(*err));
}
// find the matches
@@ -1542,12 +1610,6 @@ static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
}
}
- collection->_collection->endRead(collection->_collection);
-
- // .............................................................................
- // outside a write transaction
- // .............................................................................
-
// free data allocated by hash index result
TRI_FreeResultHashIndex(idx, list);
@@ -1556,19 +1618,85 @@ static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
CleanupExampleObject(shaper, n, 0, values);
+ return scope.Close(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief selects elements by example using a hash index
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ // extract and use the simple collection
+ v8::Handle<v8::Object> err;
+ TRI_vocbase_col_t const* collection;
+ TRI_sim_collection_t* sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
+
+ if (sim == 0) {
+ return scope.Close(v8::ThrowException(err));
+ }
+
+ // .............................................................................
+ // inside a read transaction
+ // .............................................................................
+
+ collection->_collection->beginRead(collection->_collection);
+
+ v8::Handle<v8::Value> result = ByExampleHashIndexQuery(sim, collection, &err, argv);
+
+ collection->_collection->endRead(collection->_collection);
+
+ // .............................................................................
+ // outside a write transaction
+ // .............................................................................
+
TRI_ReleaseCollection(collection);
return scope.Close(result);
}
////////////////////////////////////////////////////////////////////////////////
+/// @brief selects elements by example using a hash index
+///
+/// It is the callers responsibility to acquire and free the required locks
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_ByExampleNLHashIndex (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ // extract and use the simple collection
+ v8::Handle<v8::Object> err;
+ TRI_vocbase_col_t const* collection;
+ TRI_sim_collection_t* sim = TRI_ExtractSimpleCollection(argv, collection, &err);
+
+ if (sim == 0) {
+ return scope.Close(v8::ThrowException(err));
+ }
+
+ v8::Handle<v8::Value> result = ByExampleHashIndexQuery(sim, collection, &err, argv);
+
+ return scope.Close(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
/// @brief selects elements by condition using a skiplist index
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_ByConditionSkiplist (v8::Arguments const& argv) {
std::string signature("BY_CONDITION_SKIPLIST(<index>, <conditions>, <skip>, <limit>)");
- return ExecuteSkiplistQuery(argv, signature, QUERY_CONDITION);
+ return ExecuteSkiplistQuery(argv, signature, QUERY_CONDITION, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief selects elements by condition using a skiplist index
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_ByConditionNLSkiplist (v8::Arguments const& argv) {
+ std::string signature("BY_CONDITION_SKIPLIST_NL(<index>, <conditions>, <skip>, <limit>)");
+
+ return ExecuteSkiplistQuery(argv, signature, QUERY_CONDITION, false);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1578,9 +1706,18 @@ static v8::Handle<v8::Value> JS_ByConditionSkiplist (v8::Arguments const& argv)
static v8::Handle<v8::Value> JS_ByExampleSkiplist (v8::Arguments const& argv) {
std::string signature("BY_EXAMPLE_SKIPLIST(<index>, <example>, <skip>, <limit>)");
- return ExecuteSkiplistQuery(argv, signature, QUERY_EXAMPLE);
+ return ExecuteSkiplistQuery(argv, signature, QUERY_EXAMPLE, true);
}
+////////////////////////////////////////////////////////////////////////////////
+/// @brief selects elements by example using a skiplist index
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_ByExampleNLSkiplist (v8::Arguments const& argv) {
+ std::string signature("BY_EXAMPLE_SKIPLIST_NL(<index>, <example>, <skip>, <limit>)");
+
+ return ExecuteSkiplistQuery(argv, signature, QUERY_EXAMPLE, false);
+}
////////////////////////////////////////////////////////////////////////////////
/// @brief selects elements by example using a bitarray index
@@ -1589,11 +1726,18 @@ static v8::Handle<v8::Value> JS_ByExampleSkiplist (v8::Arguments const& argv) {
static v8::Handle<v8::Value> JS_ByExampleBitarray (v8::Arguments const& argv) {
std::string signature("BY_EXAMPLE_BITARRAY(<index>, <example>, <skip>, <limit>)");
- return ExecuteBitarrayQuery(argv, signature, QUERY_EXAMPLE);
+ return ExecuteBitarrayQuery(argv, signature, QUERY_EXAMPLE, true);
}
+////////////////////////////////////////////////////////////////////////////////
+/// @brief selects elements by example using a bitarray index
+////////////////////////////////////////////////////////////////////////////////
+static v8::Handle<v8::Value> JS_ByExampleNLBitarray (v8::Arguments const& argv) {
+ std::string signature("BY_EXAMPLE_BITARRAY_NL(<index>, <example>, <skip>, <limit>)");
+ return ExecuteBitarrayQuery(argv, signature, QUERY_EXAMPLE, false);
+}
////////////////////////////////////////////////////////////////////////////////
/// @brief selects all edges for a set of vertices
@@ -1641,48 +1785,31 @@ static v8::Handle<v8::Value> JS_InEdgesQuery (v8::Arguments const& argv) {
////////////////////////////////////////////////////////////////////////////////
/// @brief selects points near a given coordinate
+///
+/// the caller must ensure all relevant locks are acquired and freed
////////////////////////////////////////////////////////////////////////////////
-static v8::Handle<v8::Value> JS_NearQuery (v8::Arguments const& argv) {
+static v8::Handle<v8::Value> NearQuery (TRI_sim_collection_t* sim,
+ TRI_vocbase_col_t const* collection,
+ v8::Handle<v8::Object>* err,
+ v8::Arguments const& argv) {
v8::HandleScope scope;
- // extract and use the simple collection
- v8::Handle<v8::Object> err;
- TRI_vocbase_col_t const* collection;
- TRI_sim_collection_t* sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
-
- if (sim == 0) {
- return scope.Close(v8::ThrowException(err));
- }
-
// expect: NEAR(<index-id>, <latitude>, <longitude>, <limit>)
if (argv.Length() != 4) {
- TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
"usage: NEAR(<index-handle>, <latitude>, <longitude>, <limit>)")));
}
- // .............................................................................
- // inside a read transaction
- // .............................................................................
-
- collection->_collection->beginRead(collection->_collection);
-
// extract the index
- TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, &err);
+ TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, err);
if (idx == 0) {
- collection->_collection->endRead(collection->_collection);
-
- TRI_ReleaseCollection(collection);
- return scope.Close(v8::ThrowException(err));
+ return scope.Close(v8::ThrowException(*err));
}
if (idx->_type != TRI_IDX_TYPE_GEO1_INDEX && idx->_type != TRI_IDX_TYPE_GEO2_INDEX) {
- collection->_collection->endRead(collection->_collection);
-
- TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a geo-index")));
}
@@ -1708,6 +1835,33 @@ static v8::Handle<v8::Value> JS_NearQuery (v8::Arguments const& argv) {
StoreGeoResult(collection, cors, documents, distances);
}
+ return scope.Close(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief selects points near a given coordinate
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_NearQuery (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ // extract and use the simple collection
+ v8::Handle<v8::Object> err;
+ TRI_vocbase_col_t const* collection;
+ TRI_sim_collection_t* sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
+
+ if (sim == 0) {
+ return scope.Close(v8::ThrowException(err));
+ }
+
+ // .............................................................................
+ // inside a read transaction
+ // .............................................................................
+
+ collection->_collection->beginRead(collection->_collection);
+
+ v8::Handle<v8::Value> result = NearQuery(sim, collection, &err, argv);
+
collection->_collection->endRead(collection->_collection);
// .............................................................................
@@ -1720,6 +1874,29 @@ static v8::Handle<v8::Value> JS_NearQuery (v8::Arguments const& argv) {
}
////////////////////////////////////////////////////////////////////////////////
+/// @brief selects points near a given coordinate
+///
+/// It is the callers responsibility to acquire and free the required locks
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_NearNLQuery (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ // extract and use the simple collection
+ v8::Handle<v8::Object> err;
+ TRI_vocbase_col_t const* collection;
+ TRI_sim_collection_t* sim = TRI_ExtractSimpleCollection(argv, collection, &err);
+
+ if (sim == 0) {
+ return scope.Close(v8::ThrowException(err));
+ }
+
+ v8::Handle<v8::Value> result = NearQuery(sim, collection, &err, argv);
+
+ return scope.Close(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
/// @brief selects all outbound edges
///
/// @FUN{@FA{edge-collection}.outEdges(@FA{vertex})}
@@ -1743,48 +1920,31 @@ static v8::Handle<v8::Value> JS_OutEdgesQuery (v8::Arguments const& argv) {
////////////////////////////////////////////////////////////////////////////////
/// @brief selects points within a given radius
+///
+/// the caller must ensure all relevant locks are acquired and freed
////////////////////////////////////////////////////////////////////////////////
-static v8::Handle<v8::Value> JS_WithinQuery (v8::Arguments const& argv) {
+static v8::Handle<v8::Value> WithinQuery (TRI_sim_collection_t* sim,
+ TRI_vocbase_col_t const* collection,
+ v8::Handle<v8::Object>* err,
+ v8::Arguments const& argv) {
v8::HandleScope scope;
- // extract and use the simple collection
- v8::Handle<v8::Object> err;
- TRI_vocbase_col_t const* collection;
- TRI_sim_collection_t* sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
-
- if (sim == 0) {
- return scope.Close(v8::ThrowException(err));
- }
-
// expect: WITHIN(<index-handle>, <latitude>, <longitude>, <limit>)
if (argv.Length() != 4) {
- TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
"usage: WITHIN(<index-handle>, <latitude>, <longitude>, <radius>)")));
}
- // .............................................................................
- // inside a read transaction
- // .............................................................................
-
- collection->_collection->beginRead(collection->_collection);
-
// extract the index
- TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, &err);
+ TRI_index_t* idx = TRI_LookupIndexByHandle(sim->base.base._vocbase, collection, argv[0], false, err);
if (idx == 0) {
- collection->_collection->endRead(collection->_collection);
-
- TRI_ReleaseCollection(collection);
- return scope.Close(v8::ThrowException(err));
+ return scope.Close(v8::ThrowException(*err));
}
if (idx->_type != TRI_IDX_TYPE_GEO1_INDEX && idx->_type != TRI_IDX_TYPE_GEO2_INDEX) {
- collection->_collection->endRead(collection->_collection);
-
- TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a geo-index")));
}
@@ -1810,6 +1970,33 @@ static v8::Handle<v8::Value> JS_WithinQuery (v8::Arguments const& argv) {
StoreGeoResult(collection, cors, documents, distances);
}
+ return scope.Close(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief selects points within a given radius
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_WithinQuery (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ // extract and use the simple collection
+ v8::Handle<v8::Object> err;
+ TRI_vocbase_col_t const* collection;
+ TRI_sim_collection_t* sim = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
+
+ if (sim == 0) {
+ return scope.Close(v8::ThrowException(err));
+ }
+
+ // .............................................................................
+ // inside a read transaction
+ // .............................................................................
+
+ collection->_collection->beginRead(collection->_collection);
+
+ v8::Handle<v8::Value> result = WithinQuery(sim, collection, &err, argv);
+
collection->_collection->endRead(collection->_collection);
// .............................................................................
@@ -1817,6 +2004,30 @@ static v8::Handle<v8::Value> JS_WithinQuery (v8::Arguments const& argv) {
// .............................................................................
TRI_ReleaseCollection(collection);
+
+ return scope.Close(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief selects points within a given radius
+///
+/// It is the callers responsibility to acquire and free the required locks
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_WithinNLQuery (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ // extract the simple collection
+ v8::Handle<v8::Object> err;
+ TRI_vocbase_col_t const* collection;
+ TRI_sim_collection_t* sim = TRI_ExtractSimpleCollection(argv, collection, &err);
+
+ if (sim == 0) {
+ return scope.Close(v8::ThrowException(err));
+ }
+
+ v8::Handle<v8::Value> result = WithinQuery(sim, collection, &err, argv);
+
return scope.Close(result);
}
@@ -1860,16 +2071,23 @@ void TRI_InitV8Queries (v8::Handle<v8::Context> context) {
// .............................................................................
v8::Handle<v8::String> AllFuncName = v8::Persistent<v8::String>::New(v8::String::New("ALL"));
+ v8::Handle<v8::String> AllNLFuncName = v8::Persistent<v8::String>::New(v8::String::New("ALL_NL"));
v8::Handle<v8::String> ByConditionSkiplistFuncName = v8::Persistent<v8::String>::New(v8::String::New("BY_CONDITION_SKIPLIST"));
+ v8::Handle<v8::String> ByConditionSkiplistNLFuncName = v8::Persistent<v8::String>::New(v8::String::New("BY_CONDITION_SKIPLIST_NL"));
v8::Handle<v8::String> ByExampleFuncName = v8::Persistent<v8::String>::New(v8::String::New("BY_EXAMPLE"));
v8::Handle<v8::String> ByExampleBitarrayFuncName = v8::Persistent<v8::String>::New(v8::String::New("BY_EXAMPLE_BITARRAY"));
+ v8::Handle<v8::String> ByExampleBitarrayNLFuncName = v8::Persistent<v8::String>::New(v8::String::New("BY_EXAMPLE_BITARRAY_NL"));
v8::Handle<v8::String> ByExampleHashFuncName = v8::Persistent<v8::String>::New(v8::String::New("BY_EXAMPLE_HASH"));
+ v8::Handle<v8::String> ByExampleHashNLFuncName = v8::Persistent<v8::String>::New(v8::String::New("BY_EXAMPLE_HASH_NL"));
v8::Handle<v8::String> ByExampleSkiplistFuncName = v8::Persistent<v8::String>::New(v8::String::New("BY_EXAMPLE_SKIPLIST"));
+ v8::Handle<v8::String> ByExampleSkiplistNLFuncName = v8::Persistent<v8::String>::New(v8::String::New("BY_EXAMPLE_SKIPLIST_NL"));
v8::Handle<v8::String> EdgesFuncName = v8::Persistent<v8::String>::New(v8::String::New("edges"));
v8::Handle<v8::String> InEdgesFuncName = v8::Persistent<v8::String>::New(v8::String::New("inEdges"));
v8::Handle<v8::String> NearFuncName = v8::Persistent<v8::String>::New(v8::String::New("NEAR"));
+ v8::Handle<v8::String> NearNLFuncName = v8::Persistent<v8::String>::New(v8::String::New("NEAR_NL"));
v8::Handle<v8::String> OutEdgesFuncName = v8::Persistent<v8::String>::New(v8::String::New("outEdges"));
v8::Handle<v8::String> WithinFuncName = v8::Persistent<v8::String>::New(v8::String::New("WITHIN"));
+ v8::Handle<v8::String> WithinNLFuncName = v8::Persistent<v8::String>::New(v8::String::New("WITHIN_NL"));
// .............................................................................
// generate the TRI_vocbase_col_t template
@@ -1878,13 +2096,20 @@ void TRI_InitV8Queries (v8::Handle<v8::Context> context) {
rt = v8g->VocbaseColTempl;
rt->Set(AllFuncName, v8::FunctionTemplate::New(JS_AllQuery));
+ rt->Set(AllNLFuncName, v8::FunctionTemplate::New(JS_AllNLQuery));
rt->Set(ByConditionSkiplistFuncName, v8::FunctionTemplate::New(JS_ByConditionSkiplist));
+ rt->Set(ByConditionSkiplistNLFuncName, v8::FunctionTemplate::New(JS_ByConditionNLSkiplist));
rt->Set(ByExampleBitarrayFuncName, v8::FunctionTemplate::New(JS_ByExampleBitarray));
+ rt->Set(ByExampleBitarrayNLFuncName, v8::FunctionTemplate::New(JS_ByExampleNLBitarray));
rt->Set(ByExampleFuncName, v8::FunctionTemplate::New(JS_ByExampleQuery));
rt->Set(ByExampleHashFuncName, v8::FunctionTemplate::New(JS_ByExampleHashIndex));
+ rt->Set(ByExampleHashNLFuncName, v8::FunctionTemplate::New(JS_ByExampleNLHashIndex));
rt->Set(ByExampleSkiplistFuncName, v8::FunctionTemplate::New(JS_ByExampleSkiplist));
+ rt->Set(ByExampleSkiplistNLFuncName, v8::FunctionTemplate::New(JS_ByExampleNLSkiplist));
rt->Set(NearFuncName, v8::FunctionTemplate::New(JS_NearQuery));
+ rt->Set(NearNLFuncName, v8::FunctionTemplate::New(JS_NearNLQuery));
rt->Set(WithinFuncName, v8::FunctionTemplate::New(JS_WithinQuery));
+ rt->Set(WithinNLFuncName, v8::FunctionTemplate::New(JS_WithinNLQuery));
// .............................................................................
// generate the TRI_vocbase_col_t template for edges
@@ -1893,16 +2118,23 @@ void TRI_InitV8Queries (v8::Handle<v8::Context> context) {
rt = v8g->EdgesColTempl;
rt->Set(AllFuncName, v8::FunctionTemplate::New(JS_AllQuery));
+ rt->Set(AllNLFuncName, v8::FunctionTemplate::New(JS_AllNLQuery));
rt->Set(ByConditionSkiplistFuncName, v8::FunctionTemplate::New(JS_ByConditionSkiplist));
+ rt->Set(ByConditionSkiplistNLFuncName, v8::FunctionTemplate::New(JS_ByConditionNLSkiplist));
rt->Set(ByExampleBitarrayFuncName, v8::FunctionTemplate::New(JS_ByExampleBitarray));
+ rt->Set(ByExampleBitarrayNLFuncName, v8::FunctionTemplate::New(JS_ByExampleNLBitarray));
rt->Set(ByExampleFuncName, v8::FunctionTemplate::New(JS_ByExampleQuery));
rt->Set(ByExampleHashFuncName, v8::FunctionTemplate::New(JS_ByExampleHashIndex));
+ rt->Set(ByExampleHashNLFuncName, v8::FunctionTemplate::New(JS_ByExampleNLHashIndex));
rt->Set(ByExampleSkiplistFuncName, v8::FunctionTemplate::New(JS_ByExampleSkiplist));
+ rt->Set(ByExampleSkiplistNLFuncName, v8::FunctionTemplate::New(JS_ByExampleNLSkiplist));
rt->Set(EdgesFuncName, v8::FunctionTemplate::New(JS_EdgesQuery));
rt->Set(InEdgesFuncName, v8::FunctionTemplate::New(JS_InEdgesQuery));
rt->Set(NearFuncName, v8::FunctionTemplate::New(JS_NearQuery));
+ rt->Set(NearNLFuncName, v8::FunctionTemplate::New(JS_NearNLQuery));
rt->Set(OutEdgesFuncName, v8::FunctionTemplate::New(JS_OutEdgesQuery));
rt->Set(WithinFuncName, v8::FunctionTemplate::New(JS_WithinQuery));
+ rt->Set(WithinNLFuncName, v8::FunctionTemplate::New(JS_WithinNLQuery));
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp
index 9bd6923..c92f67d 100755
--- a/arangod/V8Server/v8-vocbase.cpp
+++ b/arangod/V8Server/v8-vocbase.cpp
@@ -117,6 +117,65 @@ static int32_t const WRP_SHAPED_JSON_TYPE = 4;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
+
+// -----------------------------------------------------------------------------
+// --SECTION-- HELPER CLASSES
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// --SECTION-- AhuacatlContextGuard
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup VocBase
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief scope guard for AQL queries
+////////////////////////////////////////////////////////////////////////////////
+
+class AhuacatlContextGuard {
+ public:
+ AhuacatlContextGuard (TRI_vocbase_t* vocbase, const string& query) :
+ _context(0) {
+ _context = TRI_CreateContextAql(vocbase, query.c_str());
+ }
+
+ ~AhuacatlContextGuard () {
+ this->free();
+ }
+
+ 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
@@ -476,14 +535,19 @@ static v8::Handle<v8::Value> EnsurePathIndex (string const& cmd,
////////////////////////////////////////////////////////////////////////////////
/// @brief looks up a document
+///
+/// it is the caller's responsibility to acquire and release the required locks
+/// the collection must also have the correct status already. don't use this
+/// function if you're unsure about it!
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> DocumentVocbaseCol (TRI_vocbase_t* vocbase,
TRI_vocbase_col_t const* collection,
- v8::Arguments const& argv) {
+ v8::Arguments const& argv,
+ const bool lock) {
v8::HandleScope scope;
- // first and only argument schould be a document idenfifier
+ // first and only argument should be a document idenfifier
if (argv.Length() != 1) {
return scope.Close(v8::ThrowException(
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
@@ -492,10 +556,10 @@ static v8::Handle<v8::Value> DocumentVocbaseCol (TRI_vocbase_t* vocbase,
TRI_voc_did_t did;
TRI_voc_rid_t rid;
- v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(vocbase, collection, did, rid, argv[0]);
+ v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(vocbase, collection, did, rid, lock, argv[0]);
if (! err.IsEmpty()) {
- if (collection != 0) {
+ if (collection != 0 && lock) {
TRI_ReleaseCollection(collection);
}
@@ -513,7 +577,9 @@ static v8::Handle<v8::Value> DocumentVocbaseCol (TRI_vocbase_t* vocbase,
// inside a read transaction
// .............................................................................
- collection->_collection->beginRead(collection->_collection);
+ if (lock) {
+ collection->_collection->beginRead(collection->_collection);
+ }
document = collection->_collection->read(collection->_collection, did);
@@ -524,13 +590,17 @@ static v8::Handle<v8::Value> DocumentVocbaseCol (TRI_vocbase_t* vocbase,
result = TRI_WrapShapedJson(collection, &document, barrier);
}
- collection->_collection->endRead(collection->_collection);
+ if (lock) {
+ collection->_collection->endRead(collection->_collection);
+ }
// .............................................................................
// outside a write transaction
// .............................................................................
- TRI_ReleaseCollection(collection);
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
if (document._did == 0) {
return scope.Close(v8::ThrowException(
@@ -571,7 +641,7 @@ static v8::Handle<v8::Value> ReplaceVocbaseCol (TRI_vocbase_t* vocbase,
TRI_voc_did_t did;
TRI_voc_rid_t rid;
- v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(vocbase, collection, did, rid, argv[0]);
+ v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(vocbase, collection, did, rid, true, argv[0]);
if (! err.IsEmpty()) {
if (collection != 0) {
@@ -658,7 +728,7 @@ static v8::Handle<v8::Value> DeleteVocbaseCol (TRI_vocbase_t* vocbase,
TRI_voc_did_t did;
TRI_voc_rid_t rid;
- v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(vocbase, collection, did, rid, argv[0]);
+ v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(vocbase, collection, did, rid, true, argv[0]);
if (! err.IsEmpty()) {
if (collection != 0) {
@@ -1302,9 +1372,7 @@ static v8::Handle<v8::Value> JS_DisposeGeneralCursor (v8::Arguments const& argv)
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::False());
}
////////////////////////////////////////////////////////////////////////////////
@@ -1664,6 +1732,32 @@ static v8::Handle<v8::Value> JS_HasNextGeneralCursor (v8::Arguments const& argv)
TRI_CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @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
@@ -1776,16 +1870,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"))) {
@@ -1834,8 +1928,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 +1943,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 +1956,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,18 +1999,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 +2018,11 @@ 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));
+ context.free();
- 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
@@ -2188,7 +2279,27 @@ static v8::Handle<v8::Value> JS_DocumentVocbaseCol (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(err));
}
- return DocumentVocbaseCol(collection->_vocbase, collection, argv);
+ return DocumentVocbaseCol(collection->_vocbase, collection, argv, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief looks up a document
+///
+/// it is the caller's responsibility to acquire and release the required locks
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_DocumentNLVocbaseCol (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ // extract the collection
+ TRI_vocbase_col_t* col = TRI_UnwrapClass<TRI_vocbase_col_t>(argv.Holder(), WRP_VOCBASE_COL_TYPE);
+ if (col == 0 || col->_collection == 0) {
+ return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_INTERNAL, "cannot use/load collection")));
+ }
+
+ TRI_vocbase_col_t const* collection = col;
+
+ return DocumentVocbaseCol(collection->_vocbase, collection, argv, false);
}
////////////////////////////////////////////////////////////////////////////////
@@ -3034,20 +3145,27 @@ static v8::Handle<v8::Value> JS_FiguresVocbaseCol (v8::Arguments const& argv) {
////////////////////////////////////////////////////////////////////////////////
/// @brief returns information about the indexes
///
-/// @FUN{getIndexes()}
-///
-/// Returns a list of all indexes defined for the collection.
-///
-/// @EXAMPLES
-///
-/// @verbinclude shell_index-read-all
+/// it is the caller's responsibility to acquire and release all required locks
////////////////////////////////////////////////////////////////////////////////
-static v8::Handle<v8::Value> JS_GetIndexesVocbaseCol (v8::Arguments const& argv) {
+static v8::Handle<v8::Value> GetIndexesVocbaseCol (v8::Arguments const& argv,
+ const bool lock) {
v8::HandleScope scope;
v8::Handle<v8::Object> err;
- TRI_vocbase_col_t const* collection = UseCollection(argv.Holder(), &err);
+ TRI_vocbase_col_t const* collection = 0;
+
+ if (lock) {
+ collection = UseCollection(argv.Holder(), &err);
+ }
+ else {
+ TRI_vocbase_col_t const* col = TRI_UnwrapClass<TRI_vocbase_col_t>(argv.Holder(), WRP_VOCBASE_COL_TYPE);
+ if (col == 0 || col->_collection == 0) {
+ return scope.Close(TRI_CreateErrorObject(TRI_ERROR_INTERNAL, "cannot use/load collection"));;
+ }
+
+ collection = col;
+ }
if (collection == 0) {
return scope.Close(v8::ThrowException(err));
@@ -3056,14 +3174,20 @@ static v8::Handle<v8::Value> JS_GetIndexesVocbaseCol (v8::Arguments const& argv)
TRI_doc_collection_t* doc = collection->_collection;
if (doc->base._type != TRI_COL_TYPE_SIMPLE_DOCUMENT) {
- TRI_ReleaseCollection(collection);
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
return scope.Close(v8::ThrowException(v8::String::New("unknown collection type")));
}
TRI_sim_collection_t* sim = (TRI_sim_collection_t*) doc;
// get a list of indexes
- TRI_vector_pointer_t* indexes = TRI_IndexesSimCollection(sim);
+ TRI_vector_pointer_t* indexes = TRI_IndexesSimCollection(sim, lock);
+
+ if (lock) {
+ TRI_ReleaseCollection(collection);
+ }
if (!indexes) {
return scope.Close(v8::ThrowException(v8::String::New("out of memory")));
@@ -3082,12 +3206,36 @@ static v8::Handle<v8::Value> JS_GetIndexesVocbaseCol (v8::Arguments const& argv)
}
}
- TRI_ReleaseCollection(collection);
-
TRI_FreeVectorPointer(TRI_UNKNOWN_MEM_ZONE, indexes);
return scope.Close(result);
}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief returns information about the indexes
+///
+/// @FUN{getIndexes()}
+///
+/// Returns a list of all indexes defined for the collection.
+///
+/// @EXAMPLES
+///
+/// @verbinclude shell_index-read-all
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_GetIndexesVocbaseCol (v8::Arguments const& argv) {
+ return GetIndexesVocbaseCol(argv, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief returns information about the indexes
+///
+/// it is the caller's responsibility to acquire and release all required locks
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_GetIndexesNLVocbaseCol (v8::Arguments const& argv) {
+ return GetIndexesVocbaseCol(argv, false);
+}
////////////////////////////////////////////////////////////////////////////////
/// @brief loads a collection
@@ -3657,7 +3805,7 @@ static v8::Handle<v8::Value> JS_SaveEdgesCol (v8::Arguments const& argv) {
TRI_vocbase_col_t const* fromCollection = 0;
TRI_voc_rid_t fromRid;
- errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, fromCollection, edge._fromDid, fromRid, argv[0]);
+ errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, fromCollection, edge._fromDid, fromRid, true, argv[0]);
if (! errMsg.IsEmpty()) {
TRI_ReleaseCollection(collection);
@@ -3676,7 +3824,7 @@ static v8::Handle<v8::Value> JS_SaveEdgesCol (v8::Arguments const& argv) {
TRI_vocbase_col_t const* toCollection = 0;
TRI_voc_rid_t toRid;
- errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, toCollection, edge._toDid, toRid, argv[1]);
+ errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, toCollection, edge._toDid, toRid, true, argv[1]);
if (! errMsg.IsEmpty()) {
TRI_ReleaseCollection(collection);
@@ -4024,7 +4172,27 @@ static v8::Handle<v8::Value> JS_DocumentVocbase (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
- return DocumentVocbaseCol(vocbase, 0, argv);
+ return DocumentVocbaseCol(vocbase, 0, argv, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief looks up a document
+///
+/// it is the caller's responsibility to acquire and release the required locks
+/// the collection must also have the correct status already. don't use this
+/// function if you're unsure about it!
+////////////////////////////////////////////////////////////////////////////////
+
+static v8::Handle<v8::Value> JS_DocumentNLVocbase (v8::Arguments const& argv) {
+ v8::HandleScope scope;
+
+ TRI_vocbase_t* vocbase = TRI_UnwrapClass<TRI_vocbase_t>(argv.Holder(), WRP_VOCBASE_TYPE);
+
+ if (vocbase == 0) {
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
+ }
+
+ return DocumentVocbaseCol(vocbase, 0, argv, false);
}
////////////////////////////////////////////////////////////////////////////////
@@ -4470,6 +4638,38 @@ static v8::Handle<v8::Integer> PropertyQueryShapedJson (v8::Local<v8::String> na
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
+/// @brief extracts the collection, but doesn't lock it
+///
+/// it is the caller's responsibility to acquire and release the required locks
+/// the collection must also have the correct status already. don't use this
+/// function if you're unsure about it!
+////////////////////////////////////////////////////////////////////////////////
+
+TRI_sim_collection_t* TRI_ExtractSimpleCollection (v8::Arguments const& argv,
+ TRI_vocbase_col_t const*& collection,
+ v8::Handle<v8::Object>* err) {
+ // extract the collection
+ v8::Handle<v8::Object> operand = argv.Holder();
+
+ TRI_vocbase_col_t* col = TRI_UnwrapClass<TRI_vocbase_col_t>(argv.Holder(), WRP_VOCBASE_COL_TYPE);
+ if (col == 0 || col->_collection == 0) {
+ return 0;
+ }
+
+ collection = col;
+
+ // handle various collection types
+ TRI_doc_collection_t* doc = collection->_collection;
+
+ if (doc->base._type != TRI_COL_TYPE_SIMPLE_DOCUMENT) {
+ *err = TRI_CreateErrorObject(TRI_ERROR_INTERNAL, "unknown collection type");
+ return 0;
+ }
+
+ return (TRI_sim_collection_t*) doc;
+}
+
+////////////////////////////////////////////////////////////////////////////////
/// @brief extracts and locks the collection
////////////////////////////////////////////////////////////////////////////////
@@ -4516,6 +4716,7 @@ v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (TRI_vocbase_t* vocbase,
TRI_vocbase_col_t const*& collection,
TRI_voc_did_t& did,
TRI_voc_rid_t& rid,
+ const bool lock,
v8::Handle<v8::Value> val) {
v8::HandleScope scope;
TRI_v8_global_t* v8g;
@@ -4567,11 +4768,13 @@ v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (TRI_vocbase_t* vocbase,
"collection of <document-handle> is unknown"));;
}
- // use the collection
- int res = TRI_UseCollectionVocBase(vocbase, vc);
+ if (lock) {
+ // use the collection
+ int res = TRI_UseCollectionVocBase(vocbase, vc);
- if (res != TRI_ERROR_NO_ERROR) {
- return scope.Close(TRI_CreateErrorObject(res, "cannot use/load collection"));;
+ if (res != TRI_ERROR_NO_ERROR) {
+ return scope.Close(TRI_CreateErrorObject(res, "cannot use/load collection"));;
+ }
}
collection = vc;
@@ -4872,6 +5075,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocba
v8::Handle<v8::String> DatafilesFuncName = v8::Persistent<v8::String>::New(v8::String::New("datafiles"));
v8::Handle<v8::String> DisposeFuncName = v8::Persistent<v8::String>::New(v8::String::New("dispose"));
v8::Handle<v8::String> DocumentFuncName = v8::Persistent<v8::String>::New(v8::String::New("document"));
+ v8::Handle<v8::String> DocumentNLFuncName = v8::Persistent<v8::String>::New(v8::String::New("document_nl"));
v8::Handle<v8::String> DropFuncName = v8::Persistent<v8::String>::New(v8::String::New("drop"));
v8::Handle<v8::String> DropIndexFuncName = v8::Persistent<v8::String>::New(v8::String::New("dropIndex"));
v8::Handle<v8::String> EnsureBitarrayFuncName = v8::Persistent<v8::String>::New(v8::String::New("ensureBitarray"));
@@ -4887,6 +5091,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocba
v8::Handle<v8::String> FiguresFuncName = v8::Persistent<v8::String>::New(v8::String::New("figures"));
v8::Handle<v8::String> GetBatchSizeFuncName = v8::Persistent<v8::String>::New(v8::String::New("getBatchSize"));
v8::Handle<v8::String> GetIndexesFuncName = v8::Persistent<v8::String>::New(v8::String::New("getIndexes"));
+ v8::Handle<v8::String> GetIndexesNLFuncName = v8::Persistent<v8::String>::New(v8::String::New("getIndexesNL"));
v8::Handle<v8::String> GetRowsFuncName = v8::Persistent<v8::String>::New(v8::String::New("getRows"));
v8::Handle<v8::String> HasCountFuncName = v8::Persistent<v8::String>::New(v8::String::New("hasCount"));
v8::Handle<v8::String> HasNextFuncName = v8::Persistent<v8::String>::New(v8::String::New("hasNext"));
@@ -4907,6 +5112,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"));
@@ -4914,6 +5120,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocba
v8::Handle<v8::String> _CreateFuncName = v8::Persistent<v8::String>::New(v8::String::New("_create"));
v8::Handle<v8::String> _RemoveFuncName = v8::Persistent<v8::String>::New(v8::String::New("_remove"));
v8::Handle<v8::String> _DocumentFuncName = v8::Persistent<v8::String>::New(v8::String::New("_document"));
+ v8::Handle<v8::String> _DocumentNLFuncName = v8::Persistent<v8::String>::New(v8::String::New("_document_nl"));
v8::Handle<v8::String> _ReplaceFuncName = v8::Persistent<v8::String>::New(v8::String::New("_replace"));
// .............................................................................
@@ -4972,6 +5179,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocba
rt->Set(_RemoveFuncName, v8::FunctionTemplate::New(JS_RemoveVocbase));
rt->Set(_DocumentFuncName, v8::FunctionTemplate::New(JS_DocumentVocbase));
+ rt->Set(_DocumentNLFuncName, v8::FunctionTemplate::New(JS_DocumentNLVocbase));
rt->Set(_ReplaceFuncName, v8::FunctionTemplate::New(JS_ReplaceVocbase));
v8g->VocbaseTempl = v8::Persistent<v8::ObjectTemplate>::New(rt);
@@ -4999,6 +5207,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocba
rt->Set(_RemoveFuncName, v8::FunctionTemplate::New(JS_RemoveVocbase));
rt->Set(_DocumentFuncName, v8::FunctionTemplate::New(JS_DocumentVocbase));
+ rt->Set(_DocumentNLFuncName, v8::FunctionTemplate::New(JS_DocumentNLVocbase));
rt->Set(_ReplaceFuncName, v8::FunctionTemplate::New(JS_ReplaceVocbase));
v8g->EdgesTempl = v8::Persistent<v8::ObjectTemplate>::New(rt);
@@ -5046,6 +5255,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocba
rt->Set(CountFuncName, v8::FunctionTemplate::New(JS_CountVocbaseCol));
rt->Set(DocumentFuncName, v8::FunctionTemplate::New(JS_DocumentVocbaseCol));
+ rt->Set(DocumentNLFuncName, v8::FunctionTemplate::New(JS_DocumentNLVocbaseCol));
rt->Set(DropFuncName, v8::FunctionTemplate::New(JS_DropVocbaseCol));
rt->Set(DropIndexFuncName, v8::FunctionTemplate::New(JS_DropIndexVocbaseCol));
rt->Set(EnsureBitarrayFuncName, v8::FunctionTemplate::New(JS_EnsureBitarrayVocbaseCol));
@@ -5062,6 +5272,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocba
rt->Set(DatafilesFuncName, v8::FunctionTemplate::New(JS_DatafilesVocbaseCol));
rt->Set(FiguresFuncName, v8::FunctionTemplate::New(JS_FiguresVocbaseCol));
rt->Set(GetIndexesFuncName, v8::FunctionTemplate::New(JS_GetIndexesVocbaseCol));
+ rt->Set(GetIndexesNLFuncName, v8::FunctionTemplate::New(JS_GetIndexesNLVocbaseCol));
rt->Set(LoadFuncName, v8::FunctionTemplate::New(JS_LoadVocbaseCol));
rt->Set(LookupHashIndexFuncName, v8::FunctionTemplate::New(JS_LookupHashIndexVocbaseCol));
rt->Set(LookupSkiplistFuncName, v8::FunctionTemplate::New(JS_LookupSkiplistVocbaseCol));
@@ -5112,6 +5323,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocba
rt->Set(DatafilesFuncName, v8::FunctionTemplate::New(JS_DatafilesVocbaseCol));
rt->Set(FiguresFuncName, v8::FunctionTemplate::New(JS_FiguresVocbaseCol));
rt->Set(GetIndexesFuncName, v8::FunctionTemplate::New(JS_GetIndexesVocbaseCol));
+ rt->Set(GetIndexesNLFuncName, v8::FunctionTemplate::New(JS_GetIndexesNLVocbaseCol));
rt->Set(LoadFuncName, v8::FunctionTemplate::New(JS_LoadVocbaseCol));
rt->Set(LookupHashIndexFuncName, v8::FunctionTemplate::New(JS_LookupHashIndexVocbaseCol));
rt->Set(LookupSkiplistFuncName, v8::FunctionTemplate::New(JS_LookupSkiplistVocbaseCol));
@@ -5165,6 +5377,7 @@ 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);
diff --git a/arangod/V8Server/v8-vocbase.h b/arangod/V8Server/v8-vocbase.h
index fd28c1a..0057617 100644
--- a/arangod/V8Server/v8-vocbase.h
+++ b/arangod/V8Server/v8-vocbase.h
@@ -42,6 +42,18 @@
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
+/// @brief extracts the collection, but doesn't lock it
+///
+/// it is the caller's responsibility to acquire and release the required locks
+/// the collection must also have the correct status already. don't use this
+/// function if you're unsure about it!
+////////////////////////////////////////////////////////////////////////////////
+
+TRI_sim_collection_t* TRI_ExtractSimpleCollection (v8::Arguments const& argv,
+ TRI_vocbase_col_t const*& collection,
+ v8::Handle<v8::Object>* err);
+
+////////////////////////////////////////////////////////////////////////////////
/// @brief extracts and locks the collection
////////////////////////////////////////////////////////////////////////////////
@@ -63,6 +75,7 @@ v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (TRI_vocbase_t* vocbase,
TRI_vocbase_col_t const*& collection,
TRI_voc_did_t& did,
TRI_voc_rid_t& rid,
+ const bool lock,
v8::Handle<v8::Value> val);
////////////////////////////////////////////////////////////////////////////////
diff --git a/arangod/VocBase/compactor.c b/arangod/VocBase/compactor.c
index 2809b17..13ef8fb 100644
--- a/arangod/VocBase/compactor.c
+++ b/arangod/VocBase/compactor.c
@@ -538,10 +538,8 @@ 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);
+ TRI_CleanupShadowData(vocbase->_cursors, (double) SHADOW_CURSOR_MAX_AGE, force);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/arangod/VocBase/shadow-data.c b/arangod/VocBase/shadow-data.c
index b664156..873fc66 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
}
@@ -400,7 +404,7 @@ void TRI_EndUsageIdShadowData (TRI_shadow_store_t* const store,
TRI_LockMutex(&store->_lock);
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, &id);
- 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) {
@@ -540,8 +552,13 @@ void TRI_CleanupShadowData (TRI_shadow_store_t* const store,
if (shadow->_rc < 1 || force) {
if (shadow->_type == SHADOW_TRANSIENT ||
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..fa13261 100644
--- a/arangod/VocBase/simple-collection.c
+++ b/arangod/VocBase/simple-collection.c
@@ -2868,7 +2868,8 @@ static int ComparePidName (void const* left, void const* right) {
/// @brief returns a description of all indexes
////////////////////////////////////////////////////////////////////////////////
-TRI_vector_pointer_t* TRI_IndexesSimCollection (TRI_sim_collection_t* sim) {
+TRI_vector_pointer_t* TRI_IndexesSimCollection (TRI_sim_collection_t* sim,
+ const bool lock) {
TRI_vector_pointer_t* vector;
size_t n;
size_t i;
@@ -2884,7 +2885,9 @@ TRI_vector_pointer_t* TRI_IndexesSimCollection (TRI_sim_collection_t* sim) {
// inside read-lock
// .............................................................................
- TRI_READ_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim);
+ if (lock) {
+ TRI_READ_LOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim);
+ }
n = sim->_indexes._length;
@@ -2901,7 +2904,9 @@ TRI_vector_pointer_t* TRI_IndexesSimCollection (TRI_sim_collection_t* sim) {
}
}
- TRI_READ_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim);
+ if (lock) {
+ TRI_READ_UNLOCK_DOCUMENTS_INDEXES_SIM_COLLECTION(sim);
+ }
// .............................................................................
// outside read-lock
diff --git a/arangod/VocBase/simple-collection.h b/arangod/VocBase/simple-collection.h
index 1a8c2e7..c5cce0a 100644
--- a/arangod/VocBase/simple-collection.h
+++ b/arangod/VocBase/simple-collection.h
@@ -349,7 +349,8 @@ int TRI_CloseSimCollection (TRI_sim_collection_t* collection);
/// @brief returns a description of all indexes
////////////////////////////////////////////////////////////////////////////////
-TRI_vector_pointer_t* TRI_IndexesSimCollection (TRI_sim_collection_t*);
+TRI_vector_pointer_t* TRI_IndexesSimCollection (TRI_sim_collection_t*,
+ const bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief drops an index
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/server/ahuacatl.js b/js/server/ahuacatl.js
index 665f723..9c6de31 100644
--- a/js/server/ahuacatl.js
+++ b/js/server/ahuacatl.js
@@ -70,7 +70,7 @@ function AHUACATL_THROW (error, data) {
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_INDEX (collection, indexTypes) {
- var indexes = collection.getIndexes();
+ var indexes = collection.getIndexesNL();
for (var i = 0; i < indexes.length; ++i) {
var index = indexes[i];
@@ -385,7 +385,7 @@ function AHUACATL_LIST (value) {
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_GET_DOCUMENTS (collection) {
- return internal.db[collection].all().toArray();
+ return internal.db[collection].ALL_NL(0, null).documents;
}
////////////////////////////////////////////////////////////////////////////////
@@ -395,7 +395,7 @@ function AHUACATL_GET_DOCUMENTS (collection) {
function AHUACATL_GET_DOCUMENTS_PRIMARY (collection, idx, id) {
try {
- return [ internal.db[collection].document(id) ];
+ return [ internal.db[collection].document_nl(id) ];
}
catch (e) {
return [ ];
@@ -413,7 +413,7 @@ function AHUACATL_GET_DOCUMENTS_PRIMARY_LIST (collection, idx, values) {
for (var i in values) {
var id = values[i];
try {
- var d = internal.db[collection].document(id);
+ var d = internal.db[collection].document_nl(id);
result.push(d);
}
catch (e) {
@@ -429,7 +429,7 @@ function AHUACATL_GET_DOCUMENTS_PRIMARY_LIST (collection, idx, values) {
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_GET_DOCUMENTS_HASH (collection, idx, example) {
- return internal.db[collection].BY_EXAMPLE_HASH(idx, example).documents;
+ return internal.db[collection].BY_EXAMPLE_HASH_NL(idx, example).documents;
}
////////////////////////////////////////////////////////////////////////////////
@@ -446,7 +446,7 @@ function AHUACATL_GET_DOCUMENTS_HASH_LIST (collection, idx, attribute, values) {
example[attribute] = value;
- var documents = internal.db[collection].BY_EXAMPLE_HASH(idx, example).documents;
+ var documents = internal.db[collection].BY_EXAMPLE_HASH_NL(idx, example).documents;
for (var j in documents) {
result.push(documents[j]);
}
@@ -460,7 +460,7 @@ function AHUACATL_GET_DOCUMENTS_HASH_LIST (collection, idx, attribute, values) {
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_GET_DOCUMENTS_SKIPLIST (collection, idx, example) {
- return internal.db[collection].BY_CONDITION_SKIPLIST(idx, example).documents;
+ return internal.db[collection].BY_CONDITION_SKIPLIST_NL(idx, example).documents;
}
////////////////////////////////////////////////////////////////////////////////
@@ -477,7 +477,7 @@ function AHUACATL_GET_DOCUMENTS_SKIPLIST_LIST (collection, idx, attribute, value
example[attribute] = value;
- var documents = internal.db[collection].BY_EXAMPLE_SKIPLIST(idx, example).documents;
+ var documents = internal.db[collection].BY_EXAMPLE_SKIPLIST_NL(idx, example).documents;
for (var j in documents) {
result.push(documents[j]);
}
@@ -1850,7 +1850,7 @@ function AHUACATL_GEO_NEAR () {
AHUACATL_THROW(internal.errors.ERROR_QUERY_GEO_INDEX_MISSING, collection);
}
- var result = internal.db[collection].NEAR(idx, latitude, longitude, limit);
+ var result = internal.db[collection].NEAR_NL(idx, latitude, longitude, limit);
if (distanceAttribute == null) {
return result.documents;
}
@@ -1882,7 +1882,7 @@ function AHUACATL_GEO_WITHIN () {
AHUACATL_THROW(internal.errors.ERROR_QUERY_GEO_INDEX_MISSING, collection);
}
- var result = internal.db[collection].WITHIN(idx, latitude, longitude, radius);
+ var result = internal.db[collection].WITHIN_NL(idx, latitude, longitude, radius);
if (distanceAttribute == null) {
return result.documents;
}
@@ -2027,7 +2027,7 @@ function AHUACATL_GRAPH_SUBNODES (searchAttributes, vertexId, visited, edges, ve
var clonedEdges = AHUACATL_CLONE(edges);
var clonedVertices = AHUACATL_CLONE(vertices);
clonedEdges.push(subEdge);
- clonedVertices.push(internal.db._document(targetId));
+ clonedVertices.push(internal.db._document_nl(targetId));
var connected = AHUACATL_GRAPH_SUBNODES(searchAttributes, targetId, AHUACATL_CLONE(visited), clonedEdges, clonedVertices, level + 1);
for (k = 0; k < connected.length; ++k) {
diff --git a/js/server/js-ahuacatl.h b/js/server/js-ahuacatl.h
index 7bf2dd5..2115bad 100644
--- a/js/server/js-ahuacatl.h
+++ b/js/server/js-ahuacatl.h
@@ -71,7 +71,7 @@ static string JS_server_ahuacatl =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_INDEX (collection, indexTypes) {\n"
- " var indexes = collection.getIndexes();\n"
+ " var indexes = collection.getIndexesNL();\n"
"\n"
" for (var i = 0; i < indexes.length; ++i) {\n"
" var index = indexes[i];\n"
@@ -386,7 +386,7 @@ static string JS_server_ahuacatl =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_GET_DOCUMENTS (collection) {\n"
- " return internal.db[collection].all().toArray();\n"
+ " return internal.db[collection].ALL_NL(0, null).documents;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
@@ -396,7 +396,7 @@ static string JS_server_ahuacatl =
"\n"
"function AHUACATL_GET_DOCUMENTS_PRIMARY (collection, idx, id) {\n"
" try {\n"
- " return [ internal.db[collection].document(id) ];\n"
+ " return [ internal.db[collection].document_nl(id) ];\n"
" }\n"
" catch (e) {\n"
" return [ ];\n"
@@ -414,7 +414,7 @@ static string JS_server_ahuacatl =
" for (var i in values) {\n"
" var id = values[i];\n"
" try {\n"
- " var d = internal.db[collection].document(id);\n"
+ " var d = internal.db[collection].document_nl(id);\n"
" result.push(d);\n"
" }\n"
" catch (e) {\n"
@@ -430,7 +430,7 @@ static string JS_server_ahuacatl =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_GET_DOCUMENTS_HASH (collection, idx, example) {\n"
- " return internal.db[collection].BY_EXAMPLE_HASH(idx, example).documents;\n"
+ " return internal.db[collection].BY_EXAMPLE_HASH_NL(idx, example).documents;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
@@ -447,7 +447,7 @@ static string JS_server_ahuacatl =
"\n"
" example[attribute] = value;\n"
"\n"
- " var documents = internal.db[collection].BY_EXAMPLE_HASH(idx, example).documents;\n"
+ " var documents = internal.db[collection].BY_EXAMPLE_HASH_NL(idx, example).documents;\n"
" for (var j in documents) {\n"
" result.push(documents[j]);\n"
" }\n"
@@ -461,7 +461,7 @@ static string JS_server_ahuacatl =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_GET_DOCUMENTS_SKIPLIST (collection, idx, example) {\n"
- " return internal.db[collection].BY_CONDITION_SKIPLIST(idx, example).documents;\n"
+ " return internal.db[collection].BY_CONDITION_SKIPLIST_NL(idx, example).documents;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
@@ -478,7 +478,7 @@ static string JS_server_ahuacatl =
"\n"
" example[attribute] = value;\n"
"\n"
- " var documents = internal.db[collection].BY_EXAMPLE_SKIPLIST(idx, example).documents;\n"
+ " var documents = internal.db[collection].BY_EXAMPLE_SKIPLIST_NL(idx, example).documents;\n"
" for (var j in documents) {\n"
" result.push(documents[j]);\n"
" }\n"
@@ -1851,7 +1851,7 @@ static string JS_server_ahuacatl =
" AHUACATL_THROW(internal.errors.ERROR_QUERY_GEO_INDEX_MISSING, collection);\n"
" }\n"
"\n"
- " var result = internal.db[collection].NEAR(idx, latitude, longitude, limit);\n"
+ " var result = internal.db[collection].NEAR_NL(idx, latitude, longitude, limit);\n"
" if (distanceAttribute == null) {\n"
" return result.documents;\n"
" }\n"
@@ -1883,7 +1883,7 @@ static string JS_server_ahuacatl =
" AHUACATL_THROW(internal.errors.ERROR_QUERY_GEO_INDEX_MISSING, collection);\n"
" }\n"
"\n"
- " var result = internal.db[collection].WITHIN(idx, latitude, longitude, radius);\n"
+ " var result = internal.db[collection].WITHIN_NL(idx, latitude, longitude, radius);\n"
" if (distanceAttribute == null) {\n"
" return result.documents;\n"
" }\n"
@@ -2028,7 +2028,7 @@ static string JS_server_ahuacatl =
" var clonedEdges = AHUACATL_CLONE(edges);\n"
" var clonedVertices = AHUACATL_CLONE(vertices);\n"
" clonedEdges.push(subEdge);\n"
- " clonedVertices.push(internal.db._document(targetId));\n"
+ " clonedVertices.push(internal.db._document_nl(targetId));\n"
" \n"
" var connected = AHUACATL_GRAPH_SUBNODES(searchAttributes, targetId, AHUACATL_CLONE(visited), clonedEdges, clonedVertices, level + 1);\n"
" for (k = 0; k < connected.length; ++k) {\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..006f8cc 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, with a timeout
+////////////////////////////////////////////////////////////////////////////////
+
+ bool wait (uint64_t);
+
+////////////////////////////////////////////////////////////////////////////////
/// @brief broadcasts an event
////////////////////////////////////////////////////////////////////////////////