From cd9df3460e875dd9ae99ac9dafb2d1e6b7e5ecec Mon Sep 17 00:00:00 2001 From: Aurelijus Banelis Date: Sat, 15 Aug 2015 22:22:27 +0300 Subject: [PATCH 01/29] Documentation: Example of user data in _createDatabase --- arangod/V8Server/v8-vocbase.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index ea4801627b..3101fe60eb 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -3357,8 +3357,13 @@ static void CreateDatabaseCoordinator (const v8::FunctionCallbackInfo /// require("org/arangodb/users").update(username, password, true); /// require("org/arangodb/users").remove(username); /// ``` +/// Alternatively, you can specify user data directly. For example: /// -/// This method can only be used from within the *_system* database. +/// ```js +/// db._createDatabase("newDB", [], [{ username: "newUser", passwd: "123456", active: true}]) +/// ``` +/// +/// Those methods can only be used from within the *_system* database. /// @endDocuBlock //////////////////////////////////////////////////////////////////////////////// From 078db04650d67905450549678aac1c8e2ce2e8db Mon Sep 17 00:00:00 2001 From: Aurelijus Banelis Date: Sat, 15 Aug 2015 22:28:51 +0300 Subject: [PATCH 02/29] Git ignore for CMAKE generated files --- .gitignore | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.gitignore b/.gitignore index b3007ed5cf..0d5b59e6c1 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,22 @@ core TAGS tags +CMakeCache.txt +CMakeFiles/ +CPackConfig.cmake +CPackSourceConfig.cmake +CTestTestfile.cmake +UnitTests/CMakeFiles/ +UnitTests/CTestTestfile.cmake +UnitTests/cmake_install.cmake +arangod/CMakeFiles/ +arangod/cmake_install.cmake +arangosh/CMakeFiles/ +arangosh/cmake_install.cmake +cmake_install.cmake +lib/CMakeFiles/ +lib/cmake_install.cmake + Documentation/Examples/*.generated Documentation/Books/Users/book.json Documentation/Books/Users/manual.epub From 9c075561f45011c842aace24de62926801e35553 Mon Sep 17 00:00:00 2001 From: Aurelijus Banelis Date: Sun, 16 Aug 2015 17:25:27 +0300 Subject: [PATCH 03/29] Documentation: collection.updateByExample can append not only change From example it was not clear, that old fields are left unchanged. So it is not confused with replace whole document: replaceByExample --- ...cumentsCollectionUpdateByExample.generated | 19 +++++++++++++++---- .../org/arangodb/arango-collection-common.js | 6 +++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Documentation/Examples/012_documentsCollectionUpdateByExample.generated b/Documentation/Examples/012_documentsCollectionUpdateByExample.generated index dcf31f1d79..f3431b6222 100644 --- a/Documentation/Examples/012_documentsCollectionUpdateByExample.generated +++ b/Documentation/Examples/012_documentsCollectionUpdateByExample.generated @@ -1,8 +1,19 @@ -arangosh> db.example.save({ Hello : "world" }); +arangosh> db.example.save({ Hello : "world", foo : "bar" }); { - "_id" : "example/450753419", - "_rev" : "450753419", - "_key" : "450753419" + "_id" : "example/450817260", + "_rev" : "450817260", + "_key" : "450817260" } arangosh> db.example.updateByExample({ Hello: "world" }, { Hello: "foo", World: "bar" }, false); 1 +arangosh> db.example.byExample({ Hello: "foo" }).toArray() +[ + { + "_id" : "example/450817260", + "_key" : "450817260", + "_rev" : "451144940", + "Hello" : "foo", + "foo" : "bar", + "World" : "bar" + } +] diff --git a/js/common/modules/org/arangodb/arango-collection-common.js b/js/common/modules/org/arangodb/arango-collection-common.js index a1c6c38023..3c048c46f3 100644 --- a/js/common/modules/org/arangodb/arango-collection-common.js +++ b/js/common/modules/org/arangodb/arango-collection-common.js @@ -989,6 +989,9 @@ ArangoCollection.prototype.replaceByExample = function (example, newValue, waitF /// The document meta-attributes such as *_id*, *_key*, *_from*, /// *_to* cannot be updated. /// +/// Partial update could also be used to append new fields, +/// if there were no old field with same name. +/// /// `collection.updateByExample(document, newValue, keepNull, waitForSync)` /// /// The optional *keepNull* parameter can be used to modify the behavior when @@ -1019,8 +1022,9 @@ ArangoCollection.prototype.replaceByExample = function (example, newValue, waitF /// /// @EXAMPLE_ARANGOSH_OUTPUT{012_documentsCollectionUpdateByExample} /// ~ db._create("example"); -/// db.example.save({ Hello : "world" }); +/// db.example.save({ Hello : "world", foo : "bar" }); /// db.example.updateByExample({ Hello: "world" }, { Hello: "foo", World: "bar" }, false); +/// db.example.byExample({ Hello: "foo" }).toArray() /// ~ db._drop("example"); /// @END_EXAMPLE_ARANGOSH_OUTPUT /// @endDocuBlock From 9c7c1ad88b7ca9e8d7c7c0439780a94f423bc0d4 Mon Sep 17 00:00:00 2001 From: Aurelijus Banelis Date: Sun, 16 Aug 2015 18:56:45 +0300 Subject: [PATCH 04/29] Documentation: include createEdgeCollection in example As it is useful for newcomer to know, how to create "vertex" and "relation". It is first example, so all inforamtion should be included to try example. --- arangod/V8Server/v8-collection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arangod/V8Server/v8-collection.cpp b/arangod/V8Server/v8-collection.cpp index 1f9ae04403..c73a982400 100644 --- a/arangod/V8Server/v8-collection.cpp +++ b/arangod/V8Server/v8-collection.cpp @@ -2963,8 +2963,8 @@ static string GetId (const v8::FunctionCallbackInfo& args, int which) /// @EXAMPLES /// /// @EXAMPLE_ARANGOSH_OUTPUT{EDGCOL_01_SaveEdgeCol} -/// ~ db._create("vertex"); -/// ~ db._createEdgeCollection("relation"); +/// db._create("vertex"); +/// db._createEdgeCollection("relation"); /// v1 = db.vertex.insert({ name : "vertex 1" }); /// v2 = db.vertex.insert({ name : "vertex 2" }); /// e1 = db.relation.insert(v1, v2, { label : "knows" }); From 3dce622c8212e4b8b1d09f909760d68a3fd833b0 Mon Sep 17 00:00:00 2001 From: Aurelijus Banelis Date: Sun, 16 Aug 2015 18:59:55 +0300 Subject: [PATCH 05/29] Documentation: How to update edge From context it was confusing about changing type/edge/field of collection/document/edge. It is very important to know, how to change edge, as it is second most used operation in graph database (first is graph traversal). --- Documentation/Books/Users/Edges/README.mdpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/Books/Users/Edges/README.mdpp b/Documentation/Books/Users/Edges/README.mdpp index 0af6e87174..9321d3ae16 100644 --- a/Documentation/Books/Users/Edges/README.mdpp +++ b/Documentation/Books/Users/Edges/README.mdpp @@ -13,6 +13,9 @@ The values of *_from* and *_to* are immutable once saved. are connection documents that reference other documents. The type of a collection must be specified when a collection is created and cannot be changed afterwards. +To change edge endpoints you would need to remove old document/edge and insert new one. +Other fields can be updated as in default collection. + !SECTION Working with Edges !SUBSECTION Insert From b318d2939e831c6424cc8e668bb1c1f5b9e33f69 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 17 Aug 2015 14:58:48 +0200 Subject: [PATCH 06/29] save master's last log tick in dump file --- arangosh/V8Client/arangodump.cpp | 61 ++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/arangosh/V8Client/arangodump.cpp b/arangosh/V8Client/arangodump.cpp index 2189193e2b..e1bc52ffa6 100644 --- a/arangosh/V8Client/arangodump.cpp +++ b/arangosh/V8Client/arangodump.cpp @@ -500,7 +500,7 @@ static void EndBatch (string DBserver) { const string url = "/_api/replication/batch/" + StringUtils::itoa(BatchId); string urlExt; if (! DBserver.empty()) { - urlExt = "?DBserver="+DBserver; + urlExt = "?DBserver=" + DBserver; } BatchId = 0; @@ -716,6 +716,7 @@ static int RunDump (string& errorMsg) { return TRI_ERROR_INTERNAL; } + // read the server's max tick value const string tickString = JsonHelper::getStringValue(json, "tick", ""); if (tickString == "") { @@ -726,15 +727,62 @@ static int RunDump (string& errorMsg) { } cout << "Last tick provided by server is: " << tickString << endl; - - // read the server's max tick value + uint64_t maxTick = StringUtils::uint64(tickString); - - // check if the user specific a max tick value + // check if the user specified a max tick value if (TickEnd > 0 && maxTick > TickEnd) { maxTick = TickEnd; } + + { + TRI_json_t* meta = TRI_CreateObjectJson(TRI_UNKNOWN_MEM_ZONE); + + if (meta == nullptr) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + errorMsg = "out of memory"; + + return TRI_ERROR_OUT_OF_MEMORY; + } + + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, meta, "database", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, BaseClient.databaseName().c_str(), BaseClient.databaseName().size())); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, meta, "lastTickAtDumpStart", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, tickString.c_str(), tickString.size())); + + // save last tick in file + string fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + "dump.json"; + + int fd; + + // remove an existing file first + if (TRI_ExistsFile(fileName.c_str())) { + TRI_UnlinkFile(fileName.c_str()); + } + + fd = TRI_CREATE(fileName.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); + + if (fd < 0) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, meta); + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + errorMsg = "cannot write to file '" + fileName + "'"; + + return TRI_ERROR_CANNOT_WRITE_FILE; + } + + const string metaString = JsonHelper::toString(meta); + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, meta); + + if (! TRI_WritePointer(fd, metaString.c_str(), metaString.size())) { + TRI_CLOSE(fd); + errorMsg = "cannot write to file '" + fileName + "'"; + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + + return TRI_ERROR_CANNOT_WRITE_FILE; + } + + TRI_CLOSE(fd); + } + + // create a lookup table for collections map restrictList; for (size_t i = 0; i < Collections.size(); ++i) { @@ -798,8 +846,7 @@ static int RunDump (string& errorMsg) { { // save meta data - string fileName; - fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + ".structure.json"; + string fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + ".structure.json"; int fd; From 22cff81a5c14252a415b5e71ce1977ba99d3b5d5 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 17 Aug 2015 15:04:26 +0200 Subject: [PATCH 07/29] added status methods for logfiles --- .../RestHandler/RestReplicationHandler.cpp | 93 +++++++++++++++++++ arangod/RestHandler/RestReplicationHandler.h | 12 +++ arangod/Wal/LogfileManager.cpp | 61 +++++++++--- arangod/Wal/LogfileManager.h | 35 ++++++- 4 files changed, 186 insertions(+), 15 deletions(-) diff --git a/arangod/RestHandler/RestReplicationHandler.cpp b/arangod/RestHandler/RestReplicationHandler.cpp index b6ce3aeada..05789a56e4 100644 --- a/arangod/RestHandler/RestReplicationHandler.cpp +++ b/arangod/RestHandler/RestReplicationHandler.cpp @@ -107,6 +107,18 @@ Handler::status_t RestReplicationHandler::execute () { } handleCommandLoggerState(); } + else if (command == "logger-tick-ranges") { + if (type != HttpRequest::HTTP_REQUEST_GET) { + goto BAD_CALL; + } + handleCommandLoggerTickRanges(); + } + else if (command == "logger-first-tick") { + if (type != HttpRequest::HTTP_REQUEST_GET) { + goto BAD_CALL; + } + handleCommandLoggerFirstTick(); + } else if (command == "logger-follow") { if (type != HttpRequest::HTTP_REQUEST_GET) { goto BAD_CALL; @@ -510,6 +522,87 @@ void RestReplicationHandler::handleCommandLoggerState () { TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the available logfile range +//////////////////////////////////////////////////////////////////////////////// + +void RestReplicationHandler::handleCommandLoggerTickRanges () { + auto const& ranges = triagens::wal::LogfileManager::instance()->ranges(); + + TRI_json_t* json = TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE, ranges.size()); + + if (json == nullptr) { + generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY); + return; + } + + for (auto& it : ranges) { + auto r = TRI_CreateObjectJson(TRI_UNKNOWN_MEM_ZONE); + + if (r == nullptr) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY); + return; + } + + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, r, "datafile", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, it.filename.c_str(), it.filename.size())); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, r, "status", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, it.state.c_str(), it.state.size())); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, r, "tickMin", TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, it.tickMin)); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, r, "tickMax", TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, it.tickMax)); + + TRI_PushBack3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, r); + } + + generateResult(json); + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the first tick available in a logfile +//////////////////////////////////////////////////////////////////////////////// + +void RestReplicationHandler::handleCommandLoggerFirstTick () { + auto const& ranges = triagens::wal::LogfileManager::instance()->ranges(); + + TRI_json_t* json = TRI_CreateObjectJson(TRI_UNKNOWN_MEM_ZONE, 1); + + if (json == nullptr) { + generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY); + return; + } + + TRI_voc_tick_t tick = UINT64_MAX; + + for (auto& it : ranges) { + auto r = TRI_CreateObjectJson(TRI_UNKNOWN_MEM_ZONE); + + if (r == nullptr) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY); + return; + } + + if (it.tickMin == 0) { + continue; + } + + if (it.tickMin < tick) { + tick = it.tickMin; + } + } + + if (tick == UINT64_MAX) { + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "firstTick", TRI_CreateNullJson(TRI_UNKNOWN_MEM_ZONE)); + } + else { + auto tickString = std::to_string(tick); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "firstTick", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, tickString.c_str(), tickString.size())); + } + + generateResult(json); + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief handle a dump batch command /// diff --git a/arangod/RestHandler/RestReplicationHandler.h b/arangod/RestHandler/RestReplicationHandler.h index 95d3f85c14..80599ba953 100644 --- a/arangod/RestHandler/RestReplicationHandler.h +++ b/arangod/RestHandler/RestReplicationHandler.h @@ -137,6 +137,18 @@ namespace triagens { void handleCommandLoggerState (); +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the available logfile range +//////////////////////////////////////////////////////////////////////////////// + + void handleCommandLoggerTickRanges (); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the first tick available in a logfile +//////////////////////////////////////////////////////////////////////////////// + + void handleCommandLoggerFirstTick (); + //////////////////////////////////////////////////////////////////////////////// /// @brief handle a follow command for the replication log //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Wal/LogfileManager.cpp b/arangod/Wal/LogfileManager.cpp index e001d00e12..88fb25af57 100644 --- a/arangod/Wal/LogfileManager.cpp +++ b/arangod/Wal/LogfileManager.cpp @@ -1052,7 +1052,7 @@ bool LogfileManager::removeLogfiles () { break; } - removeLogfile(logfile, true); + removeLogfile(logfile); worked = true; } @@ -1318,7 +1318,7 @@ Logfile* LogfileManager::getWriteableLogfile (uint32_t size, // and physically remove the file // note: this will also delete the logfile object! - removeLogfile(logfile, false); + removeLogfile(logfile); } else { ++it; @@ -1387,6 +1387,8 @@ Logfile* LogfileManager::getCollectableLogfile () { //////////////////////////////////////////////////////////////////////////////// /// @brief get a logfile to remove. this may return nullptr +/// if it returns a logfile, the logfile is removed from the list of available +/// logfiles //////////////////////////////////////////////////////////////////////////////// Logfile* LogfileManager::getRemovableLogfile () { @@ -1411,7 +1413,7 @@ Logfile* LogfileManager::getRemovableLogfile () { uint32_t numberOfLogfiles = 0; Logfile* first = nullptr; - READ_LOCKER(_logfilesLock); + WRITE_LOCKER(_logfilesLock); for (auto& it : _logfiles) { Logfile* logfile = it.second; @@ -1429,6 +1431,10 @@ Logfile* LogfileManager::getRemovableLogfile () { if (++numberOfLogfiles > historicLogfiles()) { TRI_ASSERT(first != nullptr); + _logfiles.erase(first->id()); + + TRI_ASSERT(_logfiles.find(first->id()) == _logfiles.end()); + return first; } } @@ -1532,20 +1538,42 @@ LogfileManagerState LogfileManager::state () { return state; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the current available logfile ranges +//////////////////////////////////////////////////////////////////////////////// + +LogfileRanges LogfileManager::ranges () { + LogfileRanges result; + + READ_LOCKER(_logfilesLock); + + for (auto const& it : _logfiles) { + Logfile* logfile = it.second; + + if (logfile == nullptr) { + continue; + } + + auto df = logfile->df(); + if (df->_tickMin == 0 && df->_tickMax == 0) { + continue; + } + + result.emplace_back(LogfileRange(it.first, logfile->filename(), logfile->statusText(), df->_tickMin, df->_tickMax)); + } + + return result; +} + // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -/// @brief remove a logfile from the inventory and in the file system +/// @brief remove a logfile in the file system //////////////////////////////////////////////////////////////////////////////// -void LogfileManager::removeLogfile (Logfile* logfile, - bool unlink) { - if (unlink) { - unlinkLogfile(logfile); - } - +void LogfileManager::removeLogfile (Logfile* logfile) { // old filename Logfile::IdType const id = logfile->id(); std::string const filename = logfileName(id); @@ -1996,6 +2024,7 @@ int LogfileManager::inspectLogfiles () { if (! _ignoreLogfileErrors) { // we don't ignore errors, so we abort here int res = TRI_errno(); + if (res == TRI_ERROR_NO_ERROR) { // must have an error! res = TRI_ERROR_ARANGO_DATAFILE_UNREADABLE; @@ -2012,13 +2041,21 @@ int LogfileManager::inspectLogfiles () { _recoverState->logfilesToProcess.push_back(logfile); } - LOG_TRACE("inspecting logfile %llu (%s)", (unsigned long long) logfile->id(), logfile->statusText().c_str()); - + LOG_TRACE("inspecting logfile %llu (%s)", + (unsigned long long) logfile->id(), + logfile->statusText().c_str()); + // update the tick statistics if (! TRI_IterateDatafile(logfile->df(), &RecoverState::InitialScanMarker, static_cast(_recoverState))) { LOG_WARNING("WAL inspection failed when scanning logfile '%s'", logfile->filename().c_str()); return TRI_ERROR_ARANGO_RECOVERY; } + + LOG_TRACE("inspected logfile %llu (%s), tickMin: %llu, tickMax: %llu", + (unsigned long long) logfile->id(), + logfile->statusText().c_str(), + (unsigned long long) logfile->df()->_tickMin, + (unsigned long long) logfile->df()->_tickMax); { MUTEX_LOCKER(_idLock); diff --git a/arangod/Wal/LogfileManager.h b/arangod/Wal/LogfileManager.h index 789ca34a0c..68d54ad538 100644 --- a/arangod/Wal/LogfileManager.h +++ b/arangod/Wal/LogfileManager.h @@ -53,6 +53,28 @@ namespace triagens { class Slot; class SynchroniserThread; + struct LogfileRange { + LogfileRange (Logfile::IdType id, + std::string const& filename, + std::string const& state, + TRI_voc_tick_t tickMin, + TRI_voc_tick_t tickMax) + : id(id), + filename(filename), + state(state), + tickMin(tickMin), + tickMax(tickMax) { + } + + Logfile::IdType id; + std::string filename; + std::string state; + TRI_voc_tick_t tickMin; + TRI_voc_tick_t tickMax; + }; + + typedef std::vector LogfileRanges; + // ----------------------------------------------------------------------------- // --SECTION-- LogfileManagerState // ----------------------------------------------------------------------------- @@ -594,6 +616,8 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// /// @brief get a logfile to remove. this may return nullptr +/// if it returns a logfile, the logfile is removed from the list of available +/// logfiles //////////////////////////////////////////////////////////////////////////////// Logfile* getRemovableLogfile (); @@ -635,6 +659,12 @@ namespace triagens { LogfileManagerState state (); +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the current available logfile ranges +//////////////////////////////////////////////////////////////////////////////// + + LogfileRanges ranges (); + // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- @@ -642,11 +672,10 @@ namespace triagens { private: //////////////////////////////////////////////////////////////////////////////// -/// @brief remove a logfile from the inventory and in the file system +/// @brief remove a logfile in the file system //////////////////////////////////////////////////////////////////////////////// - void removeLogfile (Logfile*, - bool); + void removeLogfile (Logfile*); //////////////////////////////////////////////////////////////////////////////// /// @brief wait for the collector thread to collect a specific logfile From 715ebfed4ac53a7389bb6a9f8569be06e6f24eaa Mon Sep 17 00:00:00 2001 From: Willi Goesgens Date: Mon, 17 Aug 2015 15:36:49 +0200 Subject: [PATCH 08/29] Work around inferiour windows filesystem support by adding the md5 sum of the base-filename to the filename. --- arangosh/V8Client/arangodump.cpp | 46 +++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/arangosh/V8Client/arangodump.cpp b/arangosh/V8Client/arangodump.cpp index e1bc52ffa6..4ac181fec9 100644 --- a/arangosh/V8Client/arangodump.cpp +++ b/arangosh/V8Client/arangodump.cpp @@ -48,6 +48,11 @@ #include "SimpleHttpClient/SimpleHttpClient.h" #include "SimpleHttpClient/SimpleHttpResult.h" +#ifdef _WIN32 +#include +#else +#define hexStr "" +#endif using namespace std; using namespace triagens::basics; @@ -836,6 +841,21 @@ static int RunDump (string& errorMsg) { continue; } +#ifdef _WIN32 + size_t dstLen; + char *hexStr = NULL; + char rawdigest[16]; + MD5_CTX md5context; + MD5_Init(&md5context); + + MD5_Update(&md5context, + (const unsigned char*)name.c_str(), name.length()); + + MD5_Final((u_char*)rawdigest, &md5context); + hexStr = TRI_EncodeHexString(rawdigest, 16, &dstLen); +#endif + + // found a collection! if (Progress) { cout << "dumping collection '" << name << "'..." << endl; @@ -846,7 +866,7 @@ static int RunDump (string& errorMsg) { { // save meta data - string fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + ".structure.json"; + string fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + hexStr + ".structure.json"; int fd; @@ -881,7 +901,7 @@ static int RunDump (string& errorMsg) { if (DumpData) { // save the actual data string fileName; - fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + ".data.json"; + fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + hexStr + ".data.json"; int fd; @@ -913,6 +933,9 @@ static int RunDump (string& errorMsg) { return res; } } +#ifdef _WIN32 + TRI_Free(TRI_CORE_MEM_ZONE, hexStr); +#endif } @@ -1206,7 +1229,24 @@ static int RunClusterDump (string& errorMsg) { // Now set up the output file: string fileName; - fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + ".data.json"; +#ifdef _WIN32 + size_t dstLen; + char *hexStr = NULL; + char rawdigest[16]; + MD5_CTX md5context; + MD5_Init(&md5context); + + MD5_Update(&md5context, + (const unsigned char*)name.c_str(), name.length()); + + MD5_Final((u_char*)rawdigest, &md5context); + hexStr = TRI_EncodeHexString(rawdigest, 16, &dstLen); +#endif + fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + hexStr + ".data.json"; + +#ifdef _WIN32 + TRI_Free(TRI_CORE_MEM_ZONE, hexStr); +#endif int fd; From ffe4fb556b7bbb92ff675e740f825e6d3639ba80 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 17 Aug 2015 17:05:52 +0200 Subject: [PATCH 09/29] pacify VS --- arangod/RestHandler/RestReplicationHandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arangod/RestHandler/RestReplicationHandler.cpp b/arangod/RestHandler/RestReplicationHandler.cpp index 05789a56e4..fbc7bb3ae8 100644 --- a/arangod/RestHandler/RestReplicationHandler.cpp +++ b/arangod/RestHandler/RestReplicationHandler.cpp @@ -547,8 +547,8 @@ void RestReplicationHandler::handleCommandLoggerTickRanges () { TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, r, "datafile", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, it.filename.c_str(), it.filename.size())); TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, r, "status", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, it.state.c_str(), it.state.size())); - TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, r, "tickMin", TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, it.tickMin)); - TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, r, "tickMax", TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, it.tickMax)); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, r, "tickMin", TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, static_cast(it.tickMin))); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, r, "tickMax", TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, static_cast(it.tickMax))); TRI_PushBack3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, r); } From 593eed4ac1b54914fe1c309566bf811ddcd0440b Mon Sep 17 00:00:00 2001 From: Willi Goesgens Date: Mon, 17 Aug 2015 17:08:06 +0200 Subject: [PATCH 10/29] Adjust the import site of the dumper for hashes in the filenames. --- arangosh/V8Client/arangorestore.cpp | 33 +++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/arangosh/V8Client/arangorestore.cpp b/arangosh/V8Client/arangorestore.cpp index c1da9131f2..04ce40f8c0 100644 --- a/arangosh/V8Client/arangorestore.cpp +++ b/arangosh/V8Client/arangorestore.cpp @@ -48,6 +48,12 @@ #include "SimpleHttpClient/SimpleHttpClient.h" #include "SimpleHttpClient/SimpleHttpResult.h" +#ifndef _WIN32 +#include +#else +#define hexStr "" +#endif + using namespace std; using namespace triagens::basics; using namespace triagens::httpclient; @@ -653,12 +659,19 @@ static int ProcessInputDirectory (string& errorMsg) { // found a structure.json file - const string name = files[i].substr(0, files[i].size() - suffix.size()); + string name = files[i].substr(0, files[i].size() - suffix.size()); if (name[0] == '_' && ! IncludeSystemCollections) { continue; } +#ifndef _WIN32 + // Cut of the dirty md5 hash on the wintendo: + string nname; + nname = name.substr(0, name.length() - 32); + name = nname; +#endif + if (restrictList.size() > 0 && restrictList.find(name) == restrictList.end()) { // collection name not in list @@ -766,7 +779,23 @@ static int ProcessInputDirectory (string& errorMsg) { if (ImportData) { // import data. check if we have a datafile // TODO: externalise file extension - const string datafile = InputDirectory + TRI_DIR_SEPARATOR_STR + cname + ".data.json"; +#ifndef _WIN32 + size_t dstLen; + char *hexStr = NULL; + char rawdigest[16]; + MD5_CTX md5context; + MD5_Init(&md5context); + + MD5_Update(&md5context, + (const unsigned char*)cname.c_str(), cname.length()); + + MD5_Final((u_char*)rawdigest, &md5context); + hexStr = TRI_EncodeHexString(rawdigest, 16, &dstLen); +#endif + const string datafile = InputDirectory + TRI_DIR_SEPARATOR_STR + cname + hexStr + ".data.json"; +#ifndef _WIN32 + TRI_Free(TRI_CORE_MEM_ZONE, hexStr); +#endif if (TRI_ExistsFile(datafile.c_str())) { // found a datafile From 35de50d153092f8949366273059553546be4dfea Mon Sep 17 00:00:00 2001 From: Willi Goesgens Date: Mon, 17 Aug 2015 17:31:15 +0200 Subject: [PATCH 11/29] set the mac to add hashes too. --- arangosh/V8Client/arangodump.cpp | 10 +++++----- arangosh/V8Client/arangorestore.cpp | 18 ++++++++++-------- lib/Basics/operating-system.h | 5 +++++ 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/arangosh/V8Client/arangodump.cpp b/arangosh/V8Client/arangodump.cpp index 4ac181fec9..b5cea3ca6e 100644 --- a/arangosh/V8Client/arangodump.cpp +++ b/arangosh/V8Client/arangodump.cpp @@ -48,7 +48,7 @@ #include "SimpleHttpClient/SimpleHttpClient.h" #include "SimpleHttpClient/SimpleHttpResult.h" -#ifdef _WIN32 +#ifdef TRI_FILESYSTEM_CASE_BROKEN #include #else #define hexStr "" @@ -841,7 +841,7 @@ static int RunDump (string& errorMsg) { continue; } -#ifdef _WIN32 +#ifdef TRI_FILESYSTEM_CASE_BROKEN size_t dstLen; char *hexStr = NULL; char rawdigest[16]; @@ -933,7 +933,7 @@ static int RunDump (string& errorMsg) { return res; } } -#ifdef _WIN32 +#ifdef TRI_FILESYSTEM_CASE_BROKEN TRI_Free(TRI_CORE_MEM_ZONE, hexStr); #endif } @@ -1229,7 +1229,7 @@ static int RunClusterDump (string& errorMsg) { // Now set up the output file: string fileName; -#ifdef _WIN32 +#ifdef TRI_FILESYSTEM_CASE_BROKEN size_t dstLen; char *hexStr = NULL; char rawdigest[16]; @@ -1244,7 +1244,7 @@ static int RunClusterDump (string& errorMsg) { #endif fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + hexStr + ".data.json"; -#ifdef _WIN32 +#ifdef TRI_FILESYSTEM_CASE_BROKEN TRI_Free(TRI_CORE_MEM_ZONE, hexStr); #endif diff --git a/arangosh/V8Client/arangorestore.cpp b/arangosh/V8Client/arangorestore.cpp index 04ce40f8c0..dec0054d33 100644 --- a/arangosh/V8Client/arangorestore.cpp +++ b/arangosh/V8Client/arangorestore.cpp @@ -48,7 +48,7 @@ #include "SimpleHttpClient/SimpleHttpClient.h" #include "SimpleHttpClient/SimpleHttpResult.h" -#ifndef _WIN32 +#ifdef TRI_FILESYSTEM_CASE_BROKEN #include #else #define hexStr "" @@ -665,11 +665,13 @@ static int ProcessInputDirectory (string& errorMsg) { continue; } -#ifndef _WIN32 - // Cut of the dirty md5 hash on the wintendo: - string nname; - nname = name.substr(0, name.length() - 32); - name = nname; +#ifdef TRI_FILESYSTEM_CASE_BROKEN + // Cut of the dirty md5 hash on the wintendo and on mac: + if (name.length() > 32) { + string nname; + nname = name.substr(0, name.length() - 32); + name = nname; + } #endif if (restrictList.size() > 0 && @@ -779,7 +781,7 @@ static int ProcessInputDirectory (string& errorMsg) { if (ImportData) { // import data. check if we have a datafile // TODO: externalise file extension -#ifndef _WIN32 +#ifdef TRI_FILESYSTEM_CASE_BROKEN size_t dstLen; char *hexStr = NULL; char rawdigest[16]; @@ -793,7 +795,7 @@ static int ProcessInputDirectory (string& errorMsg) { hexStr = TRI_EncodeHexString(rawdigest, 16, &dstLen); #endif const string datafile = InputDirectory + TRI_DIR_SEPARATOR_STR + cname + hexStr + ".data.json"; -#ifndef _WIN32 +#ifdef TRI_FILESYSTEM_CASE_BROKEN TRI_Free(TRI_CORE_MEM_ZONE, hexStr); #endif diff --git a/lib/Basics/operating-system.h b/lib/Basics/operating-system.h index e2499488a8..390235b6f7 100644 --- a/lib/Basics/operating-system.h +++ b/lib/Basics/operating-system.h @@ -200,6 +200,8 @@ #define TRI_ERRORBUF {} #define TRI_GET_ERRORBUF strerror(errno) +#define TRI_FILESYSTEM_CASE_BROKEN 1 + //////////////////////////////////////////////////////////////////////////////// /// @brief sockets //////////////////////////////////////////////////////////////////////////////// @@ -360,6 +362,7 @@ #define TRI_SYSTEM_ERROR() {} #define TRI_ERRORBUF {} #define TRI_GET_ERRORBUF strerror(errno) +#define TRI_FILESYSTEM_CASE_BROKEN 0 //////////////////////////////////////////////////////////////////////////////// /// @brief sockets @@ -537,6 +540,7 @@ #define TRI_SYSTEM_ERROR() {} #define TRI_ERRORBUF {} #define TRI_GET_ERRORBUF strerror(errno) +#define TRI_FILESYSTEM_CASE_BROKEN 0 //////////////////////////////////////////////////////////////////////////////// /// @brief sockets @@ -762,6 +766,7 @@ typedef unsigned char bool; #define TRI_ERRORBUF char windowsErrorBuf[256] = ""; #define TRI_GET_ERRORBUF windowsErrorBuf +#define TRI_FILESYSTEM_CASE_BROKEN 1 //////////////////////////////////////////////////////////////////////////////// /// @brief Return system error string From 4e771b27283977189539746120f4d8d39132bb2a Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 17 Aug 2015 18:41:05 +0200 Subject: [PATCH 12/29] replication improvements --- arangod/Replication/ContinuousSyncer.cpp | 35 +++++++----- arangod/Replication/ContinuousSyncer.h | 17 +++++- .../RestHandler/RestReplicationHandler.cpp | 4 ++ arangod/RestServer/ArangoServer.cpp | 5 ++ arangod/V8Server/v8-replication.cpp | 12 ++++ arangod/VocBase/replication-applier.cpp | 57 ++++++++++++++----- arangod/VocBase/replication-applier.h | 1 + arangod/VocBase/replication-common.h | 6 ++ arangod/VocBase/replication-dump.cpp | 5 +- arangod/VocBase/replication-dump.h | 4 +- arangod/VocBase/server.cpp | 10 ++++ arangod/VocBase/transaction.cpp | 5 +- arangod/Wal/LogfileManager.cpp | 9 ++- arangod/Wal/LogfileManager.h | 3 +- .../APP/frontend/js/bootstrap/errors.js | 1 + js/common/bootstrap/errors.js | 1 + lib/Basics/errors.dat | 3 +- lib/Basics/voc-errors.cpp | 1 + lib/Basics/voc-errors.h | 20 ++++++- 19 files changed, 161 insertions(+), 38 deletions(-) diff --git a/arangod/Replication/ContinuousSyncer.cpp b/arangod/Replication/ContinuousSyncer.cpp index 91e7de228d..8b7c32097d 100644 --- a/arangod/Replication/ContinuousSyncer.cpp +++ b/arangod/Replication/ContinuousSyncer.cpp @@ -91,7 +91,8 @@ ContinuousSyncer::ContinuousSyncer (TRI_server_t* server, _restrictType(RESTRICT_NONE), _initialTick(initialTick), _useTick(useTick), - _includeSystem(configuration->_includeSystem) { + _includeSystem(configuration->_includeSystem), + _requireFromPresent(configuration->_requireFromPresent) { uint64_t c = configuration->_chunkSize; if (c == 0) { @@ -102,11 +103,6 @@ ContinuousSyncer::ContinuousSyncer (TRI_server_t* server, _chunkSize = StringUtils::itoa(c); - // get number of running remote transactions so we can forge the transaction - // statistics - int const n = static_cast(_applier->_runningRemoteTransactions.size()); - triagens::arango::TransactionBase::setNumbers(n, n); - if (configuration->_restrictType == "include") { _restrictType = RESTRICT_INCLUDE; } @@ -465,15 +461,16 @@ int ContinuousSyncer::startTransaction (TRI_json_t const* json) { } // transaction id - // note: this is the remote trasnaction id! + // note: this is the remote transaction id! TRI_voc_tid_t tid = static_cast(StringUtils::uint64(id.c_str(), id.size())); auto it = _applier->_runningRemoteTransactions.find(tid); if (it != _applier->_runningRemoteTransactions.end()) { + auto trx = (*it).second; + _applier->_runningRemoteTransactions.erase(tid); - auto trx = (*it).second; // abort ongoing trx delete trx; } @@ -527,8 +524,8 @@ int ContinuousSyncer::abortTransaction (TRI_json_t const* json) { LOG_TRACE("abort replication transaction %llu", (unsigned long long) tid); - _applier->_runningRemoteTransactions.erase(tid); auto trx = (*it).second; + _applier->_runningRemoteTransactions.erase(tid); int res = trx->abort(); delete trx; @@ -562,9 +559,8 @@ int ContinuousSyncer::commitTransaction (TRI_json_t const* json) { LOG_TRACE("committing replication transaction %llu", (unsigned long long) tid); - _applier->_runningRemoteTransactions.erase(tid); - auto trx = (*it).second; + _applier->_runningRemoteTransactions.erase(tid); int res = trx->commit(); delete trx; @@ -993,8 +989,9 @@ int ContinuousSyncer::followMasterLog (string& errorMsg, } int res; - bool checkMore = false; - bool active = false; + bool checkMore = false; + bool active = false; + bool fromIncluded = false; TRI_voc_tick_t tick; bool found; @@ -1003,6 +1000,12 @@ int ContinuousSyncer::followMasterLog (string& errorMsg, if (found) { checkMore = StringUtils::boolean(header); res = TRI_ERROR_NO_ERROR; + + // was the specified from value included the result? + header = response->getHeaderField(TRI_REPLICATION_HEADER_FROMPRESENT, found); + if (found) { + fromIncluded = StringUtils::boolean(header); + } header = response->getHeaderField(TRI_REPLICATION_HEADER_ACTIVE, found); if (found) { @@ -1038,6 +1041,12 @@ int ContinuousSyncer::followMasterLog (string& errorMsg, ": required header is missing"; } + if (res == TRI_ERROR_NO_ERROR && + ! fromIncluded && + _requireFromPresent) { + res = TRI_ERROR_REPLICATION_START_TICK_NOT_PRESENT; + errorMsg = "required tick value '" + tickString + "' is not present on master at " + string(_masterInfo._endpoint); + } if (res == TRI_ERROR_NO_ERROR) { TRI_voc_tick_t lastAppliedTick; diff --git a/arangod/Replication/ContinuousSyncer.h b/arangod/Replication/ContinuousSyncer.h index 08b885257c..0d010d4268 100644 --- a/arangod/Replication/ContinuousSyncer.h +++ b/arangod/Replication/ContinuousSyncer.h @@ -78,7 +78,7 @@ namespace triagens { TRI_vocbase_t*, struct TRI_replication_applier_configuration_s const*, TRI_voc_tick_t, - bool); + bool); //////////////////////////////////////////////////////////////////////////////// /// @brief destructor @@ -98,6 +98,14 @@ namespace triagens { int run (); +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the syncer's replication applier +//////////////////////////////////////////////////////////////////////////////// + + TRI_replication_applier_t* applier () const { + return _applier; + } + // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- @@ -252,6 +260,13 @@ namespace triagens { bool _includeSystem; +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the specified from tick must be present when fetching +/// data from a master +//////////////////////////////////////////////////////////////////////////////// + + bool _requireFromPresent; + }; } diff --git a/arangod/RestHandler/RestReplicationHandler.cpp b/arangod/RestHandler/RestReplicationHandler.cpp index 05789a56e4..1fa019d238 100644 --- a/arangod/RestHandler/RestReplicationHandler.cpp +++ b/arangod/RestHandler/RestReplicationHandler.cpp @@ -1162,6 +1162,10 @@ void RestReplicationHandler::handleCommandLoggerFollow () { _response->setHeader(TRI_REPLICATION_HEADER_ACTIVE, strlen(TRI_REPLICATION_HEADER_ACTIVE), "true"); + + _response->setHeader(TRI_REPLICATION_HEADER_FROMPRESENT, + strlen(TRI_REPLICATION_HEADER_FROMPRESENT), + dump._fromTickIncluded ? "true" : "false"); if (length > 0) { // transfer ownership of the buffer contents diff --git a/arangod/RestServer/ArangoServer.cpp b/arangod/RestServer/ArangoServer.cpp index 922a2038f4..5f44e6b243 100644 --- a/arangod/RestServer/ArangoServer.cpp +++ b/arangod/RestServer/ArangoServer.cpp @@ -1141,6 +1141,11 @@ int ArangoServer::startupServer () { shutDownBegins(); +#if 0 + // stop the replication appliers so all replication transactions can end + TRI_StopReplicationAppliersServer(_server); +#endif + _applicationServer->stop(); _server->_queryRegistry = nullptr; diff --git a/arangod/V8Server/v8-replication.cpp b/arangod/V8Server/v8-replication.cpp index 771fe7da7f..00affae4c7 100644 --- a/arangod/V8Server/v8-replication.cpp +++ b/arangod/V8Server/v8-replication.cpp @@ -214,6 +214,12 @@ static void JS_SynchroniseReplication (const v8::FunctionCallbackInfo config._includeSystem = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("includeSystem"))); } } + + if (object->Has(TRI_V8_ASCII_STRING("requireFromPresent"))) { + if (object->Get(TRI_V8_ASCII_STRING("requireFromPresent"))->IsBoolean()) { + config._requireFromPresent = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("requireFromPresent"))); + } + } string errorMsg = ""; InitialSyncer syncer(vocbase, &config, restrictCollections, restrictType, verbose); @@ -434,6 +440,12 @@ static void JS_ConfigureApplierReplication (const v8::FunctionCallbackInfoGet(TRI_V8_ASCII_STRING("includeSystem"))); } } + + if (object->Has(TRI_V8_ASCII_STRING("requireFromPresent"))) { + if (object->Get(TRI_V8_ASCII_STRING("requireFromPresent"))->IsBoolean()) { + config._requireFromPresent = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("requireFromPresent"))); + } + } if (object->Has(TRI_V8_ASCII_STRING("restrictCollections")) && object->Get(TRI_V8_ASCII_STRING("restrictCollections"))->IsArray()) { config._restrictCollections.clear(); diff --git a/arangod/VocBase/replication-applier.cpp b/arangod/VocBase/replication-applier.cpp index a3f5ed20fb..135be2b116 100644 --- a/arangod/VocBase/replication-applier.cpp +++ b/arangod/VocBase/replication-applier.cpp @@ -185,6 +185,11 @@ static TRI_json_t* JsonConfiguration (TRI_replication_applier_configuration_t co "includeSystem", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, config->_includeSystem)); + TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, + json, + "requireFromPresent", + TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, config->_requireFromPresent)); + TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, json, "restrictType", @@ -347,6 +352,12 @@ static int LoadConfiguration (TRI_vocbase_t* vocbase, config->_includeSystem = value->_value._boolean; } + value = TRI_LookupObjectJson(json, "requireFromPresent"); + + if (TRI_IsBooleanJson(value)) { + config->_requireFromPresent = value->_value._boolean; + } + value = TRI_LookupObjectJson(json, "ignoreErrors"); if (TRI_IsNumberJson(value)) { @@ -473,6 +484,12 @@ static int SetError (TRI_replication_applier_t* applier, static void ApplyThread (void* data) { triagens::arango::ContinuousSyncer* s = static_cast(data); + + // get number of running remote transactions so we can forge the transaction + // statistics + int const n = static_cast(s->applier()->_runningRemoteTransactions.size()); + triagens::arango::TransactionBase::setNumbers(n, n); + s->run(); delete s; } @@ -749,6 +766,16 @@ TRI_replication_applier_t* TRI_CreateReplicationApplier (TRI_server_t* server, void TRI_DestroyReplicationApplier (TRI_replication_applier_t* applier) { TRI_ASSERT(applier != nullptr); TRI_StopReplicationApplier(applier, true); + +#if 0 + // TODO: fix thread-specific assertions about transactions + for (auto& it : applier->_runningRemoteTransactions) { + auto trx = it.second; + trx->abort(); + delete trx; + } + applier->_runningRemoteTransactions.clear(); +#endif TRI_DestroyStateReplicationApplier(&applier->_state); TRI_DestroyConfigurationReplicationApplier(&applier->_configuration); @@ -1288,21 +1315,22 @@ int TRI_LoadStateReplicationApplier (TRI_vocbase_t* vocbase, //////////////////////////////////////////////////////////////////////////////// void TRI_InitConfigurationReplicationApplier (TRI_replication_applier_configuration_t* config) { - config->_endpoint = nullptr; - config->_database = nullptr; - config->_username = nullptr; - config->_password = nullptr; + config->_endpoint = nullptr; + config->_database = nullptr; + config->_username = nullptr; + config->_password = nullptr; - config->_requestTimeout = 300.0; - config->_connectTimeout = 10.0; - config->_ignoreErrors = 0; - config->_maxConnectRetries = 100; - config->_chunkSize = 0; - config->_sslProtocol = 0; - config->_autoStart = false; - config->_adaptivePolling = true; - config->_includeSystem = true; - config->_restrictType = ""; + config->_requestTimeout = 300.0; + config->_connectTimeout = 10.0; + config->_ignoreErrors = 0; + config->_maxConnectRetries = 100; + config->_chunkSize = 0; + config->_sslProtocol = 0; + config->_autoStart = false; + config->_adaptivePolling = true; + config->_includeSystem = true; + config->_requireFromPresent = false; + config->_restrictType = ""; config->_restrictCollections.clear(); } @@ -1375,6 +1403,7 @@ void TRI_CopyConfigurationReplicationApplier (TRI_replication_applier_configurat dst->_autoStart = src->_autoStart; dst->_adaptivePolling = src->_adaptivePolling; dst->_includeSystem = src->_includeSystem; + dst->_requireFromPresent = src->_requireFromPresent; dst->_restrictType = src->_restrictType; dst->_restrictCollections = src->_restrictCollections; } diff --git a/arangod/VocBase/replication-applier.h b/arangod/VocBase/replication-applier.h index f927d1f5ed..bbe3878f83 100644 --- a/arangod/VocBase/replication-applier.h +++ b/arangod/VocBase/replication-applier.h @@ -71,6 +71,7 @@ typedef struct TRI_replication_applier_configuration_s { bool _autoStart; bool _adaptivePolling; bool _includeSystem; + bool _requireFromPresent; std::string _restrictType; std::unordered_map _restrictCollections; } diff --git a/arangod/VocBase/replication-common.h b/arangod/VocBase/replication-common.h index bbe2770b87..88b77d3233 100644 --- a/arangod/VocBase/replication-common.h +++ b/arangod/VocBase/replication-common.h @@ -60,6 +60,12 @@ #define TRI_REPLICATION_HEADER_LASTTICK "x-arango-replication-lasttick" +//////////////////////////////////////////////////////////////////////////////// +/// @brief HTTP response header for "from tick present" +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_REPLICATION_HEADER_FROMPRESENT "x-arango-replication-frompresent" + //////////////////////////////////////////////////////////////////////////////// /// @brief HTTP response header for "replication active" //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/VocBase/replication-dump.cpp b/arangod/VocBase/replication-dump.cpp index 6c86d81e4e..390bdc2d95 100644 --- a/arangod/VocBase/replication-dump.cpp +++ b/arangod/VocBase/replication-dump.cpp @@ -1363,7 +1363,8 @@ int TRI_DumpLogReplication (TRI_replication_dump_t* dump, (unsigned long long) tickMax); // ask the logfile manager which datafiles qualify - std::vector logfiles = triagens::wal::LogfileManager::instance()->getLogfilesForTickRange(tickMin, tickMax); + bool fromTickIncluded = false; + std::vector logfiles = triagens::wal::LogfileManager::instance()->getLogfilesForTickRange(tickMin, tickMax, fromTickIncluded); size_t const n = logfiles.size(); // setup some iteration state @@ -1463,6 +1464,8 @@ int TRI_DumpLogReplication (TRI_replication_dump_t* dump, TRI_AppendStringStringBuffer(dump->_buffer, "\n]"); } + dump->_fromTickIncluded = fromTickIncluded; + if (res == TRI_ERROR_NO_ERROR) { if (lastFoundTick > 0) { // data available for requested range diff --git a/arangod/VocBase/replication-dump.h b/arangod/VocBase/replication-dump.h index cb18d14964..737b75cdb3 100644 --- a/arangod/VocBase/replication-dump.h +++ b/arangod/VocBase/replication-dump.h @@ -72,7 +72,8 @@ struct TRI_replication_dump_t { _failed(false), _bufferFull(false), _hasMore(false), - _includeSystem(includeSystem) { + _includeSystem(includeSystem), + _fromTickIncluded(false) { if (_chunkSize == 0) { // default chunk size @@ -104,6 +105,7 @@ struct TRI_replication_dump_t { bool _bufferFull; bool _hasMore; bool _includeSystem; + bool _fromTickIncluded; }; // ----------------------------------------------------------------------------- diff --git a/arangod/VocBase/server.cpp b/arangod/VocBase/server.cpp index 3216f15861..632402772a 100644 --- a/arangod/VocBase/server.cpp +++ b/arangod/VocBase/server.cpp @@ -724,6 +724,16 @@ static void StopReplicationAppliers (TRI_server_t* server) { TRI_ASSERT(vocbase->_type == TRI_VOCBASE_TYPE_NORMAL); if (vocbase->_replicationApplier != nullptr) { TRI_StopReplicationApplier(vocbase->_replicationApplier, false); + +#if 0 + // stop pending transactions + for (auto& it : vocbase->_replicationApplier->_runningRemoteTransactions) { + auto trx = it.second; + trx->abort(); + delete trx; + } + vocbase->_replicationApplier->_runningRemoteTransactions.clear(); +#endif } } } diff --git a/arangod/VocBase/transaction.cpp b/arangod/VocBase/transaction.cpp index 27257dfe66..840dc16f2f 100644 --- a/arangod/VocBase/transaction.cpp +++ b/arangod/VocBase/transaction.cpp @@ -188,12 +188,13 @@ static void FreeOperations (TRI_transaction_t* trx) { for (size_t i = 0; i < n; ++i) { auto trxCollection = static_cast(TRI_AtVectorPointer(&trx->_collections, i)); - TRI_document_collection_t* document = trxCollection->_collection->_collection; - + if (trxCollection->_operations == nullptr) { continue; } + TRI_document_collection_t* document = trxCollection->_collection->_collection; + if (mustRollback) { // revert all operations for (auto it = trxCollection->_operations->rbegin(); it != trxCollection->_operations->rend(); ++it) { diff --git a/arangod/Wal/LogfileManager.cpp b/arangod/Wal/LogfileManager.cpp index 88fb25af57..c8941bf5f7 100644 --- a/arangod/Wal/LogfileManager.cpp +++ b/arangod/Wal/LogfileManager.cpp @@ -1171,9 +1171,12 @@ void LogfileManager::getActiveLogfileRegion (Logfile* logfile, //////////////////////////////////////////////////////////////////////////////// std::vector LogfileManager::getLogfilesForTickRange (TRI_voc_tick_t minTick, - TRI_voc_tick_t maxTick) { + TRI_voc_tick_t maxTick, + bool& minTickIncluded) { std::vector temp; std::vector matching; + + minTickIncluded = false; // we need a two step logfile qualification procedure // this is to avoid holding the lock on _logfilesLock and then acquiring the @@ -1208,6 +1211,10 @@ std::vector LogfileManager::getLogfilesForTickRange (TRI_voc_tick_t mi TRI_voc_tick_t logMax; _slots->getActiveTickRange(logfile, logMin, logMax); + if (logMin <= minTick && logMin > 0) { + minTickIncluded = true; + } + if (minTick > logMax || maxTick < logMin) { // datafile is older than requested range // or: datafile is newer than requested range diff --git a/arangod/Wal/LogfileManager.h b/arangod/Wal/LogfileManager.h index 68d54ad538..32758ea64f 100644 --- a/arangod/Wal/LogfileManager.h +++ b/arangod/Wal/LogfileManager.h @@ -580,7 +580,8 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// std::vector getLogfilesForTickRange (TRI_voc_tick_t, - TRI_voc_tick_t); + TRI_voc_tick_t, + bool& minTickIncluded); //////////////////////////////////////////////////////////////////////////////// /// @brief return logfiles for a tick range diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/bootstrap/errors.js b/js/apps/system/_admin/aardvark/APP/frontend/js/bootstrap/errors.js index f6227e1538..818962f8bc 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/bootstrap/errors.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/bootstrap/errors.js @@ -122,6 +122,7 @@ "ERROR_REPLICATION_RUNNING" : { "code" : 1411, "message" : "cannot change applier configuration while running" }, "ERROR_REPLICATION_APPLIER_STOPPED" : { "code" : 1412, "message" : "replication stopped" }, "ERROR_REPLICATION_NO_START_TICK" : { "code" : 1413, "message" : "no start tick" }, + "ERROR_REPLICATION_START_TICK_NOT_PRESENT" : { "code" : 1414, "message" : "start tick not present" }, "ERROR_CLUSTER_NO_AGENCY" : { "code" : 1450, "message" : "could not connect to agency" }, "ERROR_CLUSTER_NO_COORDINATOR_HEADER" : { "code" : 1451, "message" : "missing coordinator header" }, "ERROR_CLUSTER_COULD_NOT_LOCK_PLAN" : { "code" : 1452, "message" : "could not lock plan in agency" }, diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js index f6227e1538..818962f8bc 100644 --- a/js/common/bootstrap/errors.js +++ b/js/common/bootstrap/errors.js @@ -122,6 +122,7 @@ "ERROR_REPLICATION_RUNNING" : { "code" : 1411, "message" : "cannot change applier configuration while running" }, "ERROR_REPLICATION_APPLIER_STOPPED" : { "code" : 1412, "message" : "replication stopped" }, "ERROR_REPLICATION_NO_START_TICK" : { "code" : 1413, "message" : "no start tick" }, + "ERROR_REPLICATION_START_TICK_NOT_PRESENT" : { "code" : 1414, "message" : "start tick not present" }, "ERROR_CLUSTER_NO_AGENCY" : { "code" : 1450, "message" : "could not connect to agency" }, "ERROR_CLUSTER_NO_COORDINATOR_HEADER" : { "code" : 1451, "message" : "missing coordinator header" }, "ERROR_CLUSTER_COULD_NOT_LOCK_PLAN" : { "code" : 1452, "message" : "could not lock plan in agency" }, diff --git a/lib/Basics/errors.dat b/lib/Basics/errors.dat index 3362327491..e88aeafad7 100755 --- a/lib/Basics/errors.dat +++ b/lib/Basics/errors.dat @@ -152,7 +152,8 @@ ERROR_REPLICATION_INVALID_LOGGER_CONFIGURATION,1409,"invalid replication logger ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION,1410,"invalid replication applier configuration","Will be raised when the configuration for the replication applier is invalid." ERROR_REPLICATION_RUNNING,1411,"cannot change applier configuration while running","Will be raised when there is an attempt to change the configuration for the replication applier while it is running." ERROR_REPLICATION_APPLIER_STOPPED,1412,"replication stopped","Special error code used to indicate the replication applier was stopped by a user." -ERROR_REPLICATION_NO_START_TICK,1413,"no start tick","Will be raised when the replication error is started without a known start tick value." +ERROR_REPLICATION_NO_START_TICK,1413,"no start tick","Will be raised when the replication applier is started without a known start tick value." +ERROR_REPLICATION_START_TICK_NOT_PRESENT,1414,"start tick not present","Will be raised when the replication applier fetches data using a start tick, but that start tick is not present on the logger server anymore." ################################################################################ ## ArangoDB cluster errors diff --git a/lib/Basics/voc-errors.cpp b/lib/Basics/voc-errors.cpp index 8bccd98aa4..4009f6b793 100644 --- a/lib/Basics/voc-errors.cpp +++ b/lib/Basics/voc-errors.cpp @@ -118,6 +118,7 @@ void TRI_InitialiseErrorMessages () { REG_ERROR(ERROR_REPLICATION_RUNNING, "cannot change applier configuration while running"); REG_ERROR(ERROR_REPLICATION_APPLIER_STOPPED, "replication stopped"); REG_ERROR(ERROR_REPLICATION_NO_START_TICK, "no start tick"); + REG_ERROR(ERROR_REPLICATION_START_TICK_NOT_PRESENT, "start tick not present"); REG_ERROR(ERROR_CLUSTER_NO_AGENCY, "could not connect to agency"); REG_ERROR(ERROR_CLUSTER_NO_COORDINATOR_HEADER, "missing coordinator header"); REG_ERROR(ERROR_CLUSTER_COULD_NOT_LOCK_PLAN, "could not lock plan in agency"); diff --git a/lib/Basics/voc-errors.h b/lib/Basics/voc-errors.h index 676f132fab..f7d054c981 100644 --- a/lib/Basics/voc-errors.h +++ b/lib/Basics/voc-errors.h @@ -270,8 +270,11 @@ /// Special error code used to indicate the replication applier was stopped /// by a user. /// - 1413: @LIT{no start tick} -/// Will be raised when the replication error is started without a known +/// Will be raised when the replication applier is started without a known /// start tick value. +/// - 1414: @LIT{start tick not present} +/// Will be raised when the replication applier fetches data using a start +/// tick, but that start tick is not present on the logger server anymore. /// - 1450: @LIT{could not connect to agency} /// Will be raised when none of the agency servers can be connected to. /// - 1451: @LIT{missing coordinator header} @@ -1822,12 +1825,23 @@ void TRI_InitialiseErrorMessages (); /// /// no start tick /// -/// Will be raised when the replication error is started without a known start -/// tick value. +/// Will be raised when the replication applier is started without a known +/// start tick value. //////////////////////////////////////////////////////////////////////////////// #define TRI_ERROR_REPLICATION_NO_START_TICK (1413) +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1414: ERROR_REPLICATION_START_TICK_NOT_PRESENT +/// +/// start tick not present +/// +/// Will be raised when the replication applier fetches data using a start +/// tick, but that start tick is not present on the logger server anymore. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_REPLICATION_START_TICK_NOT_PRESENT (1414) + //////////////////////////////////////////////////////////////////////////////// /// @brief 1450: ERROR_CLUSTER_NO_AGENCY /// From 4195b3751317f55d05e1f7404c636d862dca8be0 Mon Sep 17 00:00:00 2001 From: Willi Goesgens Date: Tue, 18 Aug 2015 11:23:08 +0200 Subject: [PATCH 13/29] Cleanup windows build - enforce the usage of the proper python via manipulating the path environment - create the complete directory - add blanks to make the parameters better readable --- 3rdParty/Makefile.v8-windows | 14 +++++++------- 3rdParty/v8-build.bat | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/3rdParty/Makefile.v8-windows b/3rdParty/Makefile.v8-windows index d0d57bc6a9..0d9eccbf7e 100644 --- a/3rdParty/Makefile.v8-windows +++ b/3rdParty/Makefile.v8-windows @@ -8,28 +8,28 @@ all: build64 build32 build64: - ./v8-build.bat x86_amd64 x64 x64 64 + ./v8-build.bat x86_amd64 x64 x64 64 build32: - ./v8-build.bat x86 ia32 Win32 32 + ./v8-build.bat x86 ia32 Win32 32 clean: clean32 clean64 clean64: - ./v8-clean.bat cmd x86_amd64 x64 x64 64 + ./v8-clean.bat cmd x86_amd64 x64 x64 64 clean32: - ./v8-clean.bat x86 ia32 Win32 32 + ./v8-clean.bat x86 ia32 Win32 32 32 distclean: distclean32 distclean64 distclean64: - ./v8-distclean.bat x86_amd64 x64 x64 64 + ./v8-distclean.bat x86_amd64 x64 x64 64 distclean32: - ./v8-distclean.bat x86 ia32 Win32 32 + ./v8-distclean.bat x86 ia32 Win32 32 install: @@ -37,7 +37,7 @@ install: $(MAKE) -f Makefile.v8-windows install_bits BITS=64 install_bits: - mkdir -p ../WindowsLibraries/$(BITS)/lib + mkdir -p ../WindowsLibraries/$(BITS)/lib/RelWithDebInfo mkdir -p ../WindowsLibraries/$(BITS)/include/unicode for i in `find $(V8)/build -name $(PDBNAME) | grep $(BITS)`; do \ LIBNAME=`echo $$i|sed "s;.*/\(.*\)/$(PDBNAME);\1;"`; \ diff --git a/3rdParty/v8-build.bat b/3rdParty/v8-build.bat index b1da6396cd..0b11860e1d 100755 --- a/3rdParty/v8-build.bat +++ b/3rdParty/v8-build.bat @@ -42,6 +42,7 @@ echo %CMD% cd V8-%V8_VERSION% +set PATH=.\third_party\python_26\;%PATH% .\third_party\python_26\python.exe build\gyp_v8 %CMD% cd build From 76e85ffc1f3120500c8a32e956b375081a8090ca Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Tue, 18 Aug 2015 12:09:30 +0200 Subject: [PATCH 14/29] added test case --- js/server/tests/aql-optimizer-indexes.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/js/server/tests/aql-optimizer-indexes.js b/js/server/tests/aql-optimizer-indexes.js index d9ffe67ea1..78addca0f0 100644 --- a/js/server/tests/aql-optimizer-indexes.js +++ b/js/server/tests/aql-optimizer-indexes.js @@ -2568,6 +2568,18 @@ function optimizerEdgeIndexTestSuite () { db._drop("UnitTestsCollection"); }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test continuous index scan +//////////////////////////////////////////////////////////////////////////////// + + testFindContinuous : function () { + for (var i = 0; i < 20; ++i) { + var query = "FOR i IN " + e.name() + " FILTER i._from == 'UnitTestsCollection/nono' && i._to == 'UnitTestsCollection/to" + i + "' LIMIT 1 RETURN i._key"; + var results = AQL_EXECUTE(query); + assertEqual(0, results.json.length, query); + } + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test index usage //////////////////////////////////////////////////////////////////////////////// From b81ac9be43c41931885b56cf37a94dbaf86adf2b Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Mon, 17 Aug 2015 14:57:19 +0200 Subject: [PATCH 15/29] Foxx: controller.allRoutes can now use functions defined by extending the controller. --- js/server/modules/org/arangodb/foxx/controller.js | 10 ++++++++++ js/server/modules/org/arangodb/foxx/request_context.js | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/js/server/modules/org/arangodb/foxx/controller.js b/js/server/modules/org/arangodb/foxx/controller.js index 287f170f31..a1b4e27274 100644 --- a/js/server/modules/org/arangodb/foxx/controller.js +++ b/js/server/modules/org/arangodb/foxx/controller.js @@ -827,9 +827,19 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// extend(extensions) { var attr; + var extensionWrapper = function(scope, functionName) { + return function() { + this.applyChain.push({ + functionName: functionName, + argumentList: arguments + }); + return this; + }.bind(scope); + }; for (attr in extensions) { if (extensions.hasOwnProperty(attr)) { this.extensions[attr] = extensions[attr]; + this.allRoutes[attr] = extensionWrapper(this.allRoutes, attr); } } } diff --git a/js/server/modules/org/arangodb/foxx/request_context.js b/js/server/modules/org/arangodb/foxx/request_context.js index 21fa5fb861..7cca011e74 100644 --- a/js/server/modules/org/arangodb/foxx/request_context.js +++ b/js/server/modules/org/arangodb/foxx/request_context.js @@ -128,7 +128,6 @@ class RequestContext { this.docs = new SwaggerDocs(this.route.docs, models); this.docs.addNickname(route.docs.httpMethod, route.url.match); - executionBuffer.applyEachFunction(this); var attr; var extensionWrapper = function(scope, func) { return function() { @@ -141,6 +140,7 @@ class RequestContext { this[attr] = extensionWrapper(this, extensions[attr]); } } + executionBuffer.applyEachFunction(this); } //////////////////////////////////////////////////////////////////////////////// From 3c14a44c1bab0498e91fc26d1cdd7012b91d6ff4 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Tue, 18 Aug 2015 13:33:51 +0200 Subject: [PATCH 16/29] simpler parsing of replication input --- arangod/Replication/ContinuousSyncer.cpp | 61 +++++++++++------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/arangod/Replication/ContinuousSyncer.cpp b/arangod/Replication/ContinuousSyncer.cpp index 8b7c32097d..e04f527b60 100644 --- a/arangod/Replication/ContinuousSyncer.cpp +++ b/arangod/Replication/ContinuousSyncer.cpp @@ -52,25 +52,6 @@ using namespace triagens::rest; using namespace triagens::arango; using namespace triagens::httpclient; -// ----------------------------------------------------------------------------- -// --SECTION-- private functions -// ----------------------------------------------------------------------------- - -static inline void LocalGetline (char const*& p, - string& line, - char delim) { - char const* q = p; - while (*p != 0 && *p != delim) { - p++; - } - - line.assign(q, p - q); - - if (*p == delim) { - p++; - } -} - // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- @@ -729,27 +710,40 @@ int ContinuousSyncer::applyLogMarker (TRI_json_t const* json, //////////////////////////////////////////////////////////////////////////////// int ContinuousSyncer::applyLog (SimpleHttpResult* response, - string& errorMsg, + std::string& errorMsg, uint64_t& processedMarkers, uint64_t& ignoreCount) { StringBuffer& data = response->getBody(); + char* p = data.begin(); + char* end = p + data.length(); - char const* p = data.c_str(); + // buffer must end with a NUL byte + TRI_ASSERT(*end == '\0'); - while (true) { - string line; + while (p < end) { + char* q = strchr(p, '\n'); - LocalGetline(p, line, '\n'); + if (q == nullptr) { + q = end; + } - if (line.size() < 2) { + char const* lineStart = p; + size_t const lineLength = q - p; + + if (lineLength < 2) { // we are done return TRI_ERROR_NO_ERROR; } + TRI_ASSERT(q <= end); + *q = '\0'; + processedMarkers++; - TRI_json_t* json = TRI_JsonString(TRI_CORE_MEM_ZONE, line.c_str()); + std::unique_ptr json(TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, p)); + + p = q + 1; if (json == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; @@ -757,18 +751,16 @@ int ContinuousSyncer::applyLog (SimpleHttpResult* response, int res; bool skipped; - if (excludeCollection(json)) { + if (excludeCollection(json.get())) { // entry is skipped res = TRI_ERROR_NO_ERROR; skipped = true; } else { - res = applyLogMarker(json, errorMsg); + res = applyLogMarker(json.get(), errorMsg); skipped = false; } - TRI_FreeJson(TRI_CORE_MEM_ZONE, json); - if (res != TRI_ERROR_NO_ERROR) { // apply error @@ -778,11 +770,11 @@ int ContinuousSyncer::applyLog (SimpleHttpResult* response, } if (ignoreCount == 0) { - if (line.size() > 256) { - errorMsg += ", offending marker: " + line.substr(0, 256) + "..."; + if (lineLength > 256) { + errorMsg += ", offending marker: " + std::string(lineStart, 256) + "..."; } else { - errorMsg += ", offending marker: " + line;; + errorMsg += ", offending marker: " + std::string(lineStart, lineLength); } return res; @@ -806,6 +798,9 @@ int ContinuousSyncer::applyLog (SimpleHttpResult* response, ++_applier->_state._skippedOperations; } } + + // reached the end + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// From 80b92488f8a99d63f9a062e780930410ee5abf1d Mon Sep 17 00:00:00 2001 From: Alan Plum Date: Tue, 18 Aug 2015 13:42:38 +0200 Subject: [PATCH 17/29] Don't warn about Foxx app versions at all. --- js/server/modules/org/arangodb/foxx/manager.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/js/server/modules/org/arangodb/foxx/manager.js b/js/server/modules/org/arangodb/foxx/manager.js index e45b20ae7b..ff797209ed 100644 --- a/js/server/modules/org/arangodb/foxx/manager.js +++ b/js/server/modules/org/arangodb/foxx/manager.js @@ -337,13 +337,6 @@ function checkManifest(filename, manifest) { } }); - if (manifest.version && !semver.valid(manifest.version)) { - console.warn( - `Manifest "${filename}" for app "${manifest.name}":` - + ` not a valid semver version: ${manifest.version}.` - ); - } - if (manifest.engines && manifest.engines.arangodb && !semver.satisfies(internal.version, manifest.engines.arangodb)) { console.warn( `Manifest "${filename}" for app "${manifest.name}":` From 05c9005fcc83ba29a56b47902eb4581c02f7ff3f Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Tue, 18 Aug 2015 14:13:26 +0200 Subject: [PATCH 18/29] small refactoring for replication applier functions --- arangod/Replication/ContinuousSyncer.cpp | 4 +- arangod/VocBase/replication-applier.cpp | 126 ++++++++++++++--------- arangod/VocBase/replication-applier.h | 33 +----- arangod/VocBase/vocbase.cpp | 2 +- 4 files changed, 80 insertions(+), 85 deletions(-) diff --git a/arangod/Replication/ContinuousSyncer.cpp b/arangod/Replication/ContinuousSyncer.cpp index e04f527b60..ff060d8dd4 100644 --- a/arangod/Replication/ContinuousSyncer.cpp +++ b/arangod/Replication/ContinuousSyncer.cpp @@ -268,12 +268,10 @@ bool ContinuousSyncer::excludeCollection (std::string const& masterName) const { //////////////////////////////////////////////////////////////////////////////// int ContinuousSyncer::getLocalState (string& errorMsg) { - int res; - uint64_t oldTotalRequests = _applier->_state._totalRequests; uint64_t oldTotalFailedConnects = _applier->_state._totalFailedConnects; - res = TRI_LoadStateReplicationApplier(_vocbase, &_applier->_state); + int res = TRI_LoadStateReplicationApplier(_vocbase, &_applier->_state); _applier->_state._active = true; _applier->_state._totalRequests = oldTotalRequests; _applier->_state._totalFailedConnects = oldTotalFailedConnects; diff --git a/arangod/VocBase/replication-applier.cpp b/arangod/VocBase/replication-applier.cpp index 135be2b116..a09baf1a47 100644 --- a/arangod/VocBase/replication-applier.cpp +++ b/arangod/VocBase/replication-applier.cpp @@ -483,15 +483,19 @@ static int SetError (TRI_replication_applier_t* applier, //////////////////////////////////////////////////////////////////////////////// static void ApplyThread (void* data) { - triagens::arango::ContinuousSyncer* s = static_cast(data); + auto syncer = static_cast(data); // get number of running remote transactions so we can forge the transaction // statistics - int const n = static_cast(s->applier()->_runningRemoteTransactions.size()); + int const n = static_cast(syncer->applier()->_runningRemoteTransactions.size()); triagens::arango::TransactionBase::setNumbers(n, n); - s->run(); - delete s; + try { + syncer->run(); + } + catch (...) { + } + delete syncer; } //////////////////////////////////////////////////////////////////////////////// @@ -505,6 +509,7 @@ static int StartApplier (TRI_replication_applier_t* applier, TRI_replication_applier_state_t* state = &applier->_state; if (state->_active) { + // already running return TRI_ERROR_INTERNAL; } @@ -518,15 +523,11 @@ static int StartApplier (TRI_replication_applier_t* applier, // TODO: prevent restart of the applier with a tick after a shutdown - auto fetcher = new triagens::arango::ContinuousSyncer(applier->_server, - applier->_vocbase, - &applier->_configuration, - initialTick, - useTick); - - if (fetcher == nullptr) { - return TRI_ERROR_OUT_OF_MEMORY; - } + std::unique_ptr syncer(new triagens::arango::ContinuousSyncer(applier->_server, + applier->_vocbase, + &applier->_configuration, + initialTick, + useTick)); // reset error if (state->_lastError._msg != nullptr) { @@ -544,12 +545,12 @@ static int StartApplier (TRI_replication_applier_t* applier, TRI_InitThread(&applier->_thread); - if (! TRI_StartThread(&applier->_thread, nullptr, "[applier]", ApplyThread, static_cast(fetcher))) { - delete fetcher; - + if (! TRI_StartThread(&applier->_thread, nullptr, "[applier]", ApplyThread, static_cast(syncer.get()))) { return TRI_ERROR_INTERNAL; } + syncer.release(); + LOG_INFO("started replication applier for database '%s'", applier->_databaseName); @@ -759,37 +760,6 @@ TRI_replication_applier_t* TRI_CreateReplicationApplier (TRI_server_t* server, return applier; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief destroy a replication applier -//////////////////////////////////////////////////////////////////////////////// - -void TRI_DestroyReplicationApplier (TRI_replication_applier_t* applier) { - TRI_ASSERT(applier != nullptr); - TRI_StopReplicationApplier(applier, true); - -#if 0 - // TODO: fix thread-specific assertions about transactions - for (auto& it : applier->_runningRemoteTransactions) { - auto trx = it.second; - trx->abort(); - delete trx; - } - applier->_runningRemoteTransactions.clear(); -#endif - - TRI_DestroyStateReplicationApplier(&applier->_state); - TRI_DestroyConfigurationReplicationApplier(&applier->_configuration); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief free a replication applier -//////////////////////////////////////////////////////////////////////////////// - -void TRI_FreeReplicationApplier (TRI_replication_applier_t* applier) { - TRI_DestroyReplicationApplier(applier); - delete applier; -} - // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- @@ -807,14 +777,32 @@ bool TRI_WaitReplicationApplier (TRI_replication_applier_t* applier, if (sleepTime > 0) { LOG_TRACE("replication applier going to sleep for %llu ns", (unsigned long long) sleepTime); + static uint64_t const SleepChunk = 500 * 1000; + + while (sleepTime >= SleepChunk) { #ifdef _WIN32 - usleep((unsigned long) sleepTime); + usleep((unsigned long) SleepChunk); #else - usleep((useconds_t) sleepTime); + usleep((useconds_t) SleepChunk); +#endif + + sleepTime -= SleepChunk; + + if (CheckTerminateFlag(applier)) { + return false; + } + } + + if (sleepTime > 0) { +#ifdef _WIN32 + usleep((unsigned long) sleepTime); +#else + usleep((useconds_t) sleepTime); #endif - if (CheckTerminateFlag(applier)) { - return false; + if (CheckTerminateFlag(applier)) { + return false; + } } } @@ -1491,6 +1479,42 @@ int TRI_ForgetReplicationApplier (TRI_replication_applier_t* applier) { return TRI_ERROR_NO_ERROR; } +// ----------------------------------------------------------------------------- +// --SECTION-- TRI_replication_applier_t +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief create a replication applier +//////////////////////////////////////////////////////////////////////////////// + +TRI_replication_applier_t::TRI_replication_applier_t (TRI_server_t* server, + TRI_vocbase_t* vocbase) + : _server(server), + _vocbase(vocbase), + _terminateThread(false), + _databaseName(TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, vocbase->_name)) { +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief destroy a replication applier +//////////////////////////////////////////////////////////////////////////////// + +TRI_replication_applier_t::~TRI_replication_applier_t () { + TRI_StopReplicationApplier(this, true); + TRI_DestroyStateReplicationApplier(&_state); + TRI_DestroyConfigurationReplicationApplier(&_configuration); + + for (auto it = _runningRemoteTransactions.begin(); it != _runningRemoteTransactions.end(); ++it) { + auto trx = (*it).second; + + // do NOT write abort markers so we can resume running transactions later + trx->addHint(TRI_TRANSACTION_HINT_NO_ABORT_MARKER, true); + delete trx; + } + + TRI_FreeString(TRI_CORE_MEM_ZONE, _databaseName); +} + // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/arangod/VocBase/replication-applier.h b/arangod/VocBase/replication-applier.h index bbe3878f83..27ab86fa78 100644 --- a/arangod/VocBase/replication-applier.h +++ b/arangod/VocBase/replication-applier.h @@ -113,25 +113,10 @@ struct TRI_replication_applier_state_t { //////////////////////////////////////////////////////////////////////////////// struct TRI_replication_applier_t { - TRI_replication_applier_t (TRI_server_t* server, - TRI_vocbase_t* vocbase) - : _server(server), - _vocbase(vocbase), - _terminateThread(false), - _databaseName(TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, vocbase->_name)) { - } + TRI_replication_applier_t (TRI_server_t*, + TRI_vocbase_t*); - ~TRI_replication_applier_t () { - for (auto it = _runningRemoteTransactions.begin(); it != _runningRemoteTransactions.end(); ++it) { - auto trx = (*it).second; - - // do NOT write abort markers so we can resume running transactions later - trx->addHint(TRI_TRANSACTION_HINT_NO_ABORT_MARKER, true); - delete trx; - } - - TRI_FreeString(TRI_CORE_MEM_ZONE, _databaseName); - } + ~TRI_replication_applier_t (); void addRemoteTransaction (triagens::arango::ReplicationTransaction* trx) { _runningRemoteTransactions.insert(std::make_pair(trx->externalId(), trx)); @@ -174,18 +159,6 @@ struct TRI_replication_applier_t { TRI_replication_applier_t* TRI_CreateReplicationApplier (TRI_server_t*, TRI_vocbase_t*); -//////////////////////////////////////////////////////////////////////////////// -/// @brief destroy a replication applier -//////////////////////////////////////////////////////////////////////////////// - -void TRI_DestroyReplicationApplier (TRI_replication_applier_t*); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief free a replication applier -//////////////////////////////////////////////////////////////////////////////// - -void TRI_FreeReplicationApplier (TRI_replication_applier_t*); - // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- diff --git a/arangod/VocBase/vocbase.cpp b/arangod/VocBase/vocbase.cpp index 6f1d173e28..0ccff0e405 100644 --- a/arangod/VocBase/vocbase.cpp +++ b/arangod/VocBase/vocbase.cpp @@ -2433,7 +2433,7 @@ TRI_vocbase_t::~TRI_vocbase_t () { // free replication if (_replicationApplier != nullptr) { - TRI_FreeReplicationApplier(_replicationApplier); + delete _replicationApplier; } delete _oldTransactions; From 7a366c605d5c3120683b001cc465a8eddc4d3b95 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Tue, 18 Aug 2015 14:24:19 +0200 Subject: [PATCH 19/29] small refactoring --- arangod/Replication/ContinuousSyncer.cpp | 4 +- arangod/VocBase/replication-applier.cpp | 121 ++++++++++------------- arangod/VocBase/replication-applier.h | 21 ++-- 3 files changed, 67 insertions(+), 79 deletions(-) diff --git a/arangod/Replication/ContinuousSyncer.cpp b/arangod/Replication/ContinuousSyncer.cpp index ff060d8dd4..d86a547e7f 100644 --- a/arangod/Replication/ContinuousSyncer.cpp +++ b/arangod/Replication/ContinuousSyncer.cpp @@ -143,7 +143,7 @@ int ContinuousSyncer::run () { if (connectRetries <= _configuration._maxConnectRetries) { // check if we are aborted externally - if (TRI_WaitReplicationApplier(_applier, 10 * 1000 * 1000)) { + if (_applier->wait(10 * 1000 * 1000)) { continue; } @@ -918,7 +918,7 @@ int ContinuousSyncer::runContinuousSync (string& errorMsg) { // this will make the applier thread sleep if there is nothing to do, // but will also check for cancellation - if (! TRI_WaitReplicationApplier(_applier, sleepTime)) { + if (! _applier->wait(sleepTime)) { return TRI_ERROR_REPLICATION_APPLIER_STOPPED; } } diff --git a/arangod/VocBase/replication-applier.cpp b/arangod/VocBase/replication-applier.cpp index a09baf1a47..1d8e00acf4 100644 --- a/arangod/VocBase/replication-applier.cpp +++ b/arangod/VocBase/replication-applier.cpp @@ -53,24 +53,6 @@ // --SECTION-- private functions // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @brief set flag to terminate the applier thread -//////////////////////////////////////////////////////////////////////////////// - -static void SetTerminateFlag (TRI_replication_applier_t* applier, - bool value) { - - applier->_terminateThread.store(value); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief check whether the applier thread should terminate -//////////////////////////////////////////////////////////////////////////////// - -static bool CheckTerminateFlag (TRI_replication_applier_t* applier) { - return applier->_terminateThread.load(); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief read a tick value from a JSON struct //////////////////////////////////////////////////////////////////////////////// @@ -540,7 +522,7 @@ static int StartApplier (TRI_replication_applier_t* applier, TRI_GetTimeStampReplication(state->_lastError._time, sizeof(state->_lastError._time) - 1); - SetTerminateFlag(applier, false); + applier->setTermination(false); state->_active = true; TRI_InitThread(&applier->_thread); @@ -572,7 +554,7 @@ static int StopApplier (TRI_replication_applier_t* applier, state->_active = false; - SetTerminateFlag(applier, true); + applier->setTermination(true); TRI_SetProgressReplicationApplier(applier, "applier stopped", false); @@ -604,7 +586,7 @@ static int ShutdownApplier (TRI_replication_applier_t* applier) { state->_active = false; - SetTerminateFlag(applier, true); + applier->setTermination(true); TRI_SetProgressReplicationApplier(applier, "applier shut down", false); @@ -751,7 +733,7 @@ TRI_replication_applier_t* TRI_CreateReplicationApplier (TRI_server_t* server, } } - SetTerminateFlag(applier, false); + applier->setTermination(false); TRI_ASSERT(applier->_databaseName != nullptr); @@ -764,51 +746,6 @@ TRI_replication_applier_t* TRI_CreateReplicationApplier (TRI_server_t* server, // --SECTION-- public functions // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @brief checks whether the applier thread should terminate -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_WaitReplicationApplier (TRI_replication_applier_t* applier, - uint64_t sleepTime) { - if (CheckTerminateFlag(applier)) { - return false; - } - - if (sleepTime > 0) { - LOG_TRACE("replication applier going to sleep for %llu ns", (unsigned long long) sleepTime); - - static uint64_t const SleepChunk = 500 * 1000; - - while (sleepTime >= SleepChunk) { -#ifdef _WIN32 - usleep((unsigned long) SleepChunk); -#else - usleep((useconds_t) SleepChunk); -#endif - - sleepTime -= SleepChunk; - - if (CheckTerminateFlag(applier)) { - return false; - } - } - - if (sleepTime > 0) { -#ifdef _WIN32 - usleep((unsigned long) sleepTime); -#else - usleep((useconds_t) sleepTime); -#endif - - if (CheckTerminateFlag(applier)) { - return false; - } - } - } - - return true; -} - //////////////////////////////////////////////////////////////////////////////// /// @brief get a JSON representation of the replication applier configuration //////////////////////////////////////////////////////////////////////////////// @@ -833,7 +770,7 @@ int TRI_StartReplicationApplier (TRI_replication_applier_t* applier, } // wait until previous applier thread is shut down - while (! TRI_WaitReplicationApplier(applier, 10 * 1000)); + while (! applier->wait(10 * 1000)); WRITE_LOCKER(applier->_statusLock); @@ -885,7 +822,7 @@ int TRI_StopReplicationApplier (TRI_replication_applier_t* applier, } } - SetTerminateFlag(applier, false); + applier->setTermination(false); LOG_INFO("stopped replication applier for database '%s'", applier->_databaseName); @@ -935,7 +872,7 @@ int TRI_ShutdownReplicationApplier (TRI_replication_applier_t* applier) { } } - SetTerminateFlag(applier, false); + applier->setTermination(false); { WRITE_LOCKER(applier->_statusLock); @@ -1515,6 +1452,50 @@ TRI_replication_applier_t::~TRI_replication_applier_t () { TRI_FreeString(TRI_CORE_MEM_ZONE, _databaseName); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief pauses and checks whether the apply thread should terminate +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_replication_applier_t::wait (uint64_t sleepTime) { + if (isTerminated()) { + return false; + } + + if (sleepTime > 0) { + LOG_TRACE("replication applier going to sleep for %llu ns", (unsigned long long) sleepTime); + + static uint64_t const SleepChunk = 500 * 1000; + + while (sleepTime >= SleepChunk) { +#ifdef _WIN32 + usleep((unsigned long) SleepChunk); +#else + usleep((useconds_t) SleepChunk); +#endif + + sleepTime -= SleepChunk; + + if (isTerminated()) { + return false; + } + } + + if (sleepTime > 0) { +#ifdef _WIN32 + usleep((unsigned long) sleepTime); +#else + usleep((useconds_t) sleepTime); +#endif + + if (isTerminated()) { + return false; + } + } + } + + return true; +} + // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/arangod/VocBase/replication-applier.h b/arangod/VocBase/replication-applier.h index 27ab86fa78..e9a54a2791 100644 --- a/arangod/VocBase/replication-applier.h +++ b/arangod/VocBase/replication-applier.h @@ -118,6 +118,20 @@ struct TRI_replication_applier_t { ~TRI_replication_applier_t (); +//////////////////////////////////////////////////////////////////////////////// +/// @brief pauses and checks whether the apply thread should terminate +//////////////////////////////////////////////////////////////////////////////// + + bool wait (uint64_t); + + bool isTerminated () { + return _terminateThread.load(); + } + + void setTermination (bool value) { + _terminateThread.store(value); + } + void addRemoteTransaction (triagens::arango::ReplicationTransaction* trx) { _runningRemoteTransactions.insert(std::make_pair(trx->externalId(), trx)); } @@ -163,13 +177,6 @@ TRI_replication_applier_t* TRI_CreateReplicationApplier (TRI_server_t*, // --SECTION-- public functions // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @brief checks whether the apply thread should terminate -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_WaitReplicationApplier (TRI_replication_applier_t*, - uint64_t); - //////////////////////////////////////////////////////////////////////////////// /// @brief get a JSON representation of the replication apply configuration //////////////////////////////////////////////////////////////////////////////// From 487228ae83a3cd57a5407f42db576342c54b991c Mon Sep 17 00:00:00 2001 From: Willi Goesgens Date: Tue, 18 Aug 2015 15:41:27 +0200 Subject: [PATCH 20/29] Unix domainsocket startup: use arangosh to check whether the server is up and running. --- UnitTests/Makefile.unittests | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/UnitTests/Makefile.unittests b/UnitTests/Makefile.unittests index 1467f62db5..3a56010fba 100755 --- a/UnitTests/Makefile.unittests +++ b/UnitTests/Makefile.unittests @@ -144,9 +144,24 @@ start-server: @test -d "$(VOCDIR)" ($(VALGRIND) @builddir@/bin/arangod "$(VOCDIR)" $(SERVER_OPT) --pid-file $(PIDFILE) --watch-process $(PID) && rm -rf "$(VOCDIR)") & +# Wait for http/https server endpoints: + @test "$(PROTO)" == "unix" || \ + ( \ + rm -f "$(STARTFILE)"; \ + while [ ! -s "$(STARTFILE)" ]; do \ + $(CURL) $(CURL_OPT) --insecure -X GET -s "$(PROTO)://$(VOCHOST):$(VOCPORT)/_api/version" > "$(STARTFILE)" || \ + sleep 2; \ + done) +# wait for unix domain socket enpoints: + @(test "$(PROTO)" == "unix" && \ + while ! ./bin/arangosh \ + --server.endpoint unix://$(VOCDIR)/arango.sock \ + --javascript.execute-string 'if (arango.GET("/_api/version").server === "arango") { 0; } else {1; }'; do \ + sleep 1; \ + echo .; \ + done;) ||\ + true - @test "$(PROTO)" == "unix" || (rm -f "$(STARTFILE)"; while [ ! -s "$(STARTFILE)" ]; do $(CURL) $(CURL_OPT) --insecure -X GET -s "$(PROTO)://$(VOCHOST):$(VOCPORT)/_api/version" > "$(STARTFILE)" || sleep 2; done) - @(test "$(PROTO)" == "unix" && sleep 8) || true @rm -f "$(STARTFILE)" @echo "server has been started." @if [ "$(VALGRIND)" != "" ]; then echo "adding valgrind memorial time..."; sleep 75; else sleep 2; fi @@ -1009,7 +1024,6 @@ unittests-arangob: @echo "<< ARANGOB TESTS >>" @echo "================================================================================" @echo - @builddir@/bin/arangob --configuration none --quiet --server.username "$(USERNAME)" --server.password "$(PASSWORD)" --server.endpoint unix://$(VOCDIR)/arango.sock --requests 10000 --concurrency 2 --test version --keep-alive false || test "x$(FORCE)" == "x1" @builddir@/bin/arangob --configuration none --quiet --server.username "$(USERNAME)" --server.password "$(PASSWORD)" --server.endpoint unix://$(VOCDIR)/arango.sock --requests 10000 --concurrency 2 --test version --async true || test "x$(FORCE)" == "x1" @builddir@/bin/arangob --configuration none --quiet --server.username "$(USERNAME)" --server.password "$(PASSWORD)" --server.endpoint unix://$(VOCDIR)/arango.sock --requests 20000 --concurrency 1 --test version --async true || test "x$(FORCE)" == "x1" From 602c3d0d59a8080346217296676157ff0aa439a6 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Tue, 18 Aug 2015 16:14:39 +0200 Subject: [PATCH 21/29] Improved the documentation for Foxx controller --- .../Books/Users/Foxx/Develop/Controller.mdpp | 36 +-- .../Books/Users/Foxx/Develop/View.mdpp | 3 - Documentation/Books/Users/SUMMARY.md | 3 +- .../modules/org/arangodb/foxx/controller.js | 183 +++++++++++----- .../org/arangodb/foxx/request_context.js | 207 +++++++++++------- .../org/arangodb/foxx/template_middleware.js | 8 +- 6 files changed, 282 insertions(+), 158 deletions(-) delete mode 100644 Documentation/Books/Users/Foxx/Develop/View.mdpp diff --git a/Documentation/Books/Users/Foxx/Develop/Controller.mdpp b/Documentation/Books/Users/Foxx/Develop/Controller.mdpp index 6237c79940..2124bdd5d2 100644 --- a/Documentation/Books/Users/Foxx/Develop/Controller.mdpp +++ b/Documentation/Books/Users/Foxx/Develop/Controller.mdpp @@ -1,4 +1,4 @@ -!CHAPTER Details on FoxxController +!CHAPTER Details on Controller !SUBSECTION Create @@ -86,12 +86,16 @@ API by chaining the following methods onto your path definition: @startDocuBlock JSF_foxx_RequestContext_notes -!SUBSECTION pathParams in buffer -@startDocuBlock JSF_foxx_RequestContextBuffer_pathParam -!SUBSECTION bodyParams in buffer -@startDocuBlock JSF_foxx_RequestContextBuffer_queryParam +!SUBSECTION extend +In many use-cases several of the functions are always used in a certain combination (e.g.: `onlyIf` with `errorResponse`). +In order to avoid duplicating this equal usage for several routes in your application you can +extend the controller with your own functions. +These functions can simply combine several of the above on a single name, so you only have to +invoke your self defined single function on all routes using these extensions. + +@startDocuBlock JSF_foxx_controller_extend !SECTION Documenting and constraining all routes @@ -123,18 +127,24 @@ ctrl.get('/another/route', function (req, res) { }); // no errorResponse needed here either ``` -!SUBSECTION Buffer errorResponse +!SUBSECTION errorResponse @startDocuBlock JSF_foxx_RequestContextBuffer_errorResponse -!SUBSECTION Buffer onlyIf +!SUBSECTION onlyIf @startDocuBlock JSF_foxx_RequestContextBuffer_onlyIf -!SUBSECTION Buffer onlyIfAuthenticated +!SUBSECTION onlyIfAuthenticated @startDocuBlock JSF_foxx_RequestContextBuffer_onlyIfAuthenticated +!SUBSECTION pathParam +@startDocuBlock JSF_foxx_RequestContextBuffer_pathParam + +!SUBSECTION bodyParam +@startDocuBlock JSF_foxx_RequestContextBuffer_queryParam + !SECTION Before and After Hooks @@ -222,9 +232,6 @@ convenience methods: @startDocuBlock JSF_foxx_BaseMiddleware_request_rawBodyBuffer - -@startDocuBlock JSF_foxx_BaseMiddleware_request_requestParts - !SUBSECTION params @startDocuBlock JSF_foxx_BaseMiddleware_request_params @@ -233,6 +240,10 @@ convenience methods: @startDocuBlock JSF_foxx_BaseMiddleware_request_cookie +!SUBSECTION requestParts +Only useful for multi-part requests. + +@startDocuBlock JSF_foxx_BaseMiddleware_request_requestParts !SECTION The Response Object @@ -341,6 +352,3 @@ To use the application-specific authentication in your own app, first activate i !SUBSUBSECTION Restricting routes To restrict routes, see the documentation for Documenting and Restraining the routes. - - -@startDocuBlock JSF_foxx_controller_extend diff --git a/Documentation/Books/Users/Foxx/Develop/View.mdpp b/Documentation/Books/Users/Foxx/Develop/View.mdpp deleted file mode 100644 index 6fd038f041..0000000000 --- a/Documentation/Books/Users/Foxx/Develop/View.mdpp +++ /dev/null @@ -1,3 +0,0 @@ -@startDocuBlock JSF_foxx_TemplateMiddleware_initializer - -@startDocuBlock JSF_foxx_TemplateMiddleware_response_render diff --git a/Documentation/Books/Users/SUMMARY.md b/Documentation/Books/Users/SUMMARY.md index 984bbb89a2..778cae32ea 100644 --- a/Documentation/Books/Users/SUMMARY.md +++ b/Documentation/Books/Users/SUMMARY.md @@ -5,7 +5,7 @@ * [Windows](Installing/Windows.md) * [Compiling](Installing/Compiling.md) * [Upgrading](Installing/Upgrading.md) - * [Incompatible changes in 2.6](Upgrading/UpgradingChanges27.md) + * [Incompatible changes in 2.7](Upgrading/UpgradingChanges27.md) * [Incompatible changes in 2.6](Upgrading/UpgradingChanges26.md) * [Upgrading to 2.6](Upgrading/Upgrading26.md) * [Incompatible changes in 2.5](Upgrading/UpgradingChanges25.md) @@ -112,7 +112,6 @@ * [Controller](Foxx/Develop/Controller.md) * [Scripts](Foxx/Develop/Scripts.md) * [Model](Foxx/Develop/Model.md) - * [View](Foxx/Develop/View.md) * [Repository](Foxx/Develop/Repository.md) * [Queries](Foxx/Develop/Queries.md) * [Sessions](Foxx/Develop/Sessions.md) diff --git a/js/server/modules/org/arangodb/foxx/controller.js b/js/server/modules/org/arangodb/foxx/controller.js index a1b4e27274..b0efd3f083 100644 --- a/js/server/modules/org/arangodb/foxx/controller.js +++ b/js/server/modules/org/arangodb/foxx/controller.js @@ -275,7 +275,7 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_initializer /// -/// `new FoxxController(applicationContext, options)` +/// `new Controller(applicationContext, options)` /// /// This creates a new Controller. The first argument is the controller /// context available in the variable *applicationContext*. The second one is an @@ -417,11 +417,25 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_head /// -/// `FoxxController#head(path, callback)` +/// `Controller.head(path, callback)` +/// +/// Defines a new route on `path` that handles requests from the HTTP verb `head`. +/// This route can also be 'parameterized' like `/goose/:barn`. +/// In this case you can later get the value the user provided for `barn` +/// via the `params` function in the `request`. +/// The function defined in `callback` will be invoked whenever this type of +/// request is recieved. +/// `callback` get's two arguments `request` and `response`, see below for further +/// information about these objects. +/// +/// @EXAMPLES +/// +/// ```js +/// app.head('/goose/barn', function (req, res) { +/// // Take this request and deal with it! +/// }); +/// ``` /// -/// This handles requests from the HTTP verb *head*. You have to give a -/// function as *callback*. It will get a request and response object as its -/// arguments /// @endDocuBlock //////////////////////////////////////////////////////////////////////////////// @@ -432,14 +446,16 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_get /// -/// `FoxxController#get(path, callback)` +/// `Controller.get(path, callback)` /// -/// This handles requests from the HTTP verb *get*. -/// -/// When defining a route you can also define a so called 'parameterized' -/// *path* like */goose/:barn*. In this case you can later get the value -/// the user provided for *barn* via the *params* function (see the Request -/// object). +/// Defines a new route on `path` that handles requests from the HTTP verb `get`. +/// This route can also be 'parameterized' like `/goose/:barn`. +/// In this case you can later get the value the user provided for `barn` +/// via the `params` function in the `request`. +/// The function defined in `callback` will be invoked whenever this type of +/// request is recieved. +/// `callback` get's two arguments `request` and `response`, see below for further +/// information about these objects. /// /// @EXAMPLES /// @@ -459,10 +475,16 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_post /// -/// `FoxxController#post(path, callback)` +/// `Controller.post(path, callback)` /// -/// This handles requests from the HTTP verb *post*. See above for the -/// arguments you can give. +/// Defines a new route on `path` that handles requests from the HTTP verb `post`. +/// This route can also be 'parameterized' like `/goose/:barn`. +/// In this case you can later get the value the user provided for `barn` +/// via the `params` function in the `request`. +/// The function defined in `callback` will be invoked whenever this type of +/// request is recieved. +/// `callback` get's two arguments `request` and `response`, see below for further +/// information about these objects. /// /// @EXAMPLES /// @@ -482,10 +504,16 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_put /// -/// `FoxxController#put(path, callback)` +/// `Controller.put(path, callback)` /// -/// This handles requests from the HTTP verb *put*. See above for the arguments -/// you can give. +/// Defines a new route on `path` that handles requests from the HTTP verb `put`. +/// This route can also be 'parameterized' like `/goose/:barn`. +/// In this case you can later get the value the user provided for `barn` +/// via the `params` function in the `request`. +/// The function defined in `callback` will be invoked whenever this type of +/// request is recieved. +/// `callback` get's two arguments `request` and `response`, see below for further +/// information about these objects. /// /// @EXAMPLES /// @@ -505,10 +533,16 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_patch /// -/// `FoxxController#patch(path, callback)` +/// `Controller.patch(path, callback)` /// -/// This handles requests from the HTTP verb *patch*. See above for the -/// arguments you can give. +/// Defines a new route on `path` that handles requests from the HTTP verb `patch`. +/// This route can also be 'parameterized' like `/goose/:barn`. +/// In this case you can later get the value the user provided for `barn` +/// via the `params` function in the `request`. +/// The function defined in `callback` will be invoked whenever this type of +/// request is recieved. +/// `callback` get's two arguments `request` and `response`, see below for further +/// information about these objects. /// /// @EXAMPLES /// @@ -528,10 +562,16 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_delete /// -/// `FoxxController#delete(path, callback)` +/// `Controller.delete(path, callback)` /// -/// This handles requests from the HTTP verb *delete*. See above for the -/// arguments you can give. +/// Defines a new route on `path` that handles requests from the HTTP verb `delete`. +/// This route can also be 'parameterized' like `/goose/:barn`. +/// In this case you can later get the value the user provided for `barn` +/// via the `params` function in the `request`. +/// The function defined in `callback` will be invoked whenever this type of +/// request is recieved. +/// `callback` get's two arguments `request` and `response`, see below for further +/// information about these objects. /// /// @EXAMPLES /// @@ -556,14 +596,16 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_before /// -/// `FoxxController#before(path, callback)` +/// `Controller.before(path, callback)` /// -/// The before function takes a *path* on which it should watch and a -/// function that it should execute before the routing takes place. If you do -/// omit the path, the function will be executed before each request, no matter -/// the path. Your function gets a Request and a Response object. +/// Defines an additional function on the route `path` which will be executed +/// before the callback defined for a specific HTTP verb is executed. +/// The `callback` function has the same signature as the `callback` in the +/// specific route. +/// You can also omit the `path`, in this case `callback` will be executed +/// before handleing any request in this Controller. /// -/// If your callback returns the Boolean value *false*, the route handling +/// If `callback` returns the Boolean value `false`, the route handling /// will not proceed. You can use this to intercept invalid or unauthorized /// requests and prevent them from being passed to the matching routes. /// @@ -601,10 +643,10 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_after /// -/// `FoxxController#after(path, callback)` +/// `Controller.after(path, callback)` /// -/// This works pretty similar to the before function. But it acts after the -/// execution of the handlers (Big surprise, I suppose). +/// Similar to `Controller.before(path, callback)` but `callback` will be invoked +/// after the request is handled in the specific route. /// /// @EXAMPLES /// @@ -635,14 +677,17 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_around /// -/// `FoxxController#around(path, callback)` +/// `Controller.around(path, callback)` /// -/// The around function takes a *path* on which it should watch and a function -/// that it should execute around the function which normally handles the -/// route. If you do omit the path, the function will be executed before each -/// request, no matter the path. Your function gets a Request and a Response -/// object and a next function, which you must call to execute the handler for -/// that route. +/// Similar to `Controller.before(path, callback)` `callback` will be invoked +/// instead of the specific handler. +/// `callback` takes two additional paramaters `opts` and `next` where +/// `opts` contains options assigned to the route and `next` is a function. +/// Whenever you call `next` in `callback` the specific handler is invoked, +/// if you do not call `next` the specific handler will not be invoked at all. +/// So using around you can execute code before and after a specific handler +/// and even call the handler only under certain circumstances. +/// If you omit `path` `callback` will be called on every request. /// /// @EXAMPLES /// @@ -677,10 +722,10 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_activateAuthentication /// -/// `FoxxController#activateAuthentication(opts)` +/// `Controller.activateAuthentication(opts)` /// -/// To activate authentication for this controller, first call this function. -/// Provide the following arguments: +/// To activate authentication for this controller, call this function before defining any routes. +/// In the `opts` object you can set the following keys: /// /// * *type*: Currently we only support *cookie*, but this will change in the future /// * *cookieLifetime*: An integer. Lifetime of cookies in seconds @@ -712,10 +757,10 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_activateSessions /// -/// `FoxxController#activateAuthentication(opts)` +/// `Controller.activateSessions(opts)` /// -/// To activate sessions for this sessions, first call this function. -/// Provide the following arguments: +/// To activate sessions for this controller, call this function before defining any routes. +/// In the `opts` object you can set the following keys: /// /// * *type*: Currently we only support *cookie*, but this will change in the future. Defaults to *"cookie"*. /// * *cookieName*: A string used as the name of the cookie. Defaults to *"sid"*. @@ -737,6 +782,7 @@ class Controller { /// /// @endDocuBlock //////////////////////////////////////////////////////////////////////////////// + activateSessions(opts) { var sessions = require('org/arangodb/foxx/sessions'); _.extend(this, sessionControllerProps); @@ -748,11 +794,11 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_apiDocumentation /// -/// `FoxxController#apiDocumentation(path, [opts])` +/// `Controller.apiDocumentation(path, [opts])` /// -/// Mounts the API documentation (Swagger) at the given *path*. +/// Mounts the API documentation (Swagger) at the given `path`. /// -/// Note that the **path** can use URL parameters as usual but must not use any +/// Note that the `path` can use URL parameters as usual but must not use any /// wildcard (`*`) or optional (`:name?`) parameters. /// /// The optional **opts** can be an object with any of the following properties: @@ -819,12 +865,49 @@ class Controller { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_controller_extend /// -/// `FoxxController#extend(extensions)` +/// `Controller.extend(extensions)` +/// +/// Extends all functions to define routes in this controller. +/// This allows to combine several route extensions with the invocation +/// of a single function. +/// This is especially useful if you use the same input parameter in several routes of +/// your controller and want to apply the same validation, documentation and error handling +/// for it. +/// +/// The `extensions` parameter is a JSON object with arbitrary keys. +/// Each key is used as the name of the function you want to define (you cannot overwrite +/// internal functions like `pathParam`) and the value is a function that will be invoked. +/// This function can get arbitrary many arguments and the `this` of the function is bound +/// to the route definition object (e.g. you can use `this.pathParam()`). +/// Your newly defined function is chainable similar to the internal functions. /// /// **Examples** /// +/// Define a validator for a queryParameter, including documentation and errorResponses +/// in a single command: +/// +/// ```js +/// controller.extend({ +/// myParam: function (maxValue) { +/// this.queryParam("value", {type: joi.number().required()}); +/// this.onlyIf(function(req) { +/// var v = req.param("value"); +/// if (v > maxValue) { +/// throw new NumberTooLargeError(); +/// } +/// }); +/// this.errorResponse(NumberTooLargeError, 400, "The given value is too large"); +/// } +/// }); +/// +/// controller.get("/goose/barn", function(req, res) { +/// // Will only be invoked if the request has parameter value and it is less or equal 5. +/// }).myParam(5); +/// ``` +/// /// @endDocuBlock //////////////////////////////////////////////////////////////////////////////// + extend(extensions) { var attr; var extensionWrapper = function(scope, functionName) { diff --git a/js/server/modules/org/arangodb/foxx/request_context.js b/js/server/modules/org/arangodb/foxx/request_context.js index 7cca011e74..e3eed76593 100644 --- a/js/server/modules/org/arangodb/foxx/request_context.js +++ b/js/server/modules/org/arangodb/foxx/request_context.js @@ -146,8 +146,15 @@ class RequestContext { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContext_pathParam /// -/// If you defined a route "/foxx/:id", you can constrain which format a path -/// parameter (*/foxx/12*) can have by giving it a *joi* type. +/// `Route.pathParam(id, options)` +/// +/// If you defined a route "/foxx/:name", containing a parameter called `name` you can +/// constrain which format this parameter is allowed to have. +/// This format is defined using *joi* in the `options` parameter. +/// Using this function will at first allow you to access this parameter in your +/// route handler using `req.params(id)`, will reject any request having a paramter +/// that does not match the *joi* definition and creates a documentation for this +/// parameter in ArangoDBs WebInterface. /// /// For more information on *joi* see [the official Joi documentation](https://github.com/spumko/joi). /// @@ -162,20 +169,20 @@ class RequestContext { /// *Examples* /// /// ```js -/// app.get("/foxx/:id", function { +/// app.get("/foxx/:name", function { /// // Do something -/// }).pathParam("id", joi.number().integer().required().description("Id of the Foxx")); +/// }).pathParam("name", joi.number().integer().required().description("Name of the Foxx")); /// ``` /// /// You can also pass in a configuration object instead: /// /// ```js -/// app.get("/foxx/:id", function { +/// app.get("/foxx/:name", function { /// // Do something -/// }).pathParam("id", { +/// }).pathParam("name", { /// type: joi.number().integer(), /// required: true, -/// description: "Id of the Foxx" +/// description: "Name of the Foxx" /// }); /// ``` /// @endDocuBlock @@ -243,12 +250,16 @@ class RequestContext { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContext_queryParam /// -/// `FoxxController#queryParam(id, options)` +/// `Route.queryParam(id, options)` /// /// Describe a query parameter: /// -/// If you defined a route "/foxx", you can constrain which format a query -/// parameter (*/foxx?a=12*) can have by giving it a *joi* type. +/// If you defined a route "/foxx", you can allow a query paramter with the +/// name `id` on it and constrain the format of this parameter by giving it a *joi* type in the `options` parameter. +/// Using this function will at first allow you to access this parameter in your +/// route handler using `req.params(id)`, will reject any request having a paramter +/// that does not match the *joi* definition and creates a documentation for this +/// parameter in ArangoDBs WebInterface. /// /// For more information on *joi* see [the official Joi documentation](https://github.com/spumko/joi). /// @@ -360,29 +371,29 @@ class RequestContext { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContext_bodyParam /// -/// `FoxxController#bodyParam(paramName, options)` +/// `Route.bodyParam(paramName, options)` /// -/// Expect the body of the request to be a JSON with the attributes you annotated -/// in your model. It will appear alongside the provided description in your -/// Documentation. -/// This will initialize a *Model* with the data and provide it to you via the -/// params as *paramName*. +/// Defines that this route expects a JSON body when requested and binds it to +/// a pseudo parameter with the name `paramName`. +/// The body can than be read in the the handler using `req.params(paramName)` on the request object. +/// In the `options` parameter you can define how a valid request body should look like. +/// This definition can be done in two ways, either using *joi* directly. +/// Accessing the body in this case will give you a JSON object. +/// The other way is to use a Foxx *Model*. +/// Accessing the body in this case will give you an instance of this Model. +/// For both ways an entry for the body will be added in the Documentation in ArangoDBs WebInterface. /// For information about how to annotate your models, see the Model section. -/// If you provide the Model in an array, the response will take multiple models -/// instead of one. +/// All requests sending a body that does not match the validation given this way +/// will automatically be rejected. /// -/// If you wrap the provided model in an array, the body param is always an array -/// and accordingly the return value of the *params* for the body call will also -/// return an array of models. +/// You can also wrap the definition into an array, in this case this route +/// expects a body of type array containing arbitrary many valid objects. +/// Accessing the body parameter will then of course return an array of objects. /// -/// Alternatively you can provide a joi schema instead of a model to allow -/// arbitrary data. When using a joi schema or a model that has a joi schema, -/// well-formed request bodies will be rejected if they don't pass schema validation. -/// -/// The behavior of *bodyParam* changes depending on the *rootElement* option -/// set in the [manifest](../Develop/Manifest.md). If it is set to true, it is +/// Note: The behavior of `bodyParam` changes depending on the `rootElement` option +/// set in the [manifest](../Develop/Manifest.md). If it is set to `true`, it is /// expected that the body is an -/// object with a key of the same name as the *paramName* argument. +/// object with a key of the same name as the `paramName` argument. /// The value of this object is either a single object or in the case of a multi /// element an array of objects. /// @@ -506,10 +517,37 @@ class RequestContext { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContext_summary /// -/// `FoxxController#summary(description)` +/// `Route.summary(description)` /// /// Set the summary for this route in the documentation. -/// Can't be longer than 8192 characters +/// Can't be longer than 8192 characters. +/// This is equal to using JavaDoc style comments right above your function. +/// If you provide both comment and `summary()` the call to `summary()` wins +/// and will be used. +/// +/// *Examples* +/// +/// Version with comment: +/// +/// ```js +/// /** Short description +/// * +/// * Longer description +/// * with multiple lines +/// */ +/// app.get("/foxx", function() { +/// }); +/// ``` +/// +/// is identical to: +/// +/// ```js +/// app.get("/foxx", function() { +/// }) +/// .summary("Short description") +/// .notes(["Longer description", "with multiple lines"]); +/// ``` +/// /// @endDocuBlock //////////////////////////////////////////////////////////////////////////////// @@ -524,9 +562,33 @@ class RequestContext { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContext_notes /// -/// `FoxxController#notes(...description)` +/// `Route.notes(...description)` +/// +/// Set the long description for this route in the documentation +// +/// *Examples* +/// +/// Version with comment: +/// +/// ```js +/// /** Short description +/// * +/// * Longer description +/// * with multiple lines +/// */ +/// app.get("/foxx", function() { +/// }); +/// ``` +/// +/// is identical to: +/// +/// ```js +/// app.get("/foxx", function() { +/// }) +/// .summary("Short description") +/// .notes(["Longer description", "with multiple lines"]); +/// ``` /// -/// Set the notes for this route in the documentation /// @endDocuBlock //////////////////////////////////////////////////////////////////////////////// @@ -539,15 +601,16 @@ class RequestContext { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContext_errorResponse /// -/// `FoxxController#errorResponse(errorClassOrName, code, description)` +/// `Route.errorResponse(errorClassOrName, code, description, [callback])` /// /// Define a reaction to a thrown error for this route: If your handler throws an error -/// of the errorClass or with the name, it will be caught and the response will have the given +/// of the errorClass defined in `errorClassOrName` or the error has an attribute `name` equal to `errorClassOrName`, +/// it will be caught and the response object will be filled with the given /// status code and a JSON with error set to your description as the body. /// /// If you want more control over the returned JSON, you can give an optional fourth /// parameter in form of a function. It gets the error as an argument, the return -/// value will transformed into JSON and then be used as the body. +/// value will be transformed into JSON and then be used as the body. /// The status code will be used as described above. The description will be used for /// the documentation. /// @@ -593,11 +656,14 @@ class RequestContext { //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContext_onlyIf /// -/// `FoxxController#onlyIf(check)` +/// `Route.onlyIf(check)` /// -/// Provide it with a function that throws an exception if the normal processing should -/// not be executed. Provide an `errorResponse` to define the behavior in this case. -/// This can be used for authentication or authorization for example. +/// This functionality is used to secure a route by applying a checking function +/// on the request beforehand, for example the check authorization. +/// It expects `check` to be a function that takes the request object as first parameter. +/// This function is executed before the actual handler is invoked. +/// If `check` throws an error the actual handler will not be invoked. +/// Remember to provide an `errorResponse` on the route as well to define the behavior in this case. /// /// *Examples* /// @@ -680,40 +746,31 @@ _.each([ //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContextBuffer_pathParam /// -/// If you defined a route "/foxx/:id", you can constrain which format a path -/// parameter (*/foxx/12*) can have by giving it a *joi* type. +/// `Controller.allRoutes.pathParam(id, options)` /// -/// For more information on *joi* see [the official Joi documentation](https://github.com/spumko/joi). -/// -/// *Parameter* -/// -/// * *id*: name of the param. -/// * *options*: a joi schema or an object with the following properties: -/// * *type*: a joi schema. -/// * *description*: documentation description for the parameter. -/// * *required* (optional): whether the parameter is required. Default: determined by *type*. +/// This is equal to invoking `Route.pathParam` on all routes bound to this controller. /// /// *Examples* /// /// ```js -/// app.allroutes.pathParam("id", joi.number().integer().required().description("Id of the Foxx")); +/// app.allRoutes.pathParam("id", joi.number().integer().required().description("Id of the Foxx")); /// /// app.get("/foxx/:id", function { -/// // Do something +/// // Secured by pathParam /// }); /// ``` /// /// You can also pass in a configuration object instead: /// /// ```js -/// app.allroutes.pathParam("id", { +/// app.allRoutes.pathParam("id", { /// type: joi.number().integer(), /// required: true, /// description: "Id of the Foxx" /// }); /// /// app.get("/foxx/:id", function { -/// // Do something +/// // Secured by pathParam /// }); /// ``` /// @endDocuBlock @@ -722,26 +779,9 @@ _.each([ //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContextBuffer_queryParam /// -/// `FoxxController#queryParam(id, options)` +/// `Controller.allRoutes.queryParam(id, options)` /// -/// Describe a query parameter: -/// -/// If you defined a route "/foxx", you can constrain which format a query -/// parameter (*/foxx?a=12*) can have by giving it a *joi* type. -/// -/// For more information on *joi* see [the official Joi documentation](https://github.com/spumko/joi). -/// -/// You can also provide a description of this parameter and -/// whether you can provide the parameter multiple times. -/// -/// *Parameter* -/// -/// * *id*: name of the parameter -/// * *options*: a joi schema or an object with the following properties: -/// * *type*: a joi schema -/// * *description*: documentation description for this param. -/// * *required* (optional): whether the param is required. Default: determined by *type*. -/// * *allowMultiple* (optional): whether the param can be specified more than once. Default: `false`. +/// This is equal to invoking `Route.queryParam` on all routes bound to this controller. /// /// *Examples* /// @@ -777,15 +817,14 @@ _.each([ //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContextBuffer_errorResponse /// -/// `RequestContextBuffer#errorResponse(errorClass, code, description)` +/// `Controller.allRoutes.errorResponse(errorClass, code, description)` /// -/// Defines an *errorResponse* for all routes of this controller. For details on -/// *errorResponse* see the according method on routes. +/// This is equal to invoking `Route.errorResponse` on all routes bound to this controller. /// /// *Examples* /// /// ```js -/// app.allroutes.errorResponse(FoxxyError, 303, "This went completely wrong. Sorry!"); +/// app.allRoutes.errorResponse(FoxxyError, 303, "This went completely wrong. Sorry!"); /// /// app.get("/foxx", function { /// // Do something @@ -798,15 +837,14 @@ _.each([ //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContextBuffer_onlyIf /// -/// `RequestContextBuffer#onlyIf(code, reason)` +/// `Controller.allRoutes.onlyIf(code, reason)` /// -/// Defines an *onlyIf* for all routes of this controller. For details on -/// *onlyIf* see the according method on routes. +/// This is equal to invoking `Route.onlyIf` on all routes bound to this controller. /// /// *Examples* /// /// ```js -/// app.allroutes.onlyIf(myPersonalCheck); +/// app.allRoutes.onlyIf(myPersonalCheck); /// /// app.get("/foxx", function { /// // Do something @@ -819,15 +857,14 @@ _.each([ //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_foxx_RequestContextBuffer_onlyIfAuthenticated /// -/// `RequestContextBuffer#onlyIfAuthenticated(code, description)` +/// `Controller.allRoutes.onlyIfAuthenticated(code, description)` /// -/// Defines an *onlyIfAuthenticated* for all routes of this controller. For details on -/// *onlyIfAuthenticated* see the according method on routes. +/// This is equal to invoking `Route.onlyIfAuthenticated` on all routes bound to this controller. /// /// *Examples* /// /// ```js -/// app.allroutes.onlyIfAuthenticated(401, "You need to be authenticated"); +/// app.allRoutes.onlyIfAuthenticated(401, "You need to be authenticated"); /// /// app.get("/foxx", function { /// // Do something diff --git a/js/server/modules/org/arangodb/foxx/template_middleware.js b/js/server/modules/org/arangodb/foxx/template_middleware.js index 4b0053d7e2..ea702e1fb6 100644 --- a/js/server/modules/org/arangodb/foxx/template_middleware.js +++ b/js/server/modules/org/arangodb/foxx/template_middleware.js @@ -31,7 +31,7 @@ var db = require("org/arangodb").db, _ = require("underscore"); //////////////////////////////////////////////////////////////////////////////// -/// @startDocuBlock JSF_foxx_TemplateMiddleware_initializer +/// @start Docu Block JSF_foxx_TemplateMiddleware_initializer /// /// Initialize with the name of a collection or a collection and optionally /// a set of helper functions. @@ -48,7 +48,7 @@ var db = require("org/arangodb").db, /// /// app.before(templateMiddleware); /// ``` -/// @endDocuBlock +/// @end Docu Block //////////////////////////////////////////////////////////////////////////////// function TemplateMiddleware(templateCollection, helper) { @@ -59,7 +59,7 @@ function TemplateMiddleware(templateCollection, helper) { responseFunctions = { //////////////////////////////////////////////////////////////////////////////// -/// @startDocuBlock JSF_foxx_TemplateMiddleware_response_render +/// @start Docu Block JSF_foxx_TemplateMiddleware_response_render /// /// `response.render(templatePath, data)` /// @@ -74,7 +74,7 @@ function TemplateMiddleware(templateCollection, helper) { /// ```js /// response.render("high/way", {username: 'Application'}) /// ``` -/// @endDocuBlock +/// @end Docu Block //////////////////////////////////////////////////////////////////////////////// render: function (templatePath, data) { From 527120a3ea5364f00bf603d444ac1fab5e449205 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Tue, 18 Aug 2015 16:36:13 +0200 Subject: [PATCH 22/29] Removed outdated documentation, has been replased by a newer version earlier --- .../Books/Users/Foxx/Develop/Sessions.mdpp | 3 -- .../modules/org/arangodb/foxx/controller.js | 53 ++----------------- 2 files changed, 3 insertions(+), 53 deletions(-) diff --git a/Documentation/Books/Users/Foxx/Develop/Sessions.mdpp b/Documentation/Books/Users/Foxx/Develop/Sessions.mdpp index 9b98c09917..cd540bc6b8 100644 --- a/Documentation/Books/Users/Foxx/Develop/Sessions.mdpp +++ b/Documentation/Books/Users/Foxx/Develop/Sessions.mdpp @@ -3,7 +3,6 @@ Foxx provides some convenience methods to make working with sessions easier. !SUBSECTION Activate sessions -@startDocuBlock JSF_foxx_controller_activateSessions Enables session features for the controller. @@ -102,5 +101,3 @@ When using cookie sessions, this function will clear the session cookie (if *aut * *method* (optional): HTTP method to handle. Default: `"post"`. * *before* (optional): function to execute before the session is destroyed. Receives the same arguments as a regular route handler. * *after* (optional): function to execute after the session is destroyed. Receives the same arguments as a regular route handler. Default: a function that sends a *{"message": "logged out"}* JSON response. - -@startDocuBlock JSF_foxx_controller_destroySession diff --git a/js/server/modules/org/arangodb/foxx/controller.js b/js/server/modules/org/arangodb/foxx/controller.js index b0efd3f083..d240f01b43 100644 --- a/js/server/modules/org/arangodb/foxx/controller.js +++ b/js/server/modules/org/arangodb/foxx/controller.js @@ -232,31 +232,9 @@ var sessionControllerProps = { }, //////////////////////////////////////////////////////////////////////////////// -/// @startDocuBlock JSF_foxx_controller_destroySession -/// -/// `FoxxController#destroySession(path, opts)` -/// -/// This adds a path to your app for the destroySession functionality. -/// You can customize it with custom *before* and *after* function: -/// *before* is a function that you can define to do something before -/// the session is destroyed. -/// *after* is a function that you can define to do something after the -/// session is destroyed. This defaults to a function that returns a -/// JSON object with *message* set to "logged out". -/// Both *before* and *after* should take request and result as arguments. -/// If you only want to provide an *after* function, you can pass the -/// function directly instead of an object. -/// -/// @EXAMPLES -/// -/// ```js -/// app.destroySession('/logout', function (req, res) { -/// res.json({"message": "Bye, Bye"}); -/// }); -/// ``` -/// -/// @endDocuBlock +/// @brief defines a route to logout/destroy the session //////////////////////////////////////////////////////////////////////////////// + destroySession(route, opts) { var method = opts.method; if (typeof method === 'string') { @@ -755,32 +733,7 @@ class Controller { } //////////////////////////////////////////////////////////////////////////////// -/// @startDocuBlock JSF_foxx_controller_activateSessions -/// -/// `Controller.activateSessions(opts)` -/// -/// To activate sessions for this controller, call this function before defining any routes. -/// In the `opts` object you can set the following keys: -/// -/// * *type*: Currently we only support *cookie*, but this will change in the future. Defaults to *"cookie"*. -/// * *cookieName*: A string used as the name of the cookie. Defaults to *"sid"*. -/// * *cookieSecret*: A secret string used to sign the cookie (as "*cookieName*_sig"). Optional. -/// * *autoCreateSession*: Whether to always create a session if none exists. Defaults to *true*. -/// * *sessionStorage*: Mount path of the app to use for sessions. Defaults to */_system/sessions* -/// -/// -/// @EXAMPLES -/// -/// ```js -/// app.activateSessions({ -/// type: "cookie", -/// cookieName: "my_cookie", -/// autoCreateSession: true, -/// sessionStorage: "/my-sessions" -/// }); -/// ``` -/// -/// @endDocuBlock +/// @brief activate sessions with the giveon options for this controller //////////////////////////////////////////////////////////////////////////////// activateSessions(opts) { From 8992b99ec5859393e8d2ab3b12ebc6912955d852 Mon Sep 17 00:00:00 2001 From: Willi Goesgens Date: Tue, 18 Aug 2015 17:02:28 +0200 Subject: [PATCH 23/29] add possibility to skip benchmark tests --- js/server/modules/org/arangodb/testing.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/js/server/modules/org/arangodb/testing.js b/js/server/modules/org/arangodb/testing.js index 24fc1281ea..390503841a 100644 --- a/js/server/modules/org/arangodb/testing.js +++ b/js/server/modules/org/arangodb/testing.js @@ -57,6 +57,7 @@ var optionsDocumentation = [ ' - `skipGeo`: if set to true the geo index tests are skipped', ' - `skipGraph`: if set to true the Graph tests are skipped', ' - `skipAql`: if set to true the AQL tests are skipped', + ' - `skipArangoB`: if set to true benchmark tests are skipped', ' - `skipRanges`: if set to true the ranges tests are skipped', ' - `skipTimeCritical`: if set to true, time critical tests will be skipped.', ' - `skipMemoryIntense`: tests using lots of resources will be skippet.', @@ -122,6 +123,7 @@ var optionsDefaults = { "cluster": false, "skipTimeCritical": false, "skipMemoryIntense": false, "skipAql": false, + "skipArangoB": false, "skipRanges": false, "skipLogAnalysis": false, "username": "root", @@ -1866,6 +1868,10 @@ var benchTodo = [ ]; testFuncs.arangob = function (options) { + if (options.skipArangoB === true) { + print("skipping Benchmark tests!"); + return {}; + } print("arangob tests..."); var instanceInfo = startInstance("tcp",options, [], "arangob"); if (instanceInfo === false) { From 8677da48b1cbe110ec5747de7296e5392e794c19 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Tue, 18 Aug 2015 18:08:20 +0200 Subject: [PATCH 24/29] replication API enhancements, not yet ready --- arangod/Replication/ContinuousSyncer.cpp | 2 + .../RestHandler/RestReplicationHandler.cpp | 76 ++++++++ arangod/RestHandler/RestReplicationHandler.h | 7 + arangod/VocBase/replication-applier.cpp | 8 +- arangod/VocBase/replication-dump.cpp | 168 +++++++++++++++++- arangod/VocBase/replication-dump.h | 8 + arangosh/V8Client/arangosh.cpp | 6 +- lib/Utilities/ShellImplementation.cpp | 2 +- 8 files changed, 264 insertions(+), 13 deletions(-) diff --git a/arangod/Replication/ContinuousSyncer.cpp b/arangod/Replication/ContinuousSyncer.cpp index d86a547e7f..857f4181d1 100644 --- a/arangod/Replication/ContinuousSyncer.cpp +++ b/arangod/Replication/ContinuousSyncer.cpp @@ -836,6 +836,8 @@ int ContinuousSyncer::runContinuousSync (string& errorMsg) { return TRI_ERROR_REPLICATION_NO_START_TICK; } + // TODO: get the applier into a sensible start state... + // run in a loop. the loop is terminated when the applier is stopped or an // error occurs while (true) { diff --git a/arangod/RestHandler/RestReplicationHandler.cpp b/arangod/RestHandler/RestReplicationHandler.cpp index ece3b1f8be..012aff4056 100644 --- a/arangod/RestHandler/RestReplicationHandler.cpp +++ b/arangod/RestHandler/RestReplicationHandler.cpp @@ -125,6 +125,12 @@ Handler::status_t RestReplicationHandler::execute () { } handleCommandLoggerFollow(); } + else if (command == "determine-open-transactions") { + if (type != HttpRequest::HTTP_REQUEST_GET) { + goto BAD_CALL; + } + handleCommandDetermineOpenTransactions(); + } else if (command == "batch") { if (ServerState::instance()->isCoordinator()) { @@ -1190,6 +1196,76 @@ void RestReplicationHandler::handleCommandLoggerFollow () { } } +void RestReplicationHandler::handleCommandDetermineOpenTransactions () { + // determine start and end tick + triagens::wal::LogfileManagerState state = triagens::wal::LogfileManager::instance()->state(); + TRI_voc_tick_t tickStart = 0; + TRI_voc_tick_t tickEnd = state.lastDataTick; + + bool found; + char const* value; + + value = _request->value("from", found); + if (found) { + tickStart = static_cast(StringUtils::uint64(value)); + } + + // determine end tick for dump + value = _request->value("to", found); + if (found) { + tickEnd = static_cast(StringUtils::uint64(value)); + } + + if (found && (tickStart > tickEnd || tickEnd == 0)) { + generateError(HttpResponse::BAD, + TRI_ERROR_HTTP_BAD_PARAMETER, + "invalid from/to values"); + return; + } + + int res = TRI_ERROR_NO_ERROR; + + try { + // initialize the dump container + TRI_replication_dump_t dump(_vocbase, (size_t) determineChunkSize(), false); + + // and dump + res = TRI_DetermineOpenTransactionsReplication(&dump, tickStart, tickEnd); + + if (res == TRI_ERROR_NO_ERROR) { + // generate the result + size_t const length = TRI_LengthStringBuffer(dump._buffer); + + if (length == 0) { + _response = createResponse(HttpResponse::NO_CONTENT); + } + else { + _response = createResponse(HttpResponse::OK); + } + + _response->setContentType("application/x-arango-dump; charset=utf-8"); + + if (length > 0) { + // transfer ownership of the buffer contents + _response->body().set(dump._buffer); + + // to avoid double freeing + TRI_StealStringBuffer(dump._buffer); + } + } + } + catch (triagens::basics::Exception const& ex) { + res = ex.code(); + } + catch (...) { + res = TRI_ERROR_INTERNAL; + } + + if (res != TRI_ERROR_NO_ERROR) { + generateError(HttpResponse::SERVER_ERROR, res); + } +} + //////////////////////////////////////////////////////////////////////////////// /// @startDocuBlock JSF_put_api_replication_inventory /// @brief Returns an overview of collections and their indexes diff --git a/arangod/RestHandler/RestReplicationHandler.h b/arangod/RestHandler/RestReplicationHandler.h index 80599ba953..84ae7bb680 100644 --- a/arangod/RestHandler/RestReplicationHandler.h +++ b/arangod/RestHandler/RestReplicationHandler.h @@ -155,6 +155,13 @@ namespace triagens { void handleCommandLoggerFollow (); +//////////////////////////////////////////////////////////////////////////////// +/// @brief handle the command to determine the transactions that were open +/// at a certain point in time +//////////////////////////////////////////////////////////////////////////////// + + void handleCommandDetermineOpenTransactions (); + //////////////////////////////////////////////////////////////////////////////// /// @brief handle a batch command //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/VocBase/replication-applier.cpp b/arangod/VocBase/replication-applier.cpp index 1d8e00acf4..b293cd9c3a 100644 --- a/arangod/VocBase/replication-applier.cpp +++ b/arangod/VocBase/replication-applier.cpp @@ -202,11 +202,10 @@ static TRI_json_t* JsonConfiguration (TRI_replication_applier_configuration_t co static int LoadConfiguration (TRI_vocbase_t* vocbase, TRI_replication_applier_configuration_t* config) { - char* filename; - TRI_DestroyConfigurationReplicationApplier(config); TRI_InitConfigurationReplicationApplier(config); - filename = GetConfigurationFilename(vocbase); + + char* filename = GetConfigurationFilename(vocbase); if (! TRI_ExistsFile(filename)) { TRI_FreeString(TRI_CORE_MEM_ZONE, filename); @@ -431,7 +430,6 @@ static TRI_json_t* JsonApplyState (TRI_replication_applier_state_t const* state) static int SetError (TRI_replication_applier_t* applier, int errorCode, char const* msg) { - TRI_replication_applier_state_t* state; char const* realMsg; if (msg == nullptr || strlen(msg) == 0) { @@ -446,7 +444,7 @@ static int SetError (TRI_replication_applier_t* applier, LOG_ERROR("replication applier error for database '%s': %s", applier->_databaseName, realMsg); } - state = &applier->_state; + TRI_replication_applier_state_t* state = &applier->_state; state->_lastError._code = errorCode; TRI_GetTimeStampReplication(state->_lastError._time, sizeof(state->_lastError._time) - 1); diff --git a/arangod/VocBase/replication-dump.cpp b/arangod/VocBase/replication-dump.cpp index 390bdc2d95..55dd5d8308 100644 --- a/arangod/VocBase/replication-dump.cpp +++ b/arangod/VocBase/replication-dump.cpp @@ -841,6 +841,16 @@ static inline bool MustReplicateWalMarkerType (TRI_df_marker_t const* marker) { marker->_type == TRI_WAL_MARKER_DROP_INDEX); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not a marker belongs to a transaction +//////////////////////////////////////////////////////////////////////////////// + +static inline bool IsTransactionWalMarkerType (TRI_df_marker_t const* marker) { + return (marker->_type == TRI_WAL_MARKER_BEGIN_TRANSACTION || + marker->_type == TRI_WAL_MARKER_COMMIT_TRANSACTION || + marker->_type == TRI_WAL_MARKER_ABORT_TRANSACTION); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief translate a marker type to a replication type //////////////////////////////////////////////////////////////////////////////// @@ -1060,6 +1070,25 @@ static TRI_voc_tick_t GetCollectionFromWalMarker (TRI_df_marker_t const* marker) } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not a marker belongs to a transaction +//////////////////////////////////////////////////////////////////////////////// + +static bool IsTransactionWalMarker (TRI_replication_dump_t* dump, + TRI_df_marker_t const* marker) { + // first check the marker type + if (! IsTransactionWalMarkerType(marker)) { + return false; + } + + // then check if the marker belongs to the "correct" database + if (dump->_vocbase->_id != GetDatabaseFromWalMarker(marker)) { + return false; + } + + return true; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not a marker is replicated //////////////////////////////////////////////////////////////////////////////// @@ -1365,7 +1394,6 @@ int TRI_DumpLogReplication (TRI_replication_dump_t* dump, // ask the logfile manager which datafiles qualify bool fromTickIncluded = false; std::vector logfiles = triagens::wal::LogfileManager::instance()->getLogfilesForTickRange(tickMin, tickMax, fromTickIncluded); - size_t const n = logfiles.size(); // setup some iteration state int res = TRI_ERROR_NO_ERROR; @@ -1378,9 +1406,11 @@ int TRI_DumpLogReplication (TRI_replication_dump_t* dump, } try { - bool first = true; + bool first = true; // iterate over the datafiles found + size_t const n = logfiles.size(); + for (size_t i = 0; i < n; ++i) { triagens::wal::Logfile* logfile = logfiles[i]; @@ -1416,7 +1446,6 @@ int TRI_DumpLogReplication (TRI_replication_dump_t* dump, } if (! MustReplicateWalMarker(dump, marker)) { - // check if we can abort searching continue; } @@ -1484,6 +1513,139 @@ int TRI_DumpLogReplication (TRI_replication_dump_t* dump, return res; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief determine the transactions that were open at a given point in time +//////////////////////////////////////////////////////////////////////////////// + +int TRI_DetermineOpenTransactionsReplication (TRI_replication_dump_t* dump, + TRI_voc_tick_t tickMin, + TRI_voc_tick_t tickMax) { + + LOG_TRACE("determining transactions, tick range %llu - %llu", + (unsigned long long) tickMin, + (unsigned long long) tickMax); + + std::unordered_map transactions; + + // ask the logfile manager which datafiles qualify + bool fromTickIncluded = false; + std::vector logfiles = triagens::wal::LogfileManager::instance()->getLogfilesForTickRange(tickMin, tickMax, fromTickIncluded); + + // setup some iteration state + TRI_voc_tick_t lastFoundTick = 0; + int res = TRI_ERROR_NO_ERROR; + + // LOG_INFO("found logfiles: %d", (int) logfiles.size()); + + try { + // iterate over the datafiles found + size_t const n = logfiles.size(); + for (size_t i = 0; i < n; ++i) { + triagens::wal::Logfile* logfile = logfiles[i]; + + char const* ptr; + char const* end; + triagens::wal::LogfileManager::instance()->getActiveLogfileRegion(logfile, ptr, end); + + // LOG_INFO("scanning logfile %d", (int) i); + while (ptr < end) { + TRI_df_marker_t const* marker = reinterpret_cast(ptr); + + if (marker->_size == 0 || marker->_type <= TRI_MARKER_MIN) { + // end of datafile + break; + } + + ptr += TRI_DF_ALIGN_BLOCK(marker->_size); + + // get the marker's tick and check whether we should include it + TRI_voc_tick_t foundTick = marker->_tick; + + if (foundTick <= tickMin) { + // marker too old + continue; + } + + if (foundTick > tickMax) { + // marker too new + // LOG_INFO("marker too new. aborting logfile %d", (int) i); + break; + } + + if (! IsTransactionWalMarker(dump, marker)) { + continue; + } + + // LOG_INFO("found transaction marker"); + + if (marker->_type == TRI_WAL_MARKER_BEGIN_TRANSACTION) { + auto m = reinterpret_cast(marker); + transactions.emplace(m->_transactionId, foundTick); + // LOG_INFO("found begin: %llu", m->_transactionId); + } + else if (marker->_type == TRI_WAL_MARKER_COMMIT_TRANSACTION) { + auto m = reinterpret_cast(marker); + transactions.erase(m->_transactionId); + // LOG_INFO("found commit: %llu", m->_transactionId); + } + else if (marker->_type == TRI_WAL_MARKER_ABORT_TRANSACTION) { + auto m = reinterpret_cast(marker); + transactions.erase(m->_transactionId); + // LOG_INFO("found abort: %llu", m->_transactionId); + } + + // note the last tick we processed + if (foundTick > lastFoundTick) { + lastFoundTick = foundTick; + } + } + } + + // LOG_INFO("found transactions: %d", (int) transactions.size()); + // LOG_INFO("last tick: %llu", lastFoundTick); + + if (transactions.empty()) { + TRI_AppendStringStringBuffer(dump->_buffer, "[]"); + } + else { + bool first = true; + TRI_AppendStringStringBuffer(dump->_buffer, "[\""); + + for (auto const& it : transactions) { + if (it.second < lastFoundTick) { + lastFoundTick = it.second; + } + + if (first) { + first = false; + } + else { + TRI_AppendStringStringBuffer(dump->_buffer, "\",\""); + } + + TRI_AppendUInt64StringBuffer(dump->_buffer, it.first); + } + + TRI_AppendStringStringBuffer(dump->_buffer, "\"]"); + } + + dump->_fromTickIncluded = fromTickIncluded; + dump->_lastFoundTick = lastFoundTick; + // LOG_INFO("last tick2: %llu", lastFoundTick); + } + catch (triagens::basics::Exception const& ex) { + res = ex.code(); + } + catch (...) { + res = TRI_ERROR_INTERNAL; + } + + // always return the logfiles we have used + triagens::wal::LogfileManager::instance()->returnLogfiles(logfiles); + + return res; +} + // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/arangod/VocBase/replication-dump.h b/arangod/VocBase/replication-dump.h index 737b75cdb3..6e90caddcd 100644 --- a/arangod/VocBase/replication-dump.h +++ b/arangod/VocBase/replication-dump.h @@ -132,6 +132,14 @@ int TRI_DumpLogReplication (TRI_replication_dump_t*, TRI_voc_tick_t, bool); +//////////////////////////////////////////////////////////////////////////////// +/// @brief determine the transactions that were open at a given point in time +//////////////////////////////////////////////////////////////////////////////// + +int TRI_DetermineOpenTransactionsReplication (TRI_replication_dump_t*, + TRI_voc_tick_t, + TRI_voc_tick_t); + #endif // ----------------------------------------------------------------------------- diff --git a/arangosh/V8Client/arangosh.cpp b/arangosh/V8Client/arangosh.cpp index c0a49c8be7..73c2afc686 100644 --- a/arangosh/V8Client/arangosh.cpp +++ b/arangosh/V8Client/arangosh.cpp @@ -1587,9 +1587,7 @@ static void RunShell (v8::Isolate* isolate, v8::Handle context, boo #endif bool eof; - string input - = console.prompt(promptError ? badPrompt.c_str() : goodPrompt.c_str(), - "arangosh", eof); + string input = console.prompt(promptError ? badPrompt.c_str() : goodPrompt.c_str(), "arangosh", eof); if (eof) { break; @@ -1951,7 +1949,7 @@ static void arangoshExitFunction (int exitCode, void* data) { #endif -static bool printHelo(bool useServer, bool promptError) { +static bool printHelo (bool useServer, bool promptError) { // ............................................................................. // banner // ............................................................................. diff --git a/lib/Utilities/ShellImplementation.cpp b/lib/Utilities/ShellImplementation.cpp index 08379b0794..9bb3465769 100644 --- a/lib/Utilities/ShellImplementation.cpp +++ b/lib/Utilities/ShellImplementation.cpp @@ -99,7 +99,7 @@ string ShellImplementation::prompt (const string& prompt, while (true) { - // calling concrete implmentation of the shell + // calling concrete implementation of the shell line = getLine(p, eof); p = dotdot; From edd1e90511ad3a5fe87be6bd4a8fa164c6d5eaf1 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Tue, 18 Aug 2015 18:10:27 +0200 Subject: [PATCH 25/29] clean up shell implementation code --- arangosh/V8Client/arangosh.cpp | 2 +- lib/CMakeLists.txt | 4 +-- lib/Makefile.files | 5 +--- lib/Utilities/DummyShell.h | 16 +++++++++++ lib/Utilities/LinenoiseShell.h | 16 +++++++++++ lib/Utilities/ReadlineShell.cpp | 44 ++++++++++++++--------------- lib/Utilities/ReadlineShell.h | 16 +++++++++++ lib/Utilities/ShellImplFactory.cpp | 14 +++++++-- lib/Utilities/ShellImplementation.h | 14 ++++++++- lib/V8/V8LineEditor.cpp | 26 ++++++++++++++--- lib/V8/V8LineEditor.h | 16 +++++------ 11 files changed, 128 insertions(+), 45 deletions(-) diff --git a/arangosh/V8Client/arangosh.cpp b/arangosh/V8Client/arangosh.cpp index 73c2afc686..a742ae95d8 100644 --- a/arangosh/V8Client/arangosh.cpp +++ b/arangosh/V8Client/arangosh.cpp @@ -1543,7 +1543,7 @@ static void RunShell (v8::Isolate* isolate, v8::Handle context, boo #else - if (BaseClient.colors()) { + if (BaseClient.colors() && console.supportsColors()) { #ifdef TRI_HAVE_LINENOISE diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 040b405e70..a8b778aee6 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -118,9 +118,9 @@ add_library( Rest/SslInterface.cpp Rest/Version.cpp Statistics/statistics.cpp - Utilities/ScriptLoader.cpp - Utilities/ShellImplementation.cpp + Utilities/DummyShell.cpp Utilities/LineEditor.cpp + Utilities/ScriptLoader.cpp Utilities/ShellImplementation.cpp Utilities/ShellImplFactory.cpp Zip/ioapi.cpp diff --git a/lib/Makefile.files b/lib/Makefile.files index 9ff5f0b6c6..0fb44fd40c 100644 --- a/lib/Makefile.files +++ b/lib/Makefile.files @@ -91,6 +91,7 @@ lib_libarango_a_SOURCES = \ lib/Rest/SslInterface.cpp \ lib/Rest/Version.cpp \ lib/Statistics/statistics.cpp \ + lib/Utilities/DummyShell.cpp \ lib/Utilities/LineEditor.cpp \ lib/Utilities/ScriptLoader.cpp \ lib/Utilities/ShellImplFactory.cpp \ @@ -104,10 +105,6 @@ if ENABLE_READLINE lib_libarango_a_SOURCES += \ lib/Utilities/ReadlineShell.cpp -else - -lib_libarango_a_SOURCES += \ - lib/Utilities/DummyShell.cpp endif ################################################################################ diff --git a/lib/Utilities/DummyShell.h b/lib/Utilities/DummyShell.h index 571acbe288..598e5b2774 100644 --- a/lib/Utilities/DummyShell.h +++ b/lib/Utilities/DummyShell.h @@ -107,6 +107,22 @@ namespace arangodb { //////////////////////////////////////////////////////////////////////////////// std::string getLine (const std::string& prompt, bool& eof) override final; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the shell implementation supports colors +//////////////////////////////////////////////////////////////////////////////// + + bool supportsColors () override final { + return false; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the shell supports a CTRL-C handler +//////////////////////////////////////////////////////////////////////////////// + + bool supportsCtrlCHandler () override final { + return false; + } }; } diff --git a/lib/Utilities/LinenoiseShell.h b/lib/Utilities/LinenoiseShell.h index c102bb37c8..3d687de3f4 100644 --- a/lib/Utilities/LinenoiseShell.h +++ b/lib/Utilities/LinenoiseShell.h @@ -107,6 +107,22 @@ namespace arangodb { //////////////////////////////////////////////////////////////////////////////// std::string getLine (const std::string& prompt, bool& eof) override final; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the shell implementation supports colors +//////////////////////////////////////////////////////////////////////////////// + + bool supportsColors () override final { + return false; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the shell supports a CTRL-C handler +//////////////////////////////////////////////////////////////////////////////// + + bool supportsCtrlCHandler () override final { + return false; + } }; } #endif diff --git a/lib/Utilities/ReadlineShell.cpp b/lib/Utilities/ReadlineShell.cpp index aebb0268c1..17c009bf96 100644 --- a/lib/Utilities/ReadlineShell.cpp +++ b/lib/Utilities/ReadlineShell.cpp @@ -122,34 +122,32 @@ static void ReadlineInputCompleted (char* value) { auto instance = ReadlineShell::instance(); - if (instance == nullptr) { - return; - } + if (instance != nullptr) { + if (instance->getLoopState() == 2) { - if (instance->getLoopState() == 2) { + // CTRL-C received + rl_done = 1; - // CTRL-C received - rl_done = 1; + // replace current input with nothing + rl_replace_line("", 0); - // replace current input with nothing - rl_replace_line("", 0); - - if (value != nullptr) { - // avoid memleak - TRI_SystemFree(value); + instance->setLastInput(""); + } + else if (value == nullptr) { + rl_done = 1; + rl_replace_line("", 0); + instance->setLoopState(3); + instance->setLastInput(""); + } + else { + instance->setLoopState(1); + instance->setLastInput(value == 0 ? "" : value); } - - instance->setLastInput(""); } - else if (value == nullptr) { - rl_done = 1; - rl_replace_line("", 0); - instance->setLoopState(3); - instance->setLastInput(""); - } - else { - instance->setLoopState(1); - instance->setLastInput(value == 0 ? "" : value); + + if (value != nullptr) { + // avoid memleak + TRI_SystemFree(value); } } diff --git a/lib/Utilities/ReadlineShell.h b/lib/Utilities/ReadlineShell.h index 6075fca224..b51020ee4f 100644 --- a/lib/Utilities/ReadlineShell.h +++ b/lib/Utilities/ReadlineShell.h @@ -125,6 +125,22 @@ namespace arangodb { void signal () override final; +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the shell implementation supports colors +//////////////////////////////////////////////////////////////////////////////// + + bool supportsColors () override final { + return true; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the shell supports a CTRL-C handler +//////////////////////////////////////////////////////////////////////////////// + + bool supportsCtrlCHandler () override final { + return true; + } + // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- diff --git a/lib/Utilities/ShellImplFactory.cpp b/lib/Utilities/ShellImplFactory.cpp index 2946c80d0b..9a67ce2964 100644 --- a/lib/Utilities/ShellImplFactory.cpp +++ b/lib/Utilities/ShellImplFactory.cpp @@ -35,9 +35,8 @@ #include "LinenoiseShell.h" #elif defined TRI_HAVE_READLINE #include "ReadlineShell.h" -#else -#include "DummyShell.h" #endif +#include "DummyShell.h" using namespace triagens; using namespace arangodb; @@ -50,12 +49,19 @@ using namespace arangodb; // --SECTION-- static public methods // ----------------------------------------------------------------------------- +#include //////////////////////////////////////////////////////////////////////////////// /// @brief creates a shell //////////////////////////////////////////////////////////////////////////////// ShellImplementation* ShellImplFactory::buildShell (std::string const& history, Completer* completer) { + if (! isatty(STDIN_FILENO)) { + // no keyboard input. use low-level shell without fancy color codes + // and with proper pipe handling + return new DummyShell(history, completer); + } + #ifdef _WIN32 // under Windows the readline is not compilable return new LinenoiseShell(history, completer); @@ -74,6 +80,10 @@ ShellImplementation* ShellImplFactory::buildShell (std::string const& history, //////////////////////////////////////////////////////////////////////////////// bool ShellImplFactory::hasCtrlCHandler () { + if (! isatty(STDIN_FILENO)) { + return false; + } + #ifdef _WIN32 // under Windows the readline is not compilable return false; diff --git a/lib/Utilities/ShellImplementation.h b/lib/Utilities/ShellImplementation.h index 37ddcd191f..b80f73f362 100644 --- a/lib/Utilities/ShellImplementation.h +++ b/lib/Utilities/ShellImplementation.h @@ -102,7 +102,7 @@ namespace arangodb { // --SECTION-- virtual public methods // ----------------------------------------------------------------------------- - public: + public: //////////////////////////////////////////////////////////////////////////////// /// @brief handle a signal @@ -149,6 +149,18 @@ namespace arangodb { virtual std::string getLine (const std::string& prompt, bool& eof) = 0; +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the shell implementation supports colors +//////////////////////////////////////////////////////////////////////////////// + + virtual bool supportsColors () = 0; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the shell supports a CTRL-C handler +//////////////////////////////////////////////////////////////////////////////// + + virtual bool supportsCtrlCHandler () = 0; + // ----------------------------------------------------------------------------- // --SECTION-- protected variables // ----------------------------------------------------------------------------- diff --git a/lib/V8/V8LineEditor.cpp b/lib/V8/V8LineEditor.cpp index a3ba2c56d8..e33dcc8c6a 100644 --- a/lib/V8/V8LineEditor.cpp +++ b/lib/V8/V8LineEditor.cpp @@ -30,6 +30,7 @@ #include "Basics/logging.h" #include "Basics/StringUtils.h" #include "Basics/tri-strings.h" +#include "Utilities/ShellImplementation.h" #include "Utilities/ShellImplFactory.h" #include "V8/v8-utils.h" @@ -388,8 +389,6 @@ V8LineEditor::V8LineEditor (v8::Isolate* isolate, // register global instance TRI_ASSERT(_instance.load() == nullptr); _instance.store(this); - - setupCtrlCHandler(); } //////////////////////////////////////////////////////////////////////////////// @@ -403,7 +402,23 @@ V8LineEditor::~V8LineEditor () { } // ----------------------------------------------------------------------------- -// --SECTION-- static protected methods +// --SECTION-- public methods +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the shell implementation supports colors +//////////////////////////////////////////////////////////////////////////////// + +bool V8LineEditor::supportsColors () const { + if (_shellImpl == nullptr) { + return false; + } + + return _shellImpl->supportsColors(); +} + +// ----------------------------------------------------------------------------- +// --SECTION-- protected methods // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -412,7 +427,8 @@ V8LineEditor::~V8LineEditor () { void V8LineEditor::setupCtrlCHandler () { #ifndef _WIN32 - if (ShellImplFactory::hasCtrlCHandler()) { + if (_shellImpl != nullptr && + _shellImpl->supportsCtrlCHandler()) { struct sigaction sa; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); @@ -433,6 +449,8 @@ void V8LineEditor::setupCtrlCHandler () { void V8LineEditor::initializeShell () { _shellImpl = ShellImplFactory::buildShell(_history, &_completer); + + setupCtrlCHandler(); } // ----------------------------------------------------------------------------- diff --git a/lib/V8/V8LineEditor.h b/lib/V8/V8LineEditor.h index 4f17e9a80c..7912a7bd3a 100644 --- a/lib/V8/V8LineEditor.h +++ b/lib/V8/V8LineEditor.h @@ -161,8 +161,14 @@ namespace arangodb { return _instance.load(); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the shell implementation supports colors +//////////////////////////////////////////////////////////////////////////////// + + bool supportsColors () const; + // ----------------------------------------------------------------------------- -// --SECTION-- static protected methods +// --SECTION-- protected methods // ----------------------------------------------------------------------------- protected: @@ -171,13 +177,7 @@ namespace arangodb { /// @brief setup a signal handler for CTRL-C //////////////////////////////////////////////////////////////////////////////// - static void setupCtrlCHandler (); - -// ----------------------------------------------------------------------------- -// --SECTION-- protected methods -// ----------------------------------------------------------------------------- - - protected: + void setupCtrlCHandler (); //////////////////////////////////////////////////////////////////////////////// /// @brief creates a concrete Shell with the correct completer From bc7e0f7bbdae6d2ddb61f5b1b75aa0ba33fc90cf Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Wed, 19 Aug 2015 09:25:46 +0200 Subject: [PATCH 26/29] issue #1445: Object literal simplificatin does not support pseudo-variables NEW and OLD --- arangod/Aql/Scopes.cpp | 42 ++ arangod/Aql/Scopes.h | 14 + arangod/Aql/grammar.cpp | 702 +++++++++++------------ arangod/Aql/grammar.h | 12 +- arangod/Aql/grammar.y | 28 +- js/server/tests/aql-modify-noncluster.js | 104 ++++ 6 files changed, 519 insertions(+), 383 deletions(-) diff --git a/arangod/Aql/Scopes.cpp b/arangod/Aql/Scopes.cpp index 4eb05795ce..abc01abb51 100644 --- a/arangod/Aql/Scopes.cpp +++ b/arangod/Aql/Scopes.cpp @@ -137,6 +137,29 @@ Variable const* Scope::getVariable (std::string const& name) const { return (*it).second; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a variable, allowing usage of special pseudo vars such +/// as OLD and NEW +//////////////////////////////////////////////////////////////////////////////// + +Variable const* Scope::getVariable (char const* name, + bool allowSpecial) const { + auto variable = getVariable(name); + + if (variable == nullptr && allowSpecial) { + // variable does not exist + // now try variable aliases OLD (= $OLD) and NEW (= $NEW) + if (strcmp(name, "OLD") == 0) { + variable = getVariable(Variable::NAME_OLD); + } + else if (strcmp(name, "NEW") == 0) { + variable = getVariable(Variable::NAME_NEW); + } + } + + return variable; +} + // ----------------------------------------------------------------------------- // --SECTION-- constructors / destructors // ----------------------------------------------------------------------------- @@ -268,6 +291,25 @@ Variable const* Scopes::getVariable (char const* name) const { return nullptr; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a variable by name - this respects the current scopes +//////////////////////////////////////////////////////////////////////////////// + +Variable const* Scopes::getVariable (char const* name, + bool allowSpecial) const { + TRI_ASSERT(! _activeScopes.empty()); + + for (auto it = _activeScopes.rbegin(); it != _activeScopes.rend(); ++it) { + auto variable = (*it)->getVariable(name, allowSpecial); + + if (variable != nullptr) { + return variable; + } + } + + return nullptr; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief get the $CURRENT variable //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Scopes.h b/arangod/Aql/Scopes.h index 41fdba8487..9d4b97f5bd 100644 --- a/arangod/Aql/Scopes.h +++ b/arangod/Aql/Scopes.h @@ -127,6 +127,13 @@ namespace triagens { Variable const* getVariable (std::string const&) const; +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a variable, allowing usage of special pseudo vars such +/// as OLD and NEW +//////////////////////////////////////////////////////////////////////////////// + + Variable const* getVariable (char const*, bool) const; + // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- @@ -242,6 +249,13 @@ namespace triagens { Variable const* getVariable (char const*) const; +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a variable by name - this respects the current scopes +/// this also allows using special pseudo vars such as OLD and NEW +//////////////////////////////////////////////////////////////////////////////// + + Variable const* getVariable (char const*, bool) const; + //////////////////////////////////////////////////////////////////////////////// /// @brief get the $CURRENT variable //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/grammar.cpp b/arangod/Aql/grammar.cpp index a70274e5c5..03bd70a914 100644 --- a/arangod/Aql/grammar.cpp +++ b/arangod/Aql/grammar.cpp @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ +/* A Bison parser, made by GNU Bison 3.0.2. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.0.4" +#define YYBISON_VERSION "3.0.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -176,7 +176,7 @@ extern int Aqldebug; /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - +typedef union YYSTYPE YYSTYPE; union YYSTYPE { #line 17 "arangod/Aql/grammar.y" /* yacc.c:355 */ @@ -188,8 +188,6 @@ union YYSTYPE #line 190 "arangod/Aql/grammar.cpp" /* yacc.c:355 */ }; - -typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif @@ -249,7 +247,7 @@ void Aqlerror (YYLTYPE* locp, #define scanner parser->scanner() -#line 253 "arangod/Aql/grammar.cpp" /* yacc.c:358 */ +#line 251 "arangod/Aql/grammar.cpp" /* yacc.c:358 */ #ifdef short # undef short @@ -567,10 +565,10 @@ static const yytype_uint16 yyrline[] = 854, 860, 862, 867, 870, 870, 889, 892, 898, 901, 907, 907, 916, 918, 923, 926, 932, 935, 949, 949, 958, 960, 965, 967, 972, 986, 990, 1003, 1010, 1013, - 1019, 1022, 1028, 1031, 1034, 1040, 1043, 1049, 1091, 1094, - 1097, 1104, 1114, 1114, 1130, 1145, 1159, 1173, 1173, 1217, - 1220, 1226, 1233, 1243, 1246, 1249, 1252, 1255, 1261, 1268, - 1275, 1289, 1295, 1302, 1311 + 1019, 1022, 1028, 1031, 1034, 1040, 1043, 1049, 1081, 1084, + 1087, 1094, 1104, 1104, 1120, 1135, 1149, 1163, 1163, 1207, + 1210, 1216, 1223, 1233, 1236, 1239, 1242, 1245, 1251, 1258, + 1265, 1279, 1285, 1292, 1301 }; #endif @@ -1770,187 +1768,187 @@ yyreduce: switch (yyn) { case 2: -#line 202 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 202 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1777 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1775 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 3: -#line 204 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 204 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1784 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1782 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 4: -#line 206 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 206 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1791 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1789 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 5: -#line 208 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 208 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1798 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1796 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 6: -#line 210 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 210 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1805 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1803 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 7: -#line 212 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 212 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1812 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1810 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 8: -#line 217 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 217 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1819 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1817 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 9: -#line 219 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 219 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1826 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1824 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 10: -#line 224 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 224 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // still need to close the scope opened by the data-modification statement parser->ast()->scopes()->endNested(); } -#line 1835 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1833 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 11: -#line 228 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 228 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // the RETURN statement will close the scope opened by the data-modification statement } -#line 1843 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1841 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 12: -#line 234 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 234 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1850 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1848 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 13: -#line 236 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 236 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1857 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1855 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 14: -#line 241 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 241 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1864 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1862 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 15: -#line 243 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 243 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1871 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1869 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 16: -#line 245 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 245 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1878 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1876 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 17: -#line 247 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 247 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1885 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1883 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 18: -#line 249 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 249 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1892 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1890 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 19: -#line 251 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 251 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1899 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1897 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 20: -#line 256 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 256 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { parser->ast()->scopes()->start(triagens::aql::AQL_SCOPE_FOR); auto node = parser->ast()->createNodeFor((yyvsp[-2].strval), (yyvsp[0].node)); parser->ast()->addOperation(node); } -#line 1910 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1908 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 21: -#line 265 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 265 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // operand is a reference. can use it directly auto node = parser->ast()->createNodeFilter((yyvsp[0].node)); parser->ast()->addOperation(node); } -#line 1920 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1918 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 22: -#line 273 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 273 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1927 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1925 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 23: -#line 278 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 278 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1934 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1932 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 24: -#line 280 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 280 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 1941 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1939 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 25: -#line 285 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 285 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto node = parser->ast()->createNodeLet((yyvsp[-2].strval), (yyvsp[0].node), true); parser->ast()->addOperation(node); } -#line 1950 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1948 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 26: -#line 292 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 292 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! TRI_CaseEqualString((yyvsp[-2].strval), "COUNT")) { parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected qualifier '%s', expecting 'COUNT'", (yyvsp[-2].strval), yylloc.first_line, yylloc.first_column); @@ -1958,20 +1956,20 @@ yyreduce: (yyval.strval) = (yyvsp[0].strval); } -#line 1962 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1960 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 27: -#line 302 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 302 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto node = parser->ast()->createNodeArray(); parser->pushStack(node); } -#line 1971 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1969 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 28: -#line 305 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 305 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto list = static_cast(parser->popStack()); @@ -1980,11 +1978,11 @@ yyreduce: } (yyval.node) = list; } -#line 1984 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 1982 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 29: -#line 316 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 316 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto scopes = parser->ast()->scopes(); @@ -2001,11 +1999,11 @@ yyreduce: auto node = parser->ast()->createNodeCollectCount(parser->ast()->createNodeArray(), (yyvsp[-1].strval), (yyvsp[0].node)); parser->ast()->addOperation(node); } -#line 2005 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2003 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 30: -#line 332 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 332 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto scopes = parser->ast()->scopes(); @@ -2033,11 +2031,11 @@ yyreduce: auto node = parser->ast()->createNodeCollectCount((yyvsp[-2].node), (yyvsp[-1].strval), (yyvsp[0].node)); parser->ast()->addOperation(node); } -#line 2037 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2035 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 31: -#line 359 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 359 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto scopes = parser->ast()->scopes(); @@ -2065,11 +2063,11 @@ yyreduce: auto node = parser->ast()->createNodeCollect((yyvsp[-2].node), (yyvsp[-1].strval), nullptr, (yyvsp[0].node)); parser->ast()->addOperation(node); } -#line 2069 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2067 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 32: -#line 386 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 386 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto scopes = parser->ast()->scopes(); @@ -2102,11 +2100,11 @@ yyreduce: auto node = parser->ast()->createNodeCollect((yyvsp[-3].node), (yyvsp[-2].strval), (yyvsp[-1].node), (yyvsp[0].node)); parser->ast()->addOperation(node); } -#line 2106 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2104 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 33: -#line 418 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 418 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto scopes = parser->ast()->scopes(); @@ -2134,50 +2132,50 @@ yyreduce: auto node = parser->ast()->createNodeCollectExpression((yyvsp[-5].node), (yyvsp[-3].strval), (yyvsp[-1].node), (yyvsp[0].node)); parser->ast()->addOperation(node); } -#line 2138 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2136 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 34: -#line 448 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 448 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2145 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2143 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 35: -#line 450 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 450 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2152 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2150 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 36: -#line 455 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 455 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto node = parser->ast()->createNodeAssign((yyvsp[-2].strval), (yyvsp[0].node)); parser->pushArrayElement(node); } -#line 2161 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2159 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 37: -#line 462 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 462 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.strval) = nullptr; } -#line 2169 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2167 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 38: -#line 465 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 465 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.strval) = (yyvsp[0].strval); } -#line 2177 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2175 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 39: -#line 471 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 471 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! parser->ast()->scopes()->existsVariable((yyvsp[0].strval))) { parser->registerParseError(TRI_ERROR_QUERY_PARSE, "use of unknown variable '%s' for KEEP", (yyvsp[0].strval), yylloc.first_line, yylloc.first_column); @@ -2192,11 +2190,11 @@ yyreduce: node->setFlag(FLAG_KEEP_VARIABLENAME); parser->pushArrayElement(node); } -#line 2196 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2194 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 40: -#line 485 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 485 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! parser->ast()->scopes()->existsVariable((yyvsp[0].strval))) { parser->registerParseError(TRI_ERROR_QUERY_PARSE, "use of unknown variable '%s' for KEEP", (yyvsp[0].strval), yylloc.first_line, yylloc.first_column); @@ -2211,11 +2209,11 @@ yyreduce: node->setFlag(FLAG_KEEP_VARIABLENAME); parser->pushArrayElement(node); } -#line 2215 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2213 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 41: -#line 502 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 502 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! TRI_CaseEqualString((yyvsp[0].strval), "KEEP")) { parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected qualifier '%s', expecting 'KEEP'", (yyvsp[0].strval), yylloc.first_line, yylloc.first_column); @@ -2224,140 +2222,140 @@ yyreduce: auto node = parser->ast()->createNodeArray(); parser->pushStack(node); } -#line 2228 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2226 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 42: -#line 509 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 509 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto list = static_cast(parser->popStack()); (yyval.node) = list; } -#line 2237 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2235 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 43: -#line 516 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 516 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto node = parser->ast()->createNodeArray(); parser->pushStack(node); } -#line 2246 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2244 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 44: -#line 519 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 519 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto list = static_cast(parser->popStack()); auto node = parser->ast()->createNodeSort(list); parser->ast()->addOperation(node); } -#line 2256 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2254 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 45: -#line 527 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 527 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { parser->pushArrayElement((yyvsp[0].node)); } -#line 2264 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2262 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 46: -#line 530 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 530 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { parser->pushArrayElement((yyvsp[0].node)); } -#line 2272 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2270 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 47: -#line 536 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 536 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeSortElement((yyvsp[-1].node), (yyvsp[0].node)); } -#line 2280 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2278 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 48: -#line 542 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 542 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeValueBool(true); } -#line 2288 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2286 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 49: -#line 545 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 545 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeValueBool(true); } -#line 2296 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2294 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 50: -#line 548 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 548 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeValueBool(false); } -#line 2304 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2302 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 51: -#line 551 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 551 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2312 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2310 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 52: -#line 557 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 557 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto offset = parser->ast()->createNodeValueInt(0); auto node = parser->ast()->createNodeLimit(offset, (yyvsp[0].node)); parser->ast()->addOperation(node); } -#line 2322 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2320 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 53: -#line 562 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 562 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto node = parser->ast()->createNodeLimit((yyvsp[-2].node), (yyvsp[0].node)); parser->ast()->addOperation(node); } -#line 2331 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2329 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 54: -#line 569 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 569 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto node = parser->ast()->createNodeReturn((yyvsp[0].node)); parser->ast()->addOperation(node); parser->ast()->scopes()->endNested(); } -#line 2341 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2339 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 55: -#line 577 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 577 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2349 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2347 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 56: -#line 580 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 580 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2357 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2355 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 57: -#line 586 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 586 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! parser->configureWriteQuery(AQL_QUERY_REMOVE, (yyvsp[-1].node), (yyvsp[0].node))) { YYABORT; @@ -2366,11 +2364,11 @@ yyreduce: parser->ast()->addOperation(node); parser->setWriteNode(node); } -#line 2370 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2368 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 58: -#line 597 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 597 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! parser->configureWriteQuery(AQL_QUERY_INSERT, (yyvsp[-1].node), (yyvsp[0].node))) { YYABORT; @@ -2379,11 +2377,11 @@ yyreduce: parser->ast()->addOperation(node); parser->setWriteNode(node); } -#line 2383 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2381 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 59: -#line 608 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 608 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! parser->configureWriteQuery(AQL_QUERY_UPDATE, (yyvsp[-1].node), (yyvsp[0].node))) { YYABORT; @@ -2393,11 +2391,11 @@ yyreduce: parser->ast()->addOperation(node); parser->setWriteNode(node); } -#line 2397 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2395 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 60: -#line 617 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 617 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! parser->configureWriteQuery(AQL_QUERY_UPDATE, (yyvsp[-1].node), (yyvsp[0].node))) { YYABORT; @@ -2407,18 +2405,18 @@ yyreduce: parser->ast()->addOperation(node); parser->setWriteNode(node); } -#line 2411 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2409 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 61: -#line 629 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 629 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2418 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2416 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 62: -#line 634 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 634 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! parser->configureWriteQuery(AQL_QUERY_REPLACE, (yyvsp[-1].node), (yyvsp[0].node))) { YYABORT; @@ -2428,11 +2426,11 @@ yyreduce: parser->ast()->addOperation(node); parser->setWriteNode(node); } -#line 2432 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2430 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 63: -#line 643 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 643 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! parser->configureWriteQuery(AQL_QUERY_REPLACE, (yyvsp[-1].node), (yyvsp[0].node))) { YYABORT; @@ -2442,44 +2440,44 @@ yyreduce: parser->ast()->addOperation(node); parser->setWriteNode(node); } -#line 2446 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2444 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 64: -#line 655 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 655 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2453 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2451 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 65: -#line 660 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 660 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.intval) = static_cast(NODE_TYPE_UPDATE); } -#line 2461 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2459 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 66: -#line 663 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 663 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.intval) = static_cast(NODE_TYPE_REPLACE); } -#line 2469 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2467 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 67: -#line 669 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 669 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // reserve a variable named "$OLD", we might need it in the update expression // and in a later return thing parser->pushStack(parser->ast()->createNodeVariable(Variable::NAME_OLD, true)); } -#line 2479 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2477 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 68: -#line 673 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 673 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (! parser->configureWriteQuery(AQL_QUERY_UPSERT, (yyvsp[-1].node), (yyvsp[0].node))) { YYABORT; @@ -2525,11 +2523,11 @@ yyreduce: parser->ast()->addOperation(node); parser->setWriteNode(node); } -#line 2529 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2527 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 69: -#line 721 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 721 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto const scopeType = parser->ast()->scopes()->type(); @@ -2538,75 +2536,75 @@ yyreduce: parser->registerParseError(TRI_ERROR_QUERY_PARSE, "cannot use DISTINCT modifier on top-level query element", yylloc.first_line, yylloc.first_column); } } -#line 2542 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2540 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 70: -#line 728 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 728 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeDistinct((yyvsp[0].node)); } -#line 2550 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2548 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 71: -#line 731 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 731 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2558 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2556 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 72: -#line 737 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 737 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2566 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2564 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 73: -#line 740 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 740 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2574 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2572 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 74: -#line 743 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 743 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2582 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2580 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 75: -#line 746 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 746 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2590 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2588 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 76: -#line 749 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 749 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2598 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2596 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 77: -#line 752 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 752 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeRange((yyvsp[-2].node), (yyvsp[0].node)); } -#line 2606 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2604 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 78: -#line 758 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 758 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.strval) = (yyvsp[0].strval); @@ -2614,11 +2612,11 @@ yyreduce: ABORT_OOM } } -#line 2618 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2616 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 79: -#line 765 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 765 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if ((yyvsp[-2].strval) == nullptr || (yyvsp[0].strval) == nullptr) { ABORT_OOM @@ -2633,205 +2631,205 @@ yyreduce: ABORT_OOM } } -#line 2637 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2635 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 80: -#line 782 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 782 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { parser->pushStack((yyvsp[0].strval)); auto node = parser->ast()->createNodeArray(); parser->pushStack(node); } -#line 2648 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2646 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 81: -#line 787 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 787 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto list = static_cast(parser->popStack()); (yyval.node) = parser->ast()->createNodeFunctionCall(static_cast(parser->popStack()), list); } -#line 2657 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2655 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 82: -#line 794 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 794 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_PLUS, (yyvsp[0].node)); } -#line 2665 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2663 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 83: -#line 797 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 797 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_MINUS, (yyvsp[0].node)); } -#line 2673 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2671 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 84: -#line 800 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 800 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_NOT, (yyvsp[0].node)); } -#line 2681 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2679 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 85: -#line 806 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 806 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_OR, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2689 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2687 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 86: -#line 809 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 809 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_AND, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2697 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2695 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 87: -#line 812 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 812 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_PLUS, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2705 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2703 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 88: -#line 815 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 815 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_MINUS, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2713 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2711 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 89: -#line 818 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 818 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_TIMES, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2721 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2719 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 90: -#line 821 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 821 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_DIV, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2729 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2727 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 91: -#line 824 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 824 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_MOD, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2737 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2735 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 92: -#line 827 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 827 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_EQ, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2745 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2743 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 93: -#line 830 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 830 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_NE, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2753 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2751 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 94: -#line 833 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 833 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_LT, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2761 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2759 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 95: -#line 836 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 836 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_GT, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2769 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2767 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 96: -#line 839 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 839 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_LE, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2777 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2775 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 97: -#line 842 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 842 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_GE, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2785 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2783 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 98: -#line 845 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 845 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_IN, (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2793 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2791 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 99: -#line 848 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 848 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_NIN, (yyvsp[-3].node), (yyvsp[0].node)); } -#line 2801 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2799 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 100: -#line 854 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 854 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeTernaryOperator((yyvsp[-4].node), (yyvsp[-2].node), (yyvsp[0].node)); } -#line 2809 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2807 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 101: -#line 860 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 860 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2816 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2814 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 102: -#line 862 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 862 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2823 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2821 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 103: -#line 867 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 867 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2831 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2829 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 104: -#line 870 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 870 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (parser->isModificationQuery()) { parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected subquery after data-modification operation", yylloc.first_line, yylloc.first_column); @@ -2839,11 +2837,11 @@ yyreduce: parser->ast()->scopes()->start(triagens::aql::AQL_SCOPE_SUBQUERY); parser->ast()->startSubQuery(); } -#line 2843 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2841 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 105: -#line 876 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 876 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { AstNode* node = parser->ast()->endSubQuery(); parser->ast()->scopes()->endCurrent(); @@ -2854,98 +2852,98 @@ yyreduce: (yyval.node) = parser->ast()->createNodeReference(variableName.c_str()); } -#line 2858 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2856 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 106: -#line 889 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 889 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { parser->pushArrayElement((yyvsp[0].node)); } -#line 2866 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2864 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 107: -#line 892 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 892 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { parser->pushArrayElement((yyvsp[0].node)); } -#line 2874 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2872 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 108: -#line 898 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 898 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2882 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2880 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 109: -#line 901 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 901 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 2890 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2888 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 110: -#line 907 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 907 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto node = parser->ast()->createNodeArray(); parser->pushStack(node); } -#line 2899 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2897 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 111: -#line 910 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 910 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = static_cast(parser->popStack()); } -#line 2907 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2905 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 112: -#line 916 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 916 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2914 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2912 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 113: -#line 918 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 918 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2921 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2919 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 114: -#line 923 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 923 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { parser->pushArrayElement((yyvsp[0].node)); } -#line 2929 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2927 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 115: -#line 926 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 926 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { parser->pushArrayElement((yyvsp[0].node)); } -#line 2937 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2935 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 116: -#line 932 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 932 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = nullptr; } -#line 2945 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2943 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 117: -#line 935 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 935 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if ((yyvsp[-1].strval) == nullptr || (yyvsp[0].node) == nullptr) { ABORT_OOM @@ -2957,60 +2955,60 @@ yyreduce: (yyval.node) = (yyvsp[0].node); } -#line 2961 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2959 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 118: -#line 949 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 949 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto node = parser->ast()->createNodeObject(); parser->pushStack(node); } -#line 2970 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2968 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 119: -#line 952 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 952 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = static_cast(parser->popStack()); } -#line 2978 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2976 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 120: -#line 958 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 958 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2985 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2983 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 121: -#line 960 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 960 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2992 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2990 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 122: -#line 965 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 965 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 2999 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 2997 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 123: -#line 967 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 967 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { } -#line 3006 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3004 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 124: -#line 972 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 972 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // attribute-name-only (comparable to JS enhanced object literals, e.g. { foo, bar }) auto ast = parser->ast(); - auto variable = ast->scopes()->getVariable((yyvsp[0].strval)); + auto variable = ast->scopes()->getVariable((yyvsp[0].strval), true); if (variable == nullptr) { // variable does not exist @@ -3021,20 +3019,20 @@ yyreduce: auto node = ast->createNodeReference(variable); parser->pushObjectElement((yyvsp[0].strval), node); } -#line 3025 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3023 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 125: -#line 986 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 986 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // attribute-name : attribute-value parser->pushObjectElement((yyvsp[-2].strval), (yyvsp[0].node)); } -#line 3034 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3032 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 126: -#line 990 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 990 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // bind-parameter : attribute-value if ((yyvsp[-2].strval) == nullptr) { @@ -3048,123 +3046,113 @@ yyreduce: auto param = parser->ast()->createNodeParameter((yyvsp[-2].strval)); parser->pushObjectElement(param, (yyvsp[0].node)); } -#line 3052 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3050 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 127: -#line 1003 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1003 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // [ attribute-name-expression ] : attribute-value parser->pushObjectElement((yyvsp[-3].node), (yyvsp[0].node)); } -#line 3061 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3059 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 128: -#line 1010 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1010 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.intval) = 1; } -#line 3069 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3067 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 129: -#line 1013 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1013 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.intval) = (yyvsp[-1].intval) + 1; } -#line 3077 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3075 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 130: -#line 1019 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1019 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = nullptr; } -#line 3085 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3083 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 131: -#line 1022 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1022 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 3093 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3091 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 132: -#line 1028 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1028 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = nullptr; } -#line 3101 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3099 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 133: -#line 1031 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1031 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeArrayLimit(nullptr, (yyvsp[0].node)); } -#line 3109 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3107 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 134: -#line 1034 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1034 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeArrayLimit((yyvsp[-2].node), (yyvsp[0].node)); } -#line 3117 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3115 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 135: -#line 1040 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1040 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = nullptr; } -#line 3125 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3123 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 136: -#line 1043 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1043 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 3133 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3131 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 137: -#line 1049 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1049 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // variable or collection auto ast = parser->ast(); AstNode* node = nullptr; - auto variable = ast->scopes()->getVariable((yyvsp[0].strval)); + auto variable = ast->scopes()->getVariable((yyvsp[0].strval), true); - if (variable != nullptr) { - // variable exists, now use it - node = ast->createNodeReference(variable); - } - else { + if (variable == nullptr) { // variable does not exist - // now try variable aliases OLD (= $OLD) and NEW (= $NEW) - if (strcmp((yyvsp[0].strval), "OLD") == 0) { - variable = ast->scopes()->getVariable(Variable::NAME_OLD); - } - else if (strcmp((yyvsp[0].strval), "NEW") == 0) { - variable = ast->scopes()->getVariable(Variable::NAME_NEW); - } - else if (ast->scopes()->canUseCurrentVariable() && strcmp((yyvsp[0].strval), "CURRENT") == 0) { + // now try special variables + if (ast->scopes()->canUseCurrentVariable() && strcmp((yyvsp[0].strval), "CURRENT") == 0) { variable = ast->scopes()->getCurrentVariable(); } else if (strcmp((yyvsp[0].strval), Variable::NAME_CURRENT) == 0) { variable = ast->scopes()->getCurrentVariable(); } + } - if (variable != nullptr) { - // variable alias exists, now use it - node = ast->createNodeReference(variable); - } + if (variable != nullptr) { + // variable alias exists, now use it + node = ast->createNodeReference(variable); } if (node == nullptr) { @@ -3176,27 +3164,27 @@ yyreduce: (yyval.node) = node; } -#line 3180 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3168 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 138: -#line 1091 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1081 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 3188 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3176 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 139: -#line 1094 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1084 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 3196 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3184 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 140: -#line 1097 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1087 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); @@ -3204,11 +3192,11 @@ yyreduce: ABORT_OOM } } -#line 3208 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3196 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 141: -#line 1104 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1094 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if ((yyvsp[-1].node)->type == NODE_TYPE_EXPANSION) { // create a dummy passthru node that reduces and evaluates the expansion first @@ -3219,11 +3207,11 @@ yyreduce: (yyval.node) = (yyvsp[-1].node); } } -#line 3223 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3211 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 142: -#line 1114 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1104 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if (parser->isModificationQuery()) { parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected subquery after data-modification operation", yylloc.first_line, yylloc.first_column); @@ -3231,11 +3219,11 @@ yyreduce: parser->ast()->scopes()->start(triagens::aql::AQL_SCOPE_SUBQUERY); parser->ast()->startSubQuery(); } -#line 3235 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3223 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 143: -#line 1120 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1110 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { AstNode* node = parser->ast()->endSubQuery(); parser->ast()->scopes()->endCurrent(); @@ -3246,11 +3234,11 @@ yyreduce: (yyval.node) = parser->ast()->createNodeReference(variableName.c_str()); } -#line 3250 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3238 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 144: -#line 1130 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1120 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // named variable access, e.g. variable.reference if ((yyvsp[-2].node)->type == NODE_TYPE_EXPANSION) { @@ -3266,11 +3254,11 @@ yyreduce: (yyval.node) = parser->ast()->createNodeAttributeAccess((yyvsp[-2].node), (yyvsp[0].strval)); } } -#line 3270 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3258 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 145: -#line 1145 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1135 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // named variable access, e.g. variable.@reference if ((yyvsp[-2].node)->type == NODE_TYPE_EXPANSION) { @@ -3285,11 +3273,11 @@ yyreduce: (yyval.node) = parser->ast()->createNodeBoundAttributeAccess((yyvsp[-2].node), (yyvsp[0].node)); } } -#line 3289 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3277 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 146: -#line 1159 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1149 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // indexed variable access, e.g. variable[index] if ((yyvsp[-3].node)->type == NODE_TYPE_EXPANSION) { @@ -3304,11 +3292,11 @@ yyreduce: (yyval.node) = parser->ast()->createNodeIndexedAccess((yyvsp[-3].node), (yyvsp[-1].node)); } } -#line 3308 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3296 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 147: -#line 1173 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1163 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { // variable expansion, e.g. variable[*], with optional FILTER, LIMIT and RETURN clauses if ((yyvsp[0].intval) > 1 && (yyvsp[-2].node)->type == NODE_TYPE_EXPANSION) { @@ -3333,11 +3321,11 @@ yyreduce: auto scopes = parser->ast()->scopes(); scopes->stackCurrentVariable(scopes->getVariable(iteratorName)); } -#line 3337 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3325 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 148: -#line 1196 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1186 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { auto scopes = parser->ast()->scopes(); scopes->unstackCurrentVariable(); @@ -3356,27 +3344,27 @@ yyreduce: (yyval.node) = parser->ast()->createNodeExpansion((yyvsp[-5].intval), iterator, parser->ast()->createNodeReference(variable->name.c_str()), (yyvsp[-3].node), (yyvsp[-2].node), (yyvsp[-1].node)); } } -#line 3360 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3348 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 149: -#line 1217 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1207 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 3368 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3356 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 150: -#line 1220 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1210 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 3376 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3364 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 151: -#line 1226 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1216 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if ((yyvsp[0].node) == nullptr) { ABORT_OOM @@ -3384,11 +3372,11 @@ yyreduce: (yyval.node) = (yyvsp[0].node); } -#line 3388 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3376 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 152: -#line 1233 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1223 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if ((yyvsp[0].node) == nullptr) { ABORT_OOM @@ -3396,51 +3384,51 @@ yyreduce: (yyval.node) = (yyvsp[0].node); } -#line 3400 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3388 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 153: -#line 1243 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1233 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeValueString((yyvsp[0].strval)); } -#line 3408 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3396 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 154: -#line 1246 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1236 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = (yyvsp[0].node); } -#line 3416 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3404 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 155: -#line 1249 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1239 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeValueNull(); } -#line 3424 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3412 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 156: -#line 1252 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1242 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeValueBool(true); } -#line 3432 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3420 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 157: -#line 1255 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1245 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeValueBool(false); } -#line 3440 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3428 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 158: -#line 1261 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1251 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if ((yyvsp[0].strval) == nullptr) { ABORT_OOM @@ -3448,11 +3436,11 @@ yyreduce: (yyval.node) = parser->ast()->createNodeCollection((yyvsp[0].strval), TRI_TRANSACTION_WRITE); } -#line 3452 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3440 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 159: -#line 1268 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1258 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if ((yyvsp[0].strval) == nullptr) { ABORT_OOM @@ -3460,11 +3448,11 @@ yyreduce: (yyval.node) = parser->ast()->createNodeCollection((yyvsp[0].strval), TRI_TRANSACTION_WRITE); } -#line 3464 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3452 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 160: -#line 1275 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1265 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if ((yyvsp[0].strval) == nullptr) { ABORT_OOM @@ -3476,19 +3464,19 @@ yyreduce: (yyval.node) = parser->ast()->createNodeParameter((yyvsp[0].strval)); } -#line 3480 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3468 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 161: -#line 1289 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1279 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.node) = parser->ast()->createNodeParameter((yyvsp[0].strval)); } -#line 3488 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3476 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 162: -#line 1295 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1285 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if ((yyvsp[0].strval) == nullptr) { ABORT_OOM @@ -3496,11 +3484,11 @@ yyreduce: (yyval.strval) = (yyvsp[0].strval); } -#line 3500 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3488 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 163: -#line 1302 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1292 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { if ((yyvsp[0].strval) == nullptr) { ABORT_OOM @@ -3508,19 +3496,19 @@ yyreduce: (yyval.strval) = (yyvsp[0].strval); } -#line 3512 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3500 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; case 164: -#line 1311 "arangod/Aql/grammar.y" /* yacc.c:1661 */ +#line 1301 "arangod/Aql/grammar.y" /* yacc.c:1646 */ { (yyval.strval) = (yyvsp[0].strval); } -#line 3520 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3508 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ break; -#line 3524 "arangod/Aql/grammar.cpp" /* yacc.c:1661 */ +#line 3512 "arangod/Aql/grammar.cpp" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires diff --git a/arangod/Aql/grammar.h b/arangod/Aql/grammar.h index c6f6020cdb..6f7fe6abb6 100644 --- a/arangod/Aql/grammar.h +++ b/arangod/Aql/grammar.h @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ +/* A Bison parser, made by GNU Bison 3.0.2. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -110,20 +110,18 @@ extern int Aqldebug; /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - +typedef union YYSTYPE YYSTYPE; union YYSTYPE { -#line 17 "arangod/Aql/grammar.y" /* yacc.c:1915 */ +#line 17 "arangod/Aql/grammar.y" /* yacc.c:1909 */ triagens::aql::AstNode* node; char* strval; bool boolval; int64_t intval; -#line 124 "arangod/Aql/grammar.hpp" /* yacc.c:1915 */ +#line 124 "arangod/Aql/grammar.hpp" /* yacc.c:1909 */ }; - -typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif diff --git a/arangod/Aql/grammar.y b/arangod/Aql/grammar.y index 3b87ec5857..eee12edc7c 100644 --- a/arangod/Aql/grammar.y +++ b/arangod/Aql/grammar.y @@ -972,7 +972,7 @@ object_element: T_STRING { // attribute-name-only (comparable to JS enhanced object literals, e.g. { foo, bar }) auto ast = parser->ast(); - auto variable = ast->scopes()->getVariable($1); + auto variable = ast->scopes()->getVariable($1, true); if (variable == nullptr) { // variable does not exist @@ -1051,32 +1051,22 @@ reference: auto ast = parser->ast(); AstNode* node = nullptr; - auto variable = ast->scopes()->getVariable($1); + auto variable = ast->scopes()->getVariable($1, true); - if (variable != nullptr) { - // variable exists, now use it - node = ast->createNodeReference(variable); - } - else { + if (variable == nullptr) { // variable does not exist - // now try variable aliases OLD (= $OLD) and NEW (= $NEW) - if (strcmp($1, "OLD") == 0) { - variable = ast->scopes()->getVariable(Variable::NAME_OLD); - } - else if (strcmp($1, "NEW") == 0) { - variable = ast->scopes()->getVariable(Variable::NAME_NEW); - } - else if (ast->scopes()->canUseCurrentVariable() && strcmp($1, "CURRENT") == 0) { + // now try special variables + if (ast->scopes()->canUseCurrentVariable() && strcmp($1, "CURRENT") == 0) { variable = ast->scopes()->getCurrentVariable(); } else if (strcmp($1, Variable::NAME_CURRENT) == 0) { variable = ast->scopes()->getCurrentVariable(); } + } - if (variable != nullptr) { - // variable alias exists, now use it - node = ast->createNodeReference(variable); - } + if (variable != nullptr) { + // variable alias exists, now use it + node = ast->createNodeReference(variable); } if (node == nullptr) { diff --git a/js/server/tests/aql-modify-noncluster.js b/js/server/tests/aql-modify-noncluster.js index c97b6c4466..274ce07f21 100644 --- a/js/server/tests/aql-modify-noncluster.js +++ b/js/server/tests/aql-modify-noncluster.js @@ -901,6 +901,22 @@ function ahuacatlRemoveSuite () { } }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test remove - return what +//////////////////////////////////////////////////////////////////////////////// + + testRemoveReturnDocObjectLiteral : function () { + var actual = AQL_EXECUTE("FOR d IN " + cn1 + " REMOVE d IN " + cn1 + " LET removed = OLD RETURN { OLD }", {}).json; + + assertEqual(0, c1.count()); + assertEqual(100, actual.length); + for (var i = 0; i < actual.length; ++i) { + var doc = actual[i]; + assertTrue(doc.hasOwnProperty("OLD")); + assertTrue(doc.OLD.hasOwnProperty("_key")); + } + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test remove - return what //////////////////////////////////////////////////////////////////////////////// @@ -1563,6 +1579,25 @@ function ahuacatlInsertSuite () { } }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test insert +//////////////////////////////////////////////////////////////////////////////// + + testInsertReturnObjectLiteral : function () { + var expected = { writesExecuted: 100, writesIgnored: 0 }; + var actual = getModifyQueryResultsRaw("FOR d IN " + cn1 + " INSERT { foxx: true } IN " + cn1 + " RETURN { NEW }", {}); + + assertEqual(100, actual.json.length); + assertEqual(200, c1.count()); + assertEqual(expected, sanitizeStats(actual.stats)); + + for (var i = 0; i < actual.json.length; ++i) { + var doc = actual.json[i]; + assertTrue(doc.hasOwnProperty("NEW")); + assertTrue(doc.NEW.hasOwnProperty("foxx")); + } + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test insert //////////////////////////////////////////////////////////////////////////////// @@ -2520,6 +2555,29 @@ function ahuacatlUpdateSuite () { } }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test update +//////////////////////////////////////////////////////////////////////////////// + + testUpdateWithNothingReturnObjectLiteral : function () { + var expected = { writesExecuted: 100, writesIgnored: 0 }; + var actual = getModifyQueryResultsRaw("FOR d IN @@cn SORT d.value1 UPDATE d WITH { } IN @@cn RETURN { OLD, NEW }", { "@cn": cn1 }); + + assertEqual(expected, sanitizeStats(actual.stats)); + assertEqual(100, actual.json.length); + + for (var i = 0; i < 100; ++i) { + var doc = actual.json[i]; + assertEqual("test" + i, doc.OLD._key); + assertEqual("test" + i, doc.NEW._key); + assertEqual(i, doc.OLD.value1); + assertEqual(i, doc.NEW.value1); + assertEqual("test" + i, doc.OLD.value2); + assertEqual("test" + i, doc.NEW.value2); + assertEqual(doc.OLD._rev, doc.NEW._rev); // _rev should not have changed + } + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test update //////////////////////////////////////////////////////////////////////////////// @@ -2543,6 +2601,29 @@ function ahuacatlUpdateSuite () { } }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test update +//////////////////////////////////////////////////////////////////////////////// + + testUpdateWithSomethingReturnObjectLiteral : function () { + var expected = { writesExecuted: 100, writesIgnored: 0 }; + var actual = getModifyQueryResultsRaw("FOR d IN @@cn SORT d.value1 UPDATE d WITH { value1: d.value1, value2: d.value2 } IN @@cn RETURN { OLD, NEW }", { "@cn": cn1 }); + + assertEqual(expected, sanitizeStats(actual.stats)); + assertEqual(100, actual.json.length); + + for (var i = 0; i < 100; ++i) { + var doc = actual.json[i]; + assertEqual("test" + i, doc.OLD._key); + assertEqual("test" + i, doc.NEW._key); + assertEqual(i, doc.OLD.value1); + assertEqual(i, doc.NEW.value1); + assertEqual("test" + i, doc.OLD.value2); + assertEqual("test" + i, doc.NEW.value2); + assertNotEqual(doc.OLD._rev, doc.NEW._rev); // _rev should have changed + } + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test update //////////////////////////////////////////////////////////////////////////////// @@ -3194,6 +3275,29 @@ function ahuacatlUpdateSuite () { } }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test upsert +//////////////////////////////////////////////////////////////////////////////// + + testUpsertUpdateWithNothingReturnObjectLiteral : function () { + var expected = { writesExecuted: 100, writesIgnored: 0 }; + var actual = getModifyQueryResultsRaw("FOR d IN @@cn SORT d.value1 UPSERT { _key: d._key } INSERT { } UPDATE { } IN @@cn RETURN { OLD, NEW }", { "@cn": cn1 }); + + assertEqual(expected, sanitizeStats(actual.stats)); + assertEqual(100, actual.json.length); + + for (var i = 0; i < 100; ++i) { + var doc = actual.json[i]; + assertEqual("test" + i, doc.OLD._key); + assertEqual("test" + i, doc.NEW._key); + assertEqual(i, doc.OLD.value1); + assertEqual(i, doc.NEW.value1); + assertEqual("test" + i, doc.OLD.value2); + assertEqual("test" + i, doc.NEW.value2); + assertEqual(doc.OLD._rev, doc.NEW._rev); // _rev should not have changed + } + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test upsert //////////////////////////////////////////////////////////////////////////////// From 9f0384284f4ffbbd6a7a696abb4d85292f614fdc Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Wed, 19 Aug 2015 11:19:37 +0200 Subject: [PATCH 27/29] moved files --- CMakeLists.txt | 1 - Makefile.am | 1 - .../Admin/ApplicationAdminServer.cpp | 0 .../Admin/ApplicationAdminServer.h | 0 .../Admin/RestAdminBaseHandler.cpp | 0 {lib => arangod}/Admin/RestAdminBaseHandler.h | 0 .../Admin/RestAdminLogHandler.cpp | 0 {lib => arangod}/Admin/RestAdminLogHandler.h | 0 {lib => arangod}/Admin/RestBaseHandler.cpp | 0 {lib => arangod}/Admin/RestBaseHandler.h | 0 .../Admin/RestDebugHelperHandler.cpp | 0 .../Admin/RestDebugHelperHandler.h | 0 {lib => arangod}/Admin/RestHandlerCreator.h | 0 {lib => arangod}/Admin/RestJobHandler.cpp | 0 {lib => arangod}/Admin/RestJobHandler.h | 0 .../Admin/RestShutdownHandler.cpp | 0 {lib => arangod}/Admin/RestShutdownHandler.h | 0 {lib => arangod}/Admin/RestVersionHandler.cpp | 0 {lib => arangod}/Admin/RestVersionHandler.h | 0 .../ApplicationServer/ApplicationFeature.cpp | 0 .../ApplicationServer/ApplicationFeature.h | 0 .../ApplicationServer/ApplicationServer.cpp | 0 .../ApplicationServer/ApplicationServer.h | 0 arangod/CMakeLists.txt | 41 ++++ .../Dispatcher/ApplicationDispatcher.cpp | 0 .../Dispatcher/ApplicationDispatcher.h | 0 {lib => arangod}/Dispatcher/Dispatcher.cpp | 0 {lib => arangod}/Dispatcher/Dispatcher.h | 0 .../Dispatcher/DispatcherQueue.cpp | 0 {lib => arangod}/Dispatcher/DispatcherQueue.h | 0 .../Dispatcher/DispatcherThread.cpp | 0 .../Dispatcher/DispatcherThread.h | 0 {lib => arangod}/Dispatcher/Job.cpp | 0 {lib => arangod}/Dispatcher/Job.h | 0 {lib => arangod}/Dispatcher/RequeueTask.cpp | 0 {lib => arangod}/Dispatcher/RequeueTask.h | 0 .../HttpServer/ApplicationEndpointServer.cpp | 0 .../HttpServer/ApplicationEndpointServer.h | 0 .../HttpServer/AsyncJobManager.cpp | 0 {lib => arangod}/HttpServer/AsyncJobManager.h | 0 {lib => arangod}/HttpServer/HttpCommTask.cpp | 0 {lib => arangod}/HttpServer/HttpCommTask.h | 0 {lib => arangod}/HttpServer/HttpHandler.cpp | 0 {lib => arangod}/HttpServer/HttpHandler.h | 0 .../HttpServer/HttpHandlerFactory.cpp | 0 .../HttpServer/HttpHandlerFactory.h | 0 .../HttpServer/HttpListenTask.cpp | 0 {lib => arangod}/HttpServer/HttpListenTask.h | 0 {lib => arangod}/HttpServer/HttpServer.cpp | 0 {lib => arangod}/HttpServer/HttpServer.h | 0 {lib => arangod}/HttpServer/HttpServerJob.cpp | 0 {lib => arangod}/HttpServer/HttpServerJob.h | 0 {lib => arangod}/HttpServer/HttpsCommTask.cpp | 0 {lib => arangod}/HttpServer/HttpsCommTask.h | 0 {lib => arangod}/HttpServer/HttpsServer.cpp | 0 {lib => arangod}/HttpServer/HttpsServer.h | 0 {lib => arangod}/HttpServer/PathHandler.cpp | 0 {lib => arangod}/HttpServer/PathHandler.h | 0 arangod/Makefile.files | 41 ++++ {lib => arangod}/Rest/AnyServer.cpp | 0 {lib => arangod}/Rest/AnyServer.h | 0 {lib => arangod}/Rest/Handler.cpp | 0 {lib => arangod}/Rest/Handler.h | 4 +- {lib => arangod}/Rest/OperationMode.h | 0 arangod/RestServer/arangod.cpp | 14 +- .../Scheduler/ApplicationScheduler.cpp | 0 .../Scheduler/ApplicationScheduler.h | 0 {lib => arangod}/Scheduler/ListenTask.cpp | 0 {lib => arangod}/Scheduler/ListenTask.h | 0 {lib => arangod}/Scheduler/PeriodicTask.cpp | 0 {lib => arangod}/Scheduler/PeriodicTask.h | 0 {lib => arangod}/Scheduler/Scheduler.cpp | 0 {lib => arangod}/Scheduler/Scheduler.h | 0 {lib => arangod}/Scheduler/SchedulerLibev.cpp | 0 {lib => arangod}/Scheduler/SchedulerLibev.h | 0 .../Scheduler/SchedulerThread.cpp | 0 {lib => arangod}/Scheduler/SchedulerThread.h | 0 {lib => arangod}/Scheduler/SignalTask.cpp | 0 {lib => arangod}/Scheduler/SignalTask.h | 0 {lib => arangod}/Scheduler/SocketTask.cpp | 0 {lib => arangod}/Scheduler/SocketTask.h | 0 {lib => arangod}/Scheduler/Task.cpp | 0 {lib => arangod}/Scheduler/Task.h | 0 {lib => arangod}/Scheduler/TaskManager.cpp | 0 {lib => arangod}/Scheduler/TaskManager.h | 0 {lib => arangod}/Scheduler/TimerTask.cpp | 0 {lib => arangod}/Scheduler/TimerTask.h | 0 {lib => arangod}/Scheduler/events.h | 0 {lib => arangod}/Statistics/StatisticsAgent.h | 0 {lib => arangod}/Statistics/figures.h | 0 {lib => arangod}/Statistics/statistics.cpp | 68 ------ {lib => arangod}/Statistics/statistics.h | 6 - arangod/V8Server/v8-statistics.cpp | 225 ++++++++++++++++++ arangod/V8Server/v8-statistics.h | 56 +++++ arangod/V8Server/v8-vocbase.cpp | 3 + lib/Basics/process-utils.cpp | 73 ++++++ lib/Basics/process-utils.h | 14 +- lib/CMakeLists.txt | 50 ---- lib/Makefile.files | 47 ---- lib/Rest/HttpRequest.cpp | 1 - lib/Rest/InitialiseRest.cpp | 5 - lib/Rest/RequestContext.h | 1 - lib/SimpleHttpClient/SslClientConnection.cpp | 1 - lib/V8/v8-utils.cpp | 151 ------------ 104 files changed, 459 insertions(+), 344 deletions(-) rename {lib => arangod}/Admin/ApplicationAdminServer.cpp (100%) rename {lib => arangod}/Admin/ApplicationAdminServer.h (100%) rename {lib => arangod}/Admin/RestAdminBaseHandler.cpp (100%) rename {lib => arangod}/Admin/RestAdminBaseHandler.h (100%) rename {lib => arangod}/Admin/RestAdminLogHandler.cpp (100%) rename {lib => arangod}/Admin/RestAdminLogHandler.h (100%) rename {lib => arangod}/Admin/RestBaseHandler.cpp (100%) rename {lib => arangod}/Admin/RestBaseHandler.h (100%) rename {lib => arangod}/Admin/RestDebugHelperHandler.cpp (100%) rename {lib => arangod}/Admin/RestDebugHelperHandler.h (100%) rename {lib => arangod}/Admin/RestHandlerCreator.h (100%) rename {lib => arangod}/Admin/RestJobHandler.cpp (100%) rename {lib => arangod}/Admin/RestJobHandler.h (100%) rename {lib => arangod}/Admin/RestShutdownHandler.cpp (100%) rename {lib => arangod}/Admin/RestShutdownHandler.h (100%) rename {lib => arangod}/Admin/RestVersionHandler.cpp (100%) rename {lib => arangod}/Admin/RestVersionHandler.h (100%) rename {lib => arangod}/ApplicationServer/ApplicationFeature.cpp (100%) rename {lib => arangod}/ApplicationServer/ApplicationFeature.h (100%) rename {lib => arangod}/ApplicationServer/ApplicationServer.cpp (100%) rename {lib => arangod}/ApplicationServer/ApplicationServer.h (100%) rename {lib => arangod}/Dispatcher/ApplicationDispatcher.cpp (100%) rename {lib => arangod}/Dispatcher/ApplicationDispatcher.h (100%) rename {lib => arangod}/Dispatcher/Dispatcher.cpp (100%) rename {lib => arangod}/Dispatcher/Dispatcher.h (100%) rename {lib => arangod}/Dispatcher/DispatcherQueue.cpp (100%) rename {lib => arangod}/Dispatcher/DispatcherQueue.h (100%) rename {lib => arangod}/Dispatcher/DispatcherThread.cpp (100%) rename {lib => arangod}/Dispatcher/DispatcherThread.h (100%) rename {lib => arangod}/Dispatcher/Job.cpp (100%) rename {lib => arangod}/Dispatcher/Job.h (100%) rename {lib => arangod}/Dispatcher/RequeueTask.cpp (100%) rename {lib => arangod}/Dispatcher/RequeueTask.h (100%) rename {lib => arangod}/HttpServer/ApplicationEndpointServer.cpp (100%) rename {lib => arangod}/HttpServer/ApplicationEndpointServer.h (100%) rename {lib => arangod}/HttpServer/AsyncJobManager.cpp (100%) rename {lib => arangod}/HttpServer/AsyncJobManager.h (100%) rename {lib => arangod}/HttpServer/HttpCommTask.cpp (100%) rename {lib => arangod}/HttpServer/HttpCommTask.h (100%) rename {lib => arangod}/HttpServer/HttpHandler.cpp (100%) rename {lib => arangod}/HttpServer/HttpHandler.h (100%) rename {lib => arangod}/HttpServer/HttpHandlerFactory.cpp (100%) rename {lib => arangod}/HttpServer/HttpHandlerFactory.h (100%) rename {lib => arangod}/HttpServer/HttpListenTask.cpp (100%) rename {lib => arangod}/HttpServer/HttpListenTask.h (100%) rename {lib => arangod}/HttpServer/HttpServer.cpp (100%) rename {lib => arangod}/HttpServer/HttpServer.h (100%) rename {lib => arangod}/HttpServer/HttpServerJob.cpp (100%) rename {lib => arangod}/HttpServer/HttpServerJob.h (100%) rename {lib => arangod}/HttpServer/HttpsCommTask.cpp (100%) rename {lib => arangod}/HttpServer/HttpsCommTask.h (100%) rename {lib => arangod}/HttpServer/HttpsServer.cpp (100%) rename {lib => arangod}/HttpServer/HttpsServer.h (100%) rename {lib => arangod}/HttpServer/PathHandler.cpp (100%) rename {lib => arangod}/HttpServer/PathHandler.h (100%) rename {lib => arangod}/Rest/AnyServer.cpp (100%) rename {lib => arangod}/Rest/AnyServer.h (100%) rename {lib => arangod}/Rest/Handler.cpp (100%) rename {lib => arangod}/Rest/Handler.h (99%) rename {lib => arangod}/Rest/OperationMode.h (100%) rename {lib => arangod}/Scheduler/ApplicationScheduler.cpp (100%) rename {lib => arangod}/Scheduler/ApplicationScheduler.h (100%) rename {lib => arangod}/Scheduler/ListenTask.cpp (100%) rename {lib => arangod}/Scheduler/ListenTask.h (100%) rename {lib => arangod}/Scheduler/PeriodicTask.cpp (100%) rename {lib => arangod}/Scheduler/PeriodicTask.h (100%) rename {lib => arangod}/Scheduler/Scheduler.cpp (100%) rename {lib => arangod}/Scheduler/Scheduler.h (100%) rename {lib => arangod}/Scheduler/SchedulerLibev.cpp (100%) rename {lib => arangod}/Scheduler/SchedulerLibev.h (100%) rename {lib => arangod}/Scheduler/SchedulerThread.cpp (100%) rename {lib => arangod}/Scheduler/SchedulerThread.h (100%) rename {lib => arangod}/Scheduler/SignalTask.cpp (100%) rename {lib => arangod}/Scheduler/SignalTask.h (100%) rename {lib => arangod}/Scheduler/SocketTask.cpp (100%) rename {lib => arangod}/Scheduler/SocketTask.h (100%) rename {lib => arangod}/Scheduler/Task.cpp (100%) rename {lib => arangod}/Scheduler/Task.h (100%) rename {lib => arangod}/Scheduler/TaskManager.cpp (100%) rename {lib => arangod}/Scheduler/TaskManager.h (100%) rename {lib => arangod}/Scheduler/TimerTask.cpp (100%) rename {lib => arangod}/Scheduler/TimerTask.h (100%) rename {lib => arangod}/Scheduler/events.h (100%) rename {lib => arangod}/Statistics/StatisticsAgent.h (100%) rename {lib => arangod}/Statistics/figures.h (100%) rename {lib => arangod}/Statistics/statistics.cpp (92%) rename {lib => arangod}/Statistics/statistics.h (98%) create mode 100644 arangod/V8Server/v8-statistics.cpp create mode 100644 arangod/V8Server/v8-statistics.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d0fabbf103..e07caeeb81 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,6 @@ project(arangodb) set(LIB_ARANGO arango) set(LIB_ARANGO_CLIENT arango_client) -set(LIB_ARANGO_FE arango_fe) set(LIB_ARANGO_V8 arango_v8) set(BIN_ARANGOB arangob) diff --git a/Makefile.am b/Makefile.am index 11d5dcfb64..e9e3055650 100644 --- a/Makefile.am +++ b/Makefile.am @@ -161,7 +161,6 @@ LIBS = \ noinst_LIBRARIES = \ lib/libarango.a \ lib/libarango_v8.a \ - lib/libarango_fe.a \ lib/libarango_client.a \ arangod/libarangod.a diff --git a/lib/Admin/ApplicationAdminServer.cpp b/arangod/Admin/ApplicationAdminServer.cpp similarity index 100% rename from lib/Admin/ApplicationAdminServer.cpp rename to arangod/Admin/ApplicationAdminServer.cpp diff --git a/lib/Admin/ApplicationAdminServer.h b/arangod/Admin/ApplicationAdminServer.h similarity index 100% rename from lib/Admin/ApplicationAdminServer.h rename to arangod/Admin/ApplicationAdminServer.h diff --git a/lib/Admin/RestAdminBaseHandler.cpp b/arangod/Admin/RestAdminBaseHandler.cpp similarity index 100% rename from lib/Admin/RestAdminBaseHandler.cpp rename to arangod/Admin/RestAdminBaseHandler.cpp diff --git a/lib/Admin/RestAdminBaseHandler.h b/arangod/Admin/RestAdminBaseHandler.h similarity index 100% rename from lib/Admin/RestAdminBaseHandler.h rename to arangod/Admin/RestAdminBaseHandler.h diff --git a/lib/Admin/RestAdminLogHandler.cpp b/arangod/Admin/RestAdminLogHandler.cpp similarity index 100% rename from lib/Admin/RestAdminLogHandler.cpp rename to arangod/Admin/RestAdminLogHandler.cpp diff --git a/lib/Admin/RestAdminLogHandler.h b/arangod/Admin/RestAdminLogHandler.h similarity index 100% rename from lib/Admin/RestAdminLogHandler.h rename to arangod/Admin/RestAdminLogHandler.h diff --git a/lib/Admin/RestBaseHandler.cpp b/arangod/Admin/RestBaseHandler.cpp similarity index 100% rename from lib/Admin/RestBaseHandler.cpp rename to arangod/Admin/RestBaseHandler.cpp diff --git a/lib/Admin/RestBaseHandler.h b/arangod/Admin/RestBaseHandler.h similarity index 100% rename from lib/Admin/RestBaseHandler.h rename to arangod/Admin/RestBaseHandler.h diff --git a/lib/Admin/RestDebugHelperHandler.cpp b/arangod/Admin/RestDebugHelperHandler.cpp similarity index 100% rename from lib/Admin/RestDebugHelperHandler.cpp rename to arangod/Admin/RestDebugHelperHandler.cpp diff --git a/lib/Admin/RestDebugHelperHandler.h b/arangod/Admin/RestDebugHelperHandler.h similarity index 100% rename from lib/Admin/RestDebugHelperHandler.h rename to arangod/Admin/RestDebugHelperHandler.h diff --git a/lib/Admin/RestHandlerCreator.h b/arangod/Admin/RestHandlerCreator.h similarity index 100% rename from lib/Admin/RestHandlerCreator.h rename to arangod/Admin/RestHandlerCreator.h diff --git a/lib/Admin/RestJobHandler.cpp b/arangod/Admin/RestJobHandler.cpp similarity index 100% rename from lib/Admin/RestJobHandler.cpp rename to arangod/Admin/RestJobHandler.cpp diff --git a/lib/Admin/RestJobHandler.h b/arangod/Admin/RestJobHandler.h similarity index 100% rename from lib/Admin/RestJobHandler.h rename to arangod/Admin/RestJobHandler.h diff --git a/lib/Admin/RestShutdownHandler.cpp b/arangod/Admin/RestShutdownHandler.cpp similarity index 100% rename from lib/Admin/RestShutdownHandler.cpp rename to arangod/Admin/RestShutdownHandler.cpp diff --git a/lib/Admin/RestShutdownHandler.h b/arangod/Admin/RestShutdownHandler.h similarity index 100% rename from lib/Admin/RestShutdownHandler.h rename to arangod/Admin/RestShutdownHandler.h diff --git a/lib/Admin/RestVersionHandler.cpp b/arangod/Admin/RestVersionHandler.cpp similarity index 100% rename from lib/Admin/RestVersionHandler.cpp rename to arangod/Admin/RestVersionHandler.cpp diff --git a/lib/Admin/RestVersionHandler.h b/arangod/Admin/RestVersionHandler.h similarity index 100% rename from lib/Admin/RestVersionHandler.h rename to arangod/Admin/RestVersionHandler.h diff --git a/lib/ApplicationServer/ApplicationFeature.cpp b/arangod/ApplicationServer/ApplicationFeature.cpp similarity index 100% rename from lib/ApplicationServer/ApplicationFeature.cpp rename to arangod/ApplicationServer/ApplicationFeature.cpp diff --git a/lib/ApplicationServer/ApplicationFeature.h b/arangod/ApplicationServer/ApplicationFeature.h similarity index 100% rename from lib/ApplicationServer/ApplicationFeature.h rename to arangod/ApplicationServer/ApplicationFeature.h diff --git a/lib/ApplicationServer/ApplicationServer.cpp b/arangod/ApplicationServer/ApplicationServer.cpp similarity index 100% rename from lib/ApplicationServer/ApplicationServer.cpp rename to arangod/ApplicationServer/ApplicationServer.cpp diff --git a/lib/ApplicationServer/ApplicationServer.h b/arangod/ApplicationServer/ApplicationServer.h similarity index 100% rename from lib/ApplicationServer/ApplicationServer.h rename to arangod/ApplicationServer/ApplicationServer.h diff --git a/arangod/CMakeLists.txt b/arangod/CMakeLists.txt index 07dc6652f0..524e73527b 100644 --- a/arangod/CMakeLists.txt +++ b/arangod/CMakeLists.txt @@ -57,6 +57,16 @@ add_executable( ${ProductVersionFiles} Actions/actions.cpp Actions/RestActionHandler.cpp + Admin/ApplicationAdminServer.cpp + Admin/RestAdminBaseHandler.cpp + Admin/RestAdminLogHandler.cpp + Admin/RestBaseHandler.cpp + Admin/RestDebugHelperHandler.cpp + Admin/RestJobHandler.cpp + Admin/RestShutdownHandler.cpp + Admin/RestVersionHandler.cpp + ApplicationServer/ApplicationFeature.cpp + ApplicationServer/ApplicationServer.cpp Aql/AggregationOptions.cpp Aql/AqlItemBlock.cpp Aql/AqlItemBlockManager.cpp @@ -105,6 +115,12 @@ add_executable( Cluster/ServerJob.cpp Cluster/ServerState.cpp Cluster/v8-cluster.cpp + Dispatcher/ApplicationDispatcher.cpp + Dispatcher/Dispatcher.cpp + Dispatcher/DispatcherQueue.cpp + Dispatcher/DispatcherThread.cpp + Dispatcher/Job.cpp + Dispatcher/RequeueTask.cpp FulltextIndex/fulltext-handles.cpp FulltextIndex/fulltext-index.cpp FulltextIndex/fulltext-list.cpp @@ -114,6 +130,17 @@ add_executable( GeoIndex/GeoIndex.cpp HashIndex/hash-array.cpp HashIndex/hash-array-multi.cpp + HttpServer/ApplicationEndpointServer.cpp + HttpServer/AsyncJobManager.cpp + HttpServer/HttpCommTask.cpp + HttpServer/HttpHandler.cpp + HttpServer/HttpHandlerFactory.cpp + HttpServer/HttpListenTask.cpp + HttpServer/HttpServer.cpp + HttpServer/HttpServerJob.cpp + HttpServer/HttpsCommTask.cpp + HttpServer/HttpsServer.cpp + HttpServer/PathHandler.cpp Indexes/CapConstraint.cpp Indexes/EdgeIndex.cpp Indexes/FulltextIndex.cpp @@ -126,6 +153,8 @@ add_executable( Replication/ContinuousSyncer.cpp Replication/InitialSyncer.cpp Replication/Syncer.cpp + Rest/AnyServer.cpp + Rest/Handler.cpp RestHandler/RestBatchHandler.cpp RestHandler/RestCursorHandler.cpp RestHandler/RestDocumentHandler.cpp @@ -144,7 +173,19 @@ add_executable( RestServer/ConsoleThread.cpp RestServer/VocbaseContext.cpp RestServer/arangod.cpp + Scheduler/ApplicationScheduler.cpp + Scheduler/ListenTask.cpp + Scheduler/PeriodicTask.cpp + Scheduler/Scheduler.cpp + Scheduler/SchedulerLibev.cpp + Scheduler/SchedulerThread.cpp + Scheduler/SignalTask.cpp + Scheduler/SocketTask.cpp + Scheduler/Task.cpp + Scheduler/TaskManager.cpp + Scheduler/TimerTask.cpp SkipLists/skiplistIndex.cpp + Statistics/statistics.cpp Utils/CollectionExport.cpp Utils/Cursor.cpp Utils/CursorRepository.cpp diff --git a/lib/Dispatcher/ApplicationDispatcher.cpp b/arangod/Dispatcher/ApplicationDispatcher.cpp similarity index 100% rename from lib/Dispatcher/ApplicationDispatcher.cpp rename to arangod/Dispatcher/ApplicationDispatcher.cpp diff --git a/lib/Dispatcher/ApplicationDispatcher.h b/arangod/Dispatcher/ApplicationDispatcher.h similarity index 100% rename from lib/Dispatcher/ApplicationDispatcher.h rename to arangod/Dispatcher/ApplicationDispatcher.h diff --git a/lib/Dispatcher/Dispatcher.cpp b/arangod/Dispatcher/Dispatcher.cpp similarity index 100% rename from lib/Dispatcher/Dispatcher.cpp rename to arangod/Dispatcher/Dispatcher.cpp diff --git a/lib/Dispatcher/Dispatcher.h b/arangod/Dispatcher/Dispatcher.h similarity index 100% rename from lib/Dispatcher/Dispatcher.h rename to arangod/Dispatcher/Dispatcher.h diff --git a/lib/Dispatcher/DispatcherQueue.cpp b/arangod/Dispatcher/DispatcherQueue.cpp similarity index 100% rename from lib/Dispatcher/DispatcherQueue.cpp rename to arangod/Dispatcher/DispatcherQueue.cpp diff --git a/lib/Dispatcher/DispatcherQueue.h b/arangod/Dispatcher/DispatcherQueue.h similarity index 100% rename from lib/Dispatcher/DispatcherQueue.h rename to arangod/Dispatcher/DispatcherQueue.h diff --git a/lib/Dispatcher/DispatcherThread.cpp b/arangod/Dispatcher/DispatcherThread.cpp similarity index 100% rename from lib/Dispatcher/DispatcherThread.cpp rename to arangod/Dispatcher/DispatcherThread.cpp diff --git a/lib/Dispatcher/DispatcherThread.h b/arangod/Dispatcher/DispatcherThread.h similarity index 100% rename from lib/Dispatcher/DispatcherThread.h rename to arangod/Dispatcher/DispatcherThread.h diff --git a/lib/Dispatcher/Job.cpp b/arangod/Dispatcher/Job.cpp similarity index 100% rename from lib/Dispatcher/Job.cpp rename to arangod/Dispatcher/Job.cpp diff --git a/lib/Dispatcher/Job.h b/arangod/Dispatcher/Job.h similarity index 100% rename from lib/Dispatcher/Job.h rename to arangod/Dispatcher/Job.h diff --git a/lib/Dispatcher/RequeueTask.cpp b/arangod/Dispatcher/RequeueTask.cpp similarity index 100% rename from lib/Dispatcher/RequeueTask.cpp rename to arangod/Dispatcher/RequeueTask.cpp diff --git a/lib/Dispatcher/RequeueTask.h b/arangod/Dispatcher/RequeueTask.h similarity index 100% rename from lib/Dispatcher/RequeueTask.h rename to arangod/Dispatcher/RequeueTask.h diff --git a/lib/HttpServer/ApplicationEndpointServer.cpp b/arangod/HttpServer/ApplicationEndpointServer.cpp similarity index 100% rename from lib/HttpServer/ApplicationEndpointServer.cpp rename to arangod/HttpServer/ApplicationEndpointServer.cpp diff --git a/lib/HttpServer/ApplicationEndpointServer.h b/arangod/HttpServer/ApplicationEndpointServer.h similarity index 100% rename from lib/HttpServer/ApplicationEndpointServer.h rename to arangod/HttpServer/ApplicationEndpointServer.h diff --git a/lib/HttpServer/AsyncJobManager.cpp b/arangod/HttpServer/AsyncJobManager.cpp similarity index 100% rename from lib/HttpServer/AsyncJobManager.cpp rename to arangod/HttpServer/AsyncJobManager.cpp diff --git a/lib/HttpServer/AsyncJobManager.h b/arangod/HttpServer/AsyncJobManager.h similarity index 100% rename from lib/HttpServer/AsyncJobManager.h rename to arangod/HttpServer/AsyncJobManager.h diff --git a/lib/HttpServer/HttpCommTask.cpp b/arangod/HttpServer/HttpCommTask.cpp similarity index 100% rename from lib/HttpServer/HttpCommTask.cpp rename to arangod/HttpServer/HttpCommTask.cpp diff --git a/lib/HttpServer/HttpCommTask.h b/arangod/HttpServer/HttpCommTask.h similarity index 100% rename from lib/HttpServer/HttpCommTask.h rename to arangod/HttpServer/HttpCommTask.h diff --git a/lib/HttpServer/HttpHandler.cpp b/arangod/HttpServer/HttpHandler.cpp similarity index 100% rename from lib/HttpServer/HttpHandler.cpp rename to arangod/HttpServer/HttpHandler.cpp diff --git a/lib/HttpServer/HttpHandler.h b/arangod/HttpServer/HttpHandler.h similarity index 100% rename from lib/HttpServer/HttpHandler.h rename to arangod/HttpServer/HttpHandler.h diff --git a/lib/HttpServer/HttpHandlerFactory.cpp b/arangod/HttpServer/HttpHandlerFactory.cpp similarity index 100% rename from lib/HttpServer/HttpHandlerFactory.cpp rename to arangod/HttpServer/HttpHandlerFactory.cpp diff --git a/lib/HttpServer/HttpHandlerFactory.h b/arangod/HttpServer/HttpHandlerFactory.h similarity index 100% rename from lib/HttpServer/HttpHandlerFactory.h rename to arangod/HttpServer/HttpHandlerFactory.h diff --git a/lib/HttpServer/HttpListenTask.cpp b/arangod/HttpServer/HttpListenTask.cpp similarity index 100% rename from lib/HttpServer/HttpListenTask.cpp rename to arangod/HttpServer/HttpListenTask.cpp diff --git a/lib/HttpServer/HttpListenTask.h b/arangod/HttpServer/HttpListenTask.h similarity index 100% rename from lib/HttpServer/HttpListenTask.h rename to arangod/HttpServer/HttpListenTask.h diff --git a/lib/HttpServer/HttpServer.cpp b/arangod/HttpServer/HttpServer.cpp similarity index 100% rename from lib/HttpServer/HttpServer.cpp rename to arangod/HttpServer/HttpServer.cpp diff --git a/lib/HttpServer/HttpServer.h b/arangod/HttpServer/HttpServer.h similarity index 100% rename from lib/HttpServer/HttpServer.h rename to arangod/HttpServer/HttpServer.h diff --git a/lib/HttpServer/HttpServerJob.cpp b/arangod/HttpServer/HttpServerJob.cpp similarity index 100% rename from lib/HttpServer/HttpServerJob.cpp rename to arangod/HttpServer/HttpServerJob.cpp diff --git a/lib/HttpServer/HttpServerJob.h b/arangod/HttpServer/HttpServerJob.h similarity index 100% rename from lib/HttpServer/HttpServerJob.h rename to arangod/HttpServer/HttpServerJob.h diff --git a/lib/HttpServer/HttpsCommTask.cpp b/arangod/HttpServer/HttpsCommTask.cpp similarity index 100% rename from lib/HttpServer/HttpsCommTask.cpp rename to arangod/HttpServer/HttpsCommTask.cpp diff --git a/lib/HttpServer/HttpsCommTask.h b/arangod/HttpServer/HttpsCommTask.h similarity index 100% rename from lib/HttpServer/HttpsCommTask.h rename to arangod/HttpServer/HttpsCommTask.h diff --git a/lib/HttpServer/HttpsServer.cpp b/arangod/HttpServer/HttpsServer.cpp similarity index 100% rename from lib/HttpServer/HttpsServer.cpp rename to arangod/HttpServer/HttpsServer.cpp diff --git a/lib/HttpServer/HttpsServer.h b/arangod/HttpServer/HttpsServer.h similarity index 100% rename from lib/HttpServer/HttpsServer.h rename to arangod/HttpServer/HttpsServer.h diff --git a/lib/HttpServer/PathHandler.cpp b/arangod/HttpServer/PathHandler.cpp similarity index 100% rename from lib/HttpServer/PathHandler.cpp rename to arangod/HttpServer/PathHandler.cpp diff --git a/lib/HttpServer/PathHandler.h b/arangod/HttpServer/PathHandler.h similarity index 100% rename from lib/HttpServer/PathHandler.h rename to arangod/HttpServer/PathHandler.h diff --git a/arangod/Makefile.files b/arangod/Makefile.files index 25004cf80d..704e4c73a2 100644 --- a/arangod/Makefile.files +++ b/arangod/Makefile.files @@ -15,6 +15,16 @@ arangod_libarangod_a_CPPFLAGS = \ arangod_libarangod_a_SOURCES = \ arangod/Actions/actions.cpp \ arangod/Actions/RestActionHandler.cpp \ + arangod/Admin/ApplicationAdminServer.cpp \ + arangod/Admin/RestAdminBaseHandler.cpp \ + arangod/Admin/RestAdminLogHandler.cpp \ + arangod/Admin/RestBaseHandler.cpp \ + arangod/Admin/RestDebugHelperHandler.cpp \ + arangod/Admin/RestJobHandler.cpp \ + arangod/Admin/RestShutdownHandler.cpp \ + arangod/Admin/RestVersionHandler.cpp \ + arangod/ApplicationServer/ApplicationFeature.cpp \ + arangod/ApplicationServer/ApplicationServer.cpp \ arangod/Aql/AggregationOptions.cpp \ arangod/Aql/AqlItemBlock.cpp \ arangod/Aql/AqlItemBlockManager.cpp \ @@ -63,6 +73,12 @@ arangod_libarangod_a_SOURCES = \ arangod/Cluster/ServerState.cpp \ arangod/Cluster/v8-cluster.cpp \ arangod/Cluster/ClusterMethods.cpp \ + arangod/Dispatcher/ApplicationDispatcher.cpp \ + arangod/Dispatcher/Dispatcher.cpp \ + arangod/Dispatcher/DispatcherQueue.cpp \ + arangod/Dispatcher/DispatcherThread.cpp \ + arangod/Dispatcher/Job.cpp \ + arangod/Dispatcher/RequeueTask.cpp \ arangod/FulltextIndex/fulltext-handles.cpp \ arangod/FulltextIndex/fulltext-index.cpp \ arangod/FulltextIndex/fulltext-list.cpp \ @@ -72,6 +88,17 @@ arangod_libarangod_a_SOURCES = \ arangod/GeoIndex/GeoIndex.cpp \ arangod/HashIndex/hash-array.cpp \ arangod/HashIndex/hash-array-multi.cpp \ + arangod/HttpServer/ApplicationEndpointServer.cpp \ + arangod/HttpServer/AsyncJobManager.cpp \ + arangod/HttpServer/HttpCommTask.cpp \ + arangod/HttpServer/HttpHandler.cpp \ + arangod/HttpServer/HttpHandlerFactory.cpp \ + arangod/HttpServer/HttpListenTask.cpp \ + arangod/HttpServer/HttpServer.cpp \ + arangod/HttpServer/HttpServerJob.cpp \ + arangod/HttpServer/HttpsCommTask.cpp \ + arangod/HttpServer/HttpsServer.cpp \ + arangod/HttpServer/PathHandler.cpp \ arangod/Indexes/CapConstraint.cpp \ arangod/Indexes/EdgeIndex.cpp \ arangod/Indexes/FulltextIndex.cpp \ @@ -84,6 +111,8 @@ arangod_libarangod_a_SOURCES = \ arangod/Replication/ContinuousSyncer.cpp \ arangod/Replication/InitialSyncer.cpp \ arangod/Replication/Syncer.cpp \ + arangod/Rest/AnyServer.cpp \ + arangod/Rest/Handler.cpp \ arangod/RestHandler/RestBatchHandler.cpp \ arangod/RestHandler/RestCursorHandler.cpp \ arangod/RestHandler/RestDocumentHandler.cpp \ @@ -102,7 +131,19 @@ arangod_libarangod_a_SOURCES = \ arangod/RestServer/ConsoleThread.cpp \ arangod/RestServer/VocbaseContext.cpp \ arangod/RestServer/arangod.cpp \ + arangod/Scheduler/ApplicationScheduler.cpp \ + arangod/Scheduler/ListenTask.cpp \ + arangod/Scheduler/PeriodicTask.cpp \ + arangod/Scheduler/Scheduler.cpp \ + arangod/Scheduler/SchedulerLibev.cpp \ + arangod/Scheduler/SchedulerThread.cpp \ + arangod/Scheduler/SignalTask.cpp \ + arangod/Scheduler/SocketTask.cpp \ + arangod/Scheduler/Task.cpp \ + arangod/Scheduler/TaskManager.cpp \ + arangod/Scheduler/TimerTask.cpp \ arangod/SkipLists/skiplistIndex.cpp \ + arangod/Statistics/statistics.cpp \ arangod/Utils/CollectionExport.cpp \ arangod/Utils/Cursor.cpp \ arangod/Utils/CursorRepository.cpp \ diff --git a/lib/Rest/AnyServer.cpp b/arangod/Rest/AnyServer.cpp similarity index 100% rename from lib/Rest/AnyServer.cpp rename to arangod/Rest/AnyServer.cpp diff --git a/lib/Rest/AnyServer.h b/arangod/Rest/AnyServer.h similarity index 100% rename from lib/Rest/AnyServer.h rename to arangod/Rest/AnyServer.h diff --git a/lib/Rest/Handler.cpp b/arangod/Rest/Handler.cpp similarity index 100% rename from lib/Rest/Handler.cpp rename to arangod/Rest/Handler.cpp diff --git a/lib/Rest/Handler.h b/arangod/Rest/Handler.h similarity index 99% rename from lib/Rest/Handler.h rename to arangod/Rest/Handler.h index c5e3faa5cb..d0f0fd6d74 100644 --- a/lib/Rest/Handler.h +++ b/arangod/Rest/Handler.h @@ -31,11 +31,9 @@ #define ARANGODB_REST_HANDLER_H 1 #include "Basics/Common.h" - -#include "Statistics/StatisticsAgent.h" - #include "Basics/Exceptions.h" #include "Dispatcher/Job.h" +#include "Statistics/StatisticsAgent.h" // ----------------------------------------------------------------------------- // --SECTION-- forward declarations diff --git a/lib/Rest/OperationMode.h b/arangod/Rest/OperationMode.h similarity index 100% rename from lib/Rest/OperationMode.h rename to arangod/Rest/OperationMode.h diff --git a/arangod/RestServer/arangod.cpp b/arangod/RestServer/arangod.cpp index a02bc24084..cc146f7674 100644 --- a/arangod/RestServer/arangod.cpp +++ b/arangod/RestServer/arangod.cpp @@ -30,13 +30,13 @@ #include #include "Basics/Common.h" - -#include "Basics/messages.h" -#include "Basics/logging.h" -#include "Basics/tri-strings.h" -#include "Rest/InitialiseRest.h" #include "Basics/files.h" +#include "Basics/logging.h" +#include "Basics/messages.h" +//#include "Basics/tri-strings.h" +#include "Rest/InitialiseRest.h" #include "RestServer/ArangoServer.h" +#include "Statistics/statistics.h" #include using namespace triagens; @@ -110,6 +110,8 @@ int main (int argc, char* argv[]) { // initialise sub-systems TRI_GlobalEntryFunction(); TRIAGENS_REST_INITIALISE(argc, argv); + + TRI_InitialiseStatistics(); if (startAsService) { TRI_StartService(argc, argv); @@ -133,6 +135,8 @@ int main (int argc, char* argv[]) { } ArangoInstance = nullptr; } + + TRI_ShutdownStatistics(); // shutdown sub-systems TRIAGENS_REST_SHUTDOWN; diff --git a/lib/Scheduler/ApplicationScheduler.cpp b/arangod/Scheduler/ApplicationScheduler.cpp similarity index 100% rename from lib/Scheduler/ApplicationScheduler.cpp rename to arangod/Scheduler/ApplicationScheduler.cpp diff --git a/lib/Scheduler/ApplicationScheduler.h b/arangod/Scheduler/ApplicationScheduler.h similarity index 100% rename from lib/Scheduler/ApplicationScheduler.h rename to arangod/Scheduler/ApplicationScheduler.h diff --git a/lib/Scheduler/ListenTask.cpp b/arangod/Scheduler/ListenTask.cpp similarity index 100% rename from lib/Scheduler/ListenTask.cpp rename to arangod/Scheduler/ListenTask.cpp diff --git a/lib/Scheduler/ListenTask.h b/arangod/Scheduler/ListenTask.h similarity index 100% rename from lib/Scheduler/ListenTask.h rename to arangod/Scheduler/ListenTask.h diff --git a/lib/Scheduler/PeriodicTask.cpp b/arangod/Scheduler/PeriodicTask.cpp similarity index 100% rename from lib/Scheduler/PeriodicTask.cpp rename to arangod/Scheduler/PeriodicTask.cpp diff --git a/lib/Scheduler/PeriodicTask.h b/arangod/Scheduler/PeriodicTask.h similarity index 100% rename from lib/Scheduler/PeriodicTask.h rename to arangod/Scheduler/PeriodicTask.h diff --git a/lib/Scheduler/Scheduler.cpp b/arangod/Scheduler/Scheduler.cpp similarity index 100% rename from lib/Scheduler/Scheduler.cpp rename to arangod/Scheduler/Scheduler.cpp diff --git a/lib/Scheduler/Scheduler.h b/arangod/Scheduler/Scheduler.h similarity index 100% rename from lib/Scheduler/Scheduler.h rename to arangod/Scheduler/Scheduler.h diff --git a/lib/Scheduler/SchedulerLibev.cpp b/arangod/Scheduler/SchedulerLibev.cpp similarity index 100% rename from lib/Scheduler/SchedulerLibev.cpp rename to arangod/Scheduler/SchedulerLibev.cpp diff --git a/lib/Scheduler/SchedulerLibev.h b/arangod/Scheduler/SchedulerLibev.h similarity index 100% rename from lib/Scheduler/SchedulerLibev.h rename to arangod/Scheduler/SchedulerLibev.h diff --git a/lib/Scheduler/SchedulerThread.cpp b/arangod/Scheduler/SchedulerThread.cpp similarity index 100% rename from lib/Scheduler/SchedulerThread.cpp rename to arangod/Scheduler/SchedulerThread.cpp diff --git a/lib/Scheduler/SchedulerThread.h b/arangod/Scheduler/SchedulerThread.h similarity index 100% rename from lib/Scheduler/SchedulerThread.h rename to arangod/Scheduler/SchedulerThread.h diff --git a/lib/Scheduler/SignalTask.cpp b/arangod/Scheduler/SignalTask.cpp similarity index 100% rename from lib/Scheduler/SignalTask.cpp rename to arangod/Scheduler/SignalTask.cpp diff --git a/lib/Scheduler/SignalTask.h b/arangod/Scheduler/SignalTask.h similarity index 100% rename from lib/Scheduler/SignalTask.h rename to arangod/Scheduler/SignalTask.h diff --git a/lib/Scheduler/SocketTask.cpp b/arangod/Scheduler/SocketTask.cpp similarity index 100% rename from lib/Scheduler/SocketTask.cpp rename to arangod/Scheduler/SocketTask.cpp diff --git a/lib/Scheduler/SocketTask.h b/arangod/Scheduler/SocketTask.h similarity index 100% rename from lib/Scheduler/SocketTask.h rename to arangod/Scheduler/SocketTask.h diff --git a/lib/Scheduler/Task.cpp b/arangod/Scheduler/Task.cpp similarity index 100% rename from lib/Scheduler/Task.cpp rename to arangod/Scheduler/Task.cpp diff --git a/lib/Scheduler/Task.h b/arangod/Scheduler/Task.h similarity index 100% rename from lib/Scheduler/Task.h rename to arangod/Scheduler/Task.h diff --git a/lib/Scheduler/TaskManager.cpp b/arangod/Scheduler/TaskManager.cpp similarity index 100% rename from lib/Scheduler/TaskManager.cpp rename to arangod/Scheduler/TaskManager.cpp diff --git a/lib/Scheduler/TaskManager.h b/arangod/Scheduler/TaskManager.h similarity index 100% rename from lib/Scheduler/TaskManager.h rename to arangod/Scheduler/TaskManager.h diff --git a/lib/Scheduler/TimerTask.cpp b/arangod/Scheduler/TimerTask.cpp similarity index 100% rename from lib/Scheduler/TimerTask.cpp rename to arangod/Scheduler/TimerTask.cpp diff --git a/lib/Scheduler/TimerTask.h b/arangod/Scheduler/TimerTask.h similarity index 100% rename from lib/Scheduler/TimerTask.h rename to arangod/Scheduler/TimerTask.h diff --git a/lib/Scheduler/events.h b/arangod/Scheduler/events.h similarity index 100% rename from lib/Scheduler/events.h rename to arangod/Scheduler/events.h diff --git a/lib/Statistics/StatisticsAgent.h b/arangod/Statistics/StatisticsAgent.h similarity index 100% rename from lib/Statistics/StatisticsAgent.h rename to arangod/Statistics/StatisticsAgent.h diff --git a/lib/Statistics/figures.h b/arangod/Statistics/figures.h similarity index 100% rename from lib/Statistics/figures.h rename to arangod/Statistics/figures.h diff --git a/lib/Statistics/statistics.cpp b/arangod/Statistics/statistics.cpp similarity index 92% rename from lib/Statistics/statistics.cpp rename to arangod/Statistics/statistics.cpp index 2fc4fd1b7b..db74fdebeb 100644 --- a/lib/Statistics/statistics.cpp +++ b/arangod/Statistics/statistics.cpp @@ -334,67 +334,6 @@ static TRI_thread_t StatisticsThread; // --SECTION-- private functions // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @brief gets the physical memory -//////////////////////////////////////////////////////////////////////////////// - -#if (defined(BSD) || defined(TRI_HAVE_MACOS_MEM_STATS)) - -static uint64_t GetPhysicalMemory () { - int mib[2]; - int64_t physicalMemory; - size_t length; - - // Get the Physical memory size - mib[0] = CTL_HW; -#ifdef TRI_HAVE_MACOS_MEM_STATS - mib[1] = HW_MEMSIZE; -#else - mib[1] = HW_PHYSMEM; // The bytes of physical memory. (kenel + user space) -#endif - length = sizeof(int64_t); - sysctl(mib, 2, &physicalMemory, &length, nullptr, 0); - - return (uint64_t) physicalMemory; -} - -#else -#ifdef TRI_HAVE_SC_PHYS_PAGES - -static uint64_t GetPhysicalMemory () { - long pages = sysconf(_SC_PHYS_PAGES); - long page_size = sysconf(_SC_PAGE_SIZE); - - return (uint64_t)(pages * page_size); -} - -#else -#ifdef TRI_HAVE_WIN32_GLOBAL_MEMORY_STATUS - -static uint64_t GetPhysicalMemory () { - MEMORYSTATUSEX status; - status.dwLength = sizeof(status); - GlobalMemoryStatusEx(&status); - - return (uint64_t) status.ullTotalPhys; -} - -#else - -static uint64_t TRI_GetPhysicalMemory () { - PROCESS_MEMORY_COUNTERS pmc; - memset(&result, 0, sizeof(result)); - pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS); - // http://msdn.microsoft.com/en-us/library/windows/desktop/ms684874(v=vs.85).aspx - if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, pmc.cb)) { - return pmc.PeakWorkingSetSize; - } - return 0; -} -#endif -#endif -#endif - //////////////////////////////////////////////////////////////////////////////// /// @brief checks for new statistics and process them //////////////////////////////////////////////////////////////////////////////// @@ -550,12 +489,6 @@ StatisticsDistribution* TRI_BytesReceivedDistributionStatistics; TRI_server_statistics_t TRI_ServerStatistics; -//////////////////////////////////////////////////////////////////////////////// -/// @brief physical memory -//////////////////////////////////////////////////////////////////////////////// - -uint64_t TRI_PhysicalMemory; - // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- @@ -578,7 +511,6 @@ double TRI_StatisticsTime () { void TRI_InitialiseStatistics () { TRI_ServerStatistics._startTime = TRI_microtime(); - TRI_PhysicalMemory = GetPhysicalMemory(); // ............................................................................. // sets up the statistics diff --git a/lib/Statistics/statistics.h b/arangod/Statistics/statistics.h similarity index 98% rename from lib/Statistics/statistics.h rename to arangod/Statistics/statistics.h index c5894732ab..64c36654f3 100644 --- a/lib/Statistics/statistics.h +++ b/arangod/Statistics/statistics.h @@ -308,12 +308,6 @@ extern triagens::basics::StatisticsDistribution* TRI_BytesReceivedDistributionSt extern TRI_server_statistics_t TRI_ServerStatistics; -//////////////////////////////////////////////////////////////////////////////// -/// @brief physical memory -//////////////////////////////////////////////////////////////////////////////// - -extern uint64_t TRI_PhysicalMemory; - // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- diff --git a/arangod/V8Server/v8-statistics.cpp b/arangod/V8Server/v8-statistics.cpp new file mode 100644 index 0000000000..c34c974359 --- /dev/null +++ b/arangod/V8Server/v8-statistics.cpp @@ -0,0 +1,225 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief V8 statistics functions +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2014 ArangoDB GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is ArangoDB GmbH, Cologne, Germany +/// +/// @author Dr. Frank Celler +/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany +/// @author Copyright 2011-2014, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#include "v8-statistics.h" +#include "Basics/StringUtils.h" +#include "Statistics/statistics.h" +#include "V8/v8-conv.h" +#include "V8/v8-globals.h" + +using namespace std; +using namespace triagens::arango; +using namespace triagens::basics; +using namespace triagens::httpclient; +using namespace triagens::rest; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief creates a distribution vector +//////////////////////////////////////////////////////////////////////////////// + +static v8::Handle DistributionList (v8::Isolate* isolate, + StatisticsVector const& dist) { + v8::EscapableHandleScope scope(isolate); + + v8::Handle result = v8::Array::New(isolate); + + for (uint32_t i = 0; i < (uint32_t) dist._value.size(); ++i) { + result->Set(i, v8::Number::New(isolate, dist._value[i])); + } + + return scope.Escape(result); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief fills the distribution +//////////////////////////////////////////////////////////////////////////////// + +static void FillDistribution (v8::Isolate* isolate, + v8::Handle list, + v8::Handle name, + StatisticsDistribution const& dist) { + v8::Handle result = v8::Object::New(isolate); + + result->Set(TRI_V8_ASCII_STRING("sum"), v8::Number::New(isolate, dist._total)); + result->Set(TRI_V8_ASCII_STRING("count"), v8::Number::New(isolate, (double) dist._count)); + + v8::Handle counts = v8::Array::New(isolate, (int) dist._counts.size()); + uint32_t pos = 0; + + for (vector::const_iterator i = dist._counts.begin(); i != dist._counts.end(); ++i, ++pos) { + counts->Set(pos, v8::Number::New(isolate, (double) *i)); + } + + result->Set(TRI_V8_ASCII_STRING("counts"), counts); + + list->Set(name, result); +} + +// ----------------------------------------------------------------------------- +// --SECTION-- JS functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns server statistics +/// +/// @FUN{internal.serverStatistics()} +/// +/// Returns information about the server: +/// +/// - `uptime`: time since server start in seconds. +//////////////////////////////////////////////////////////////////////////////// + +static void JS_ServerStatistics (const v8::FunctionCallbackInfo& args) { + TRI_V8_TRY_CATCH_BEGIN(isolate) + v8::HandleScope scope(isolate); + + TRI_server_statistics_t info = TRI_GetServerStatistics(); + + v8::Handle result = v8::Object::New(isolate); + + result->Set(TRI_V8_ASCII_STRING("uptime"), v8::Number::New(isolate, (double) info._uptime)); + result->Set(TRI_V8_ASCII_STRING("physicalMemory"), v8::Number::New(isolate, (double) TRI_PhysicalMemory)); + + TRI_V8_RETURN(result); + TRI_V8_TRY_CATCH_END +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns the current request and connection statistics +//////////////////////////////////////////////////////////////////////////////// + +static void JS_ClientStatistics (const v8::FunctionCallbackInfo& args) { + TRI_V8_TRY_CATCH_BEGIN(isolate) + v8::HandleScope scope(isolate); + + v8::Handle result = v8::Object::New(isolate); + + StatisticsCounter httpConnections; + StatisticsCounter totalRequests; + vector methodRequests; + StatisticsCounter asyncRequests; + StatisticsDistribution connectionTime; + + TRI_FillConnectionStatistics(httpConnections, totalRequests, methodRequests, asyncRequests, connectionTime); + + result->Set(TRI_V8_ASCII_STRING("httpConnections"), v8::Number::New(isolate, (double) httpConnections._count)); + FillDistribution(isolate, result, TRI_V8_ASCII_STRING("connectionTime"), connectionTime); + + StatisticsDistribution totalTime; + StatisticsDistribution requestTime; + StatisticsDistribution queueTime; + StatisticsDistribution ioTime; + StatisticsDistribution bytesSent; + StatisticsDistribution bytesReceived; + + TRI_FillRequestStatistics(totalTime, requestTime, queueTime, ioTime, bytesSent, bytesReceived); + + FillDistribution(isolate, result, TRI_V8_ASCII_STRING("totalTime"), totalTime); + FillDistribution(isolate, result, TRI_V8_ASCII_STRING("requestTime"), requestTime); + FillDistribution(isolate, result, TRI_V8_ASCII_STRING("queueTime"), queueTime); + FillDistribution(isolate, result, TRI_V8_ASCII_STRING("ioTime"), ioTime); + FillDistribution(isolate, result, TRI_V8_ASCII_STRING("bytesSent"), bytesSent); + FillDistribution(isolate, result, TRI_V8_ASCII_STRING("bytesReceived"), bytesReceived); + + TRI_V8_RETURN(result); + TRI_V8_TRY_CATCH_END +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns the current http statistics +//////////////////////////////////////////////////////////////////////////////// + +static void JS_HttpStatistics (const v8::FunctionCallbackInfo& args) { + TRI_V8_TRY_CATCH_BEGIN(isolate); + v8::HandleScope scope(isolate); + + v8::Handle result = v8::Object::New(isolate); + + StatisticsCounter httpConnections; + StatisticsCounter totalRequests; + vector methodRequests; + StatisticsCounter asyncRequests; + StatisticsDistribution connectionTime; + + TRI_FillConnectionStatistics(httpConnections, totalRequests, methodRequests, asyncRequests, connectionTime); + + // request counters + result->Set(TRI_V8_ASCII_STRING("requestsTotal"), v8::Number::New(isolate, (double) totalRequests._count)); + result->Set(TRI_V8_ASCII_STRING("requestsAsync"), v8::Number::New(isolate, (double) asyncRequests._count)); + result->Set(TRI_V8_ASCII_STRING("requestsGet"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_GET]._count)); + result->Set(TRI_V8_ASCII_STRING("requestsHead"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_HEAD]._count)); + result->Set(TRI_V8_ASCII_STRING("requestsPost"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_POST]._count)); + result->Set(TRI_V8_ASCII_STRING("requestsPut"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_PUT]._count)); + result->Set(TRI_V8_ASCII_STRING("requestsPatch"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_PATCH]._count)); + result->Set(TRI_V8_ASCII_STRING("requestsDelete"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_DELETE]._count)); + result->Set(TRI_V8_ASCII_STRING("requestsOptions"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_OPTIONS]._count)); + result->Set(TRI_V8_ASCII_STRING("requestsOther"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_ILLEGAL]._count)); + + TRI_V8_RETURN(result); + TRI_V8_TRY_CATCH_END +} + +// ----------------------------------------------------------------------------- +// --SECTION-- module initialisation +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief initializes the statistics functions +//////////////////////////////////////////////////////////////////////////////// + +void TRI_InitV8Statistics (v8::Isolate* isolate, + v8::Handle context) { + v8::HandleScope scope(isolate); + + // check the isolate + TRI_v8_global_t* v8g = TRI_GetV8Globals(isolate); + TRI_ASSERT(v8g != nullptr); + + // ............................................................................. + // create the global functions + // ............................................................................. + + TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_CLIENT_STATISTICS"), JS_ClientStatistics); + TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_HTTP_STATISTICS"), JS_HttpStatistics); + TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_SERVER_STATISTICS"), JS_ServerStatistics); + + TRI_AddGlobalVariableVocbase(isolate, context, TRI_V8_ASCII_STRING("CONNECTION_TIME_DISTRIBUTION"), DistributionList(isolate, TRI_ConnectionTimeDistributionVectorStatistics)); + TRI_AddGlobalVariableVocbase(isolate, context, TRI_V8_ASCII_STRING("REQUEST_TIME_DISTRIBUTION"), DistributionList(isolate, TRI_RequestTimeDistributionVectorStatistics)); + TRI_AddGlobalVariableVocbase(isolate, context, TRI_V8_ASCII_STRING("BYTES_SENT_DISTRIBUTION"), DistributionList(isolate, TRI_BytesSentDistributionVectorStatistics)); + TRI_AddGlobalVariableVocbase(isolate, context, TRI_V8_ASCII_STRING("BYTES_RECEIVED_DISTRIBUTION"), DistributionList(isolate, TRI_BytesReceivedDistributionVectorStatistics)); +} + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- + +// Local Variables: +// mode: outline-minor +// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}" +// End: diff --git a/arangod/V8Server/v8-statistics.h b/arangod/V8Server/v8-statistics.h new file mode 100644 index 0000000000..ab88bae48d --- /dev/null +++ b/arangod/V8Server/v8-statistics.h @@ -0,0 +1,56 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief V8 statistics functions +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2014 ArangoDB GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is ArangoDB GmbH, Cologne, Germany +/// +/// @author Dr. Frank Celler +/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany +/// @author Copyright 2011-2014, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ARANGODB_V8_SERVER_STATISTICS_H +#define ARANGODB_V8_SERVER_STATISTICS_H 1 + +#include "Basics/Common.h" +#include "V8/v8-globals.h" + +// ----------------------------------------------------------------------------- +// --SECTION-- GENERAL +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief initializes the statistics functions +//////////////////////////////////////////////////////////////////////////////// + +void TRI_InitV8Statistics (v8::Isolate* isolate, + v8::Handle); + +#endif + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- + +// Local Variables: +// mode: outline-minor +// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}" +// End: diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index ea4801627b..e29c071f2b 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -55,6 +55,7 @@ #include "V8/V8LineEditor.h" #include "V8Server/v8-collection.h" #include "V8Server/v8-replication.h" +#include "V8Server/v8-statistics.h" #include "V8Server/v8-voccursor.h" #include "V8Server/v8-vocindex.h" #include "V8Server/v8-wrapshapedjson.h" @@ -3835,6 +3836,8 @@ void TRI_InitV8VocBridge (v8::Isolate* isolate, TRI_AddMethodVocbase(isolate, ArangoNS, TRI_V8_ASCII_STRING("_dropDatabase"), JS_DropDatabase); TRI_AddMethodVocbase(isolate, ArangoNS, TRI_V8_ASCII_STRING("_listDatabases"), JS_ListDatabases); TRI_AddMethodVocbase(isolate, ArangoNS, TRI_V8_ASCII_STRING("_useDatabase"), JS_UseDatabase); + + TRI_InitV8Statistics(isolate, context); TRI_InitV8indexArangoDB(isolate, ArangoNS); diff --git a/lib/Basics/process-utils.cpp b/lib/Basics/process-utils.cpp index 4a9dd8d89a..657de09933 100644 --- a/lib/Basics/process-utils.cpp +++ b/lib/Basics/process-utils.cpp @@ -59,6 +59,15 @@ #include "Basics/logging.h" #include "Basics/StringUtils.h" +// ----------------------------------------------------------------------------- +// --SECTION-- global variables +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief physical memory +//////////////////////////////////////////////////////////////////////////////// + +uint64_t TRI_PhysicalMemory; // ----------------------------------------------------------------------------- // --SECTION-- private types @@ -1318,9 +1327,71 @@ bool TRI_KillExternalProcess (TRI_external_id_t pid) { TRI_RemoveVectorPointer(&ExternalProcesses, i); TRI_UnlockMutex(&ExternalProcessesLock); FreeExternal(external); + return ok; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief gets the physical memory +//////////////////////////////////////////////////////////////////////////////// + +#if (defined(BSD) || defined(TRI_HAVE_MACOS_MEM_STATS)) + +static uint64_t GetPhysicalMemory () { + int mib[2]; + int64_t physicalMemory; + size_t length; + + // Get the Physical memory size + mib[0] = CTL_HW; +#ifdef TRI_HAVE_MACOS_MEM_STATS + mib[1] = HW_MEMSIZE; +#else + mib[1] = HW_PHYSMEM; // The bytes of physical memory. (kenel + user space) +#endif + length = sizeof(int64_t); + sysctl(mib, 2, &physicalMemory, &length, nullptr, 0); + + return (uint64_t) physicalMemory; +} + +#else +#ifdef TRI_HAVE_SC_PHYS_PAGES + +static uint64_t GetPhysicalMemory () { + long pages = sysconf(_SC_PHYS_PAGES); + long page_size = sysconf(_SC_PAGE_SIZE); + + return (uint64_t)(pages * page_size); +} + +#else +#ifdef TRI_HAVE_WIN32_GLOBAL_MEMORY_STATUS + +static uint64_t GetPhysicalMemory () { + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + GlobalMemoryStatusEx(&status); + + return (uint64_t) status.ullTotalPhys; +} + +#else + +static uint64_t GetPhysicalMemory () { + PROCESS_MEMORY_COUNTERS pmc; + memset(&result, 0, sizeof(result)); + pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS); + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms684874(v=vs.85).aspx + if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, pmc.cb)) { + return pmc.PeakWorkingSetSize; + } + return 0; +} +#endif +#endif +#endif + // ----------------------------------------------------------------------------- // --SECTION-- MODULE // ----------------------------------------------------------------------------- @@ -1334,6 +1405,8 @@ bool TRI_KillExternalProcess (TRI_external_id_t pid) { //////////////////////////////////////////////////////////////////////////////// void TRI_InitialiseProcess (int argc, char* argv[]) { + TRI_PhysicalMemory = GetPhysicalMemory(); + if (ProcessName != nullptr) { return; } diff --git a/lib/Basics/process-utils.h b/lib/Basics/process-utils.h index 1a1bb54290..68421757a3 100644 --- a/lib/Basics/process-utils.h +++ b/lib/Basics/process-utils.h @@ -31,7 +31,6 @@ #define ARANGODB_BASICS_C_PROCESS__UTILS_H 1 #include "Basics/Common.h" - #include "Basics/threads.h" // ----------------------------------------------------------------------------- @@ -52,6 +51,12 @@ // --SECTION-- public types // ----------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +/// @brief physical memory +//////////////////////////////////////////////////////////////////////////////// + +extern uint64_t TRI_PhysicalMemory; + //////////////////////////////////////////////////////////////////////////////// /// @brief returns information about the process //////////////////////////////////////////////////////////////////////////////// @@ -173,11 +178,12 @@ void TRI_SetProcessTitle (char const* title); //////////////////////////////////////////////////////////////////////////////// /// @brief starts an external process //////////////////////////////////////////////////////////////////////////////// -void TRI_CreateExternalProcess (const char* executable, - const char** arguments, + +void TRI_CreateExternalProcess (char const* executable, + char const** arguments, size_t n, bool usePipes, - TRI_external_id_t * pid); + TRI_external_id_t* pid); //////////////////////////////////////////////////////////////////////////////// /// @brief returns the status of an external process diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index a8b778aee6..6e0fe388ac 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -105,19 +105,16 @@ add_library( Basics/xxhash.cpp JsonParser/json-parser.cpp ProgramOptions/program-options.cpp - Rest/AnyServer.cpp Rest/EndpointList.cpp Rest/Endpoint.cpp Rest/EndpointIp.cpp Rest/EndpointIpV4.cpp Rest/EndpointIpV6.cpp - Rest/Handler.cpp Rest/HttpRequest.cpp Rest/HttpResponse.cpp Rest/InitialiseRest.cpp Rest/SslInterface.cpp Rest/Version.cpp - Statistics/statistics.cpp Utilities/DummyShell.cpp Utilities/LineEditor.cpp Utilities/ScriptLoader.cpp @@ -143,53 +140,6 @@ add_library( SimpleHttpClient/SimpleHttpResult.cpp ) -################################################################################ -### @brief LIB_ARANGO_FE -################################################################################ - -add_library( - ${LIB_ARANGO_FE} - STATIC - Admin/ApplicationAdminServer.cpp - Admin/RestAdminBaseHandler.cpp - Admin/RestAdminLogHandler.cpp - Admin/RestBaseHandler.cpp - Admin/RestDebugHelperHandler.cpp - Admin/RestJobHandler.cpp - Admin/RestShutdownHandler.cpp - Admin/RestVersionHandler.cpp - ApplicationServer/ApplicationFeature.cpp - ApplicationServer/ApplicationServer.cpp - Dispatcher/ApplicationDispatcher.cpp - Dispatcher/Dispatcher.cpp - Dispatcher/DispatcherQueue.cpp - Dispatcher/DispatcherThread.cpp - Dispatcher/Job.cpp - Dispatcher/RequeueTask.cpp - HttpServer/ApplicationEndpointServer.cpp - HttpServer/AsyncJobManager.cpp - HttpServer/HttpCommTask.cpp - HttpServer/HttpHandler.cpp - HttpServer/HttpHandlerFactory.cpp - HttpServer/HttpListenTask.cpp - HttpServer/HttpServer.cpp - HttpServer/HttpServerJob.cpp - HttpServer/HttpsCommTask.cpp - HttpServer/HttpsServer.cpp - HttpServer/PathHandler.cpp - Scheduler/ApplicationScheduler.cpp - Scheduler/ListenTask.cpp - Scheduler/PeriodicTask.cpp - Scheduler/Scheduler.cpp - Scheduler/SchedulerLibev.cpp - Scheduler/SchedulerThread.cpp - Scheduler/SignalTask.cpp - Scheduler/SocketTask.cpp - Scheduler/Task.cpp - Scheduler/TaskManager.cpp - Scheduler/TimerTask.cpp -) - ################################################################################ ### @brief LIB_ARANGO_V8 ################################################################################ diff --git a/lib/Makefile.files b/lib/Makefile.files index 0fb44fd40c..ea1c935e47 100644 --- a/lib/Makefile.files +++ b/lib/Makefile.files @@ -77,20 +77,17 @@ lib_libarango_a_SOURCES = \ lib/Basics/xxhash.cpp \ lib/JsonParser/json-parser.cpp \ lib/ProgramOptions/program-options.cpp \ - lib/Rest/AnyServer.cpp \ lib/Rest/EndpointList.cpp \ lib/Rest/Endpoint.cpp \ lib/Rest/EndpointIp.cpp \ lib/Rest/EndpointIpV4.cpp \ lib/Rest/EndpointIpV6.cpp \ lib/Rest/EndpointUnixDomain.cpp \ - lib/Rest/Handler.cpp \ lib/Rest/HttpRequest.cpp \ lib/Rest/HttpResponse.cpp \ lib/Rest/InitialiseRest.cpp \ lib/Rest/SslInterface.cpp \ lib/Rest/Version.cpp \ - lib/Statistics/statistics.cpp \ lib/Utilities/DummyShell.cpp \ lib/Utilities/LineEditor.cpp \ lib/Utilities/ScriptLoader.cpp \ @@ -119,50 +116,6 @@ lib_libarango_client_a_SOURCES = \ lib/SimpleHttpClient/SimpleHttpResult.cpp \ lib/SimpleHttpClient/ConnectionManager.cpp -################################################################################ -### @brief library "libarango.a", front-end part -################################################################################ - -lib_libarango_fe_a_SOURCES = \ - lib/Admin/ApplicationAdminServer.cpp \ - lib/Admin/RestAdminBaseHandler.cpp \ - lib/Admin/RestAdminLogHandler.cpp \ - lib/Admin/RestBaseHandler.cpp \ - lib/Admin/RestDebugHelperHandler.cpp \ - lib/Admin/RestJobHandler.cpp \ - lib/Admin/RestShutdownHandler.cpp \ - lib/Admin/RestVersionHandler.cpp \ - lib/ApplicationServer/ApplicationFeature.cpp \ - lib/ApplicationServer/ApplicationServer.cpp \ - lib/Dispatcher/ApplicationDispatcher.cpp \ - lib/Dispatcher/Dispatcher.cpp \ - lib/Dispatcher/DispatcherQueue.cpp \ - lib/Dispatcher/DispatcherThread.cpp \ - lib/Dispatcher/Job.cpp \ - lib/Dispatcher/RequeueTask.cpp \ - lib/HttpServer/ApplicationEndpointServer.cpp \ - lib/HttpServer/AsyncJobManager.cpp \ - lib/HttpServer/HttpCommTask.cpp \ - lib/HttpServer/HttpHandler.cpp \ - lib/HttpServer/HttpHandlerFactory.cpp \ - lib/HttpServer/HttpListenTask.cpp \ - lib/HttpServer/HttpServer.cpp \ - lib/HttpServer/HttpServerJob.cpp \ - lib/HttpServer/HttpsCommTask.cpp \ - lib/HttpServer/HttpsServer.cpp \ - lib/HttpServer/PathHandler.cpp \ - lib/Scheduler/ApplicationScheduler.cpp \ - lib/Scheduler/ListenTask.cpp \ - lib/Scheduler/PeriodicTask.cpp \ - lib/Scheduler/Scheduler.cpp \ - lib/Scheduler/SchedulerLibev.cpp \ - lib/Scheduler/SchedulerThread.cpp \ - lib/Scheduler/SignalTask.cpp \ - lib/Scheduler/SocketTask.cpp \ - lib/Scheduler/Task.cpp \ - lib/Scheduler/TaskManager.cpp \ - lib/Scheduler/TimerTask.cpp - ################################################################################ ### @brief library "libarango.a", JavaScript part ################################################################################ diff --git a/lib/Rest/HttpRequest.cpp b/lib/Rest/HttpRequest.cpp index d7a104d61a..d495e573c8 100644 --- a/lib/Rest/HttpRequest.cpp +++ b/lib/Rest/HttpRequest.cpp @@ -29,7 +29,6 @@ //////////////////////////////////////////////////////////////////////////////// #include "HttpRequest.h" - #include "Basics/conversions.h" #include "Basics/logging.h" #include "Basics/StringBuffer.h" diff --git a/lib/Rest/InitialiseRest.cpp b/lib/Rest/InitialiseRest.cpp index 51dcdbe879..18922328b1 100644 --- a/lib/Rest/InitialiseRest.cpp +++ b/lib/Rest/InitialiseRest.cpp @@ -46,7 +46,6 @@ #include "Basics/threads.h" #include "Rest/HttpResponse.h" #include "Rest/Version.h" -#include "Statistics/statistics.h" // ----------------------------------------------------------------------------- // OPEN SSL support @@ -138,8 +137,6 @@ namespace triagens { void InitialiseRest (int argc, char* argv[]) { TRIAGENS_BASICS_INITIALISE(argc, argv); - TRI_InitialiseStatistics(); - SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); @@ -155,8 +152,6 @@ namespace triagens { void ShutdownRest () { opensslCleanup(); - TRI_ShutdownStatistics(); - TRIAGENS_BASICS_SHUTDOWN; } } diff --git a/lib/Rest/RequestContext.h b/lib/Rest/RequestContext.h index dc9041d706..1e673e11a1 100644 --- a/lib/Rest/RequestContext.h +++ b/lib/Rest/RequestContext.h @@ -31,7 +31,6 @@ #define ARANGODB_REST_REQUEST_CONTEXT_H 1 #include "Basics/Common.h" - #include "Rest/RequestUser.h" #include "Rest/HttpRequest.h" #include "Rest/HttpResponse.h" diff --git a/lib/SimpleHttpClient/SslClientConnection.cpp b/lib/SimpleHttpClient/SslClientConnection.cpp index 25574f8c72..7becf86653 100644 --- a/lib/SimpleHttpClient/SslClientConnection.cpp +++ b/lib/SimpleHttpClient/SslClientConnection.cpp @@ -49,7 +49,6 @@ #include "Basics/ssl-helper.h" #include "Basics/socket-utils.h" -#include "HttpServer/HttpsServer.h" #ifdef _WIN32 #define STR_ERROR() \ diff --git a/lib/V8/v8-utils.cpp b/lib/V8/v8-utils.cpp index 19ffb6d7b8..ce10037fc6 100644 --- a/lib/V8/v8-utils.cpp +++ b/lib/V8/v8-utils.cpp @@ -57,7 +57,6 @@ #include "SimpleHttpClient/GeneralClientConnection.h" #include "SimpleHttpClient/SimpleHttpClient.h" #include "SimpleHttpClient/SimpleHttpResult.h" -#include "Statistics/statistics.h" #include "V8/v8-conv.h" #include "V8/v8-globals.h" @@ -300,48 +299,6 @@ static bool LoadJavaScriptDirectory (v8::Isolate* isolate, return result; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief creates a distribution vector -//////////////////////////////////////////////////////////////////////////////// - -static v8::Handle DistributionList (v8::Isolate* isolate, - StatisticsVector const& dist) { - v8::EscapableHandleScope scope(isolate); - - v8::Handle result = v8::Array::New(isolate); - - for (uint32_t i = 0; i < (uint32_t) dist._value.size(); ++i) { - result->Set(i, v8::Number::New(isolate, dist._value[i])); - } - - return scope.Escape(result); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief fills the distribution -//////////////////////////////////////////////////////////////////////////////// - -static void FillDistribution (v8::Isolate* isolate, - v8::Handle list, - v8::Handle name, - StatisticsDistribution const& dist) { - v8::Handle result = v8::Object::New(isolate); - - result->Set(TRI_V8_ASCII_STRING("sum"), v8::Number::New(isolate, dist._total)); - result->Set(TRI_V8_ASCII_STRING("count"), v8::Number::New(isolate, (double) dist._count)); - - v8::Handle counts = v8::Array::New(isolate, (int) dist._counts.size()); - uint32_t pos = 0; - - for (vector::const_iterator i = dist._counts.begin(); i != dist._counts.end(); ++i, ++pos) { - counts->Set(pos, v8::Number::New(isolate, (double) *i)); - } - - result->Set(TRI_V8_ASCII_STRING("counts"), counts); - - list->Set(name, result); -} - // ----------------------------------------------------------------------------- // --SECTION-- JS functions // ----------------------------------------------------------------------------- @@ -2819,31 +2776,6 @@ static void JS_RemoveRecursiveDirectory (const v8::FunctionCallbackInfo& args) { - TRI_V8_TRY_CATCH_BEGIN(isolate) - v8::HandleScope scope(isolate); - - TRI_server_statistics_t info = TRI_GetServerStatistics(); - - v8::Handle result = v8::Object::New(isolate); - - result->Set(TRI_V8_ASCII_STRING("uptime"), v8::Number::New(isolate, (double) info._uptime)); - result->Set(TRI_V8_ASCII_STRING("physicalMemory"), v8::Number::New(isolate, (double) TRI_PhysicalMemory)); - - TRI_V8_RETURN(result); - TRI_V8_TRY_CATCH_END -} - //////////////////////////////////////////////////////////////////////////////// /// @brief formats the arguments /// @@ -3392,47 +3324,6 @@ static void JS_DebugCanUseFailAt (const v8::FunctionCallbackInfo& arg TRI_V8_TRY_CATCH_END } -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the current request and connection statistics -//////////////////////////////////////////////////////////////////////////////// - -static void JS_ClientStatistics (const v8::FunctionCallbackInfo& args) { - TRI_V8_TRY_CATCH_BEGIN(isolate) - v8::HandleScope scope(isolate); - - v8::Handle result = v8::Object::New(isolate); - - StatisticsCounter httpConnections; - StatisticsCounter totalRequests; - vector methodRequests; - StatisticsCounter asyncRequests; - StatisticsDistribution connectionTime; - - TRI_FillConnectionStatistics(httpConnections, totalRequests, methodRequests, asyncRequests, connectionTime); - - result->Set(TRI_V8_ASCII_STRING("httpConnections"), v8::Number::New(isolate, (double) httpConnections._count)); - FillDistribution(isolate, result, TRI_V8_ASCII_STRING("connectionTime"), connectionTime); - - StatisticsDistribution totalTime; - StatisticsDistribution requestTime; - StatisticsDistribution queueTime; - StatisticsDistribution ioTime; - StatisticsDistribution bytesSent; - StatisticsDistribution bytesReceived; - - TRI_FillRequestStatistics(totalTime, requestTime, queueTime, ioTime, bytesSent, bytesReceived); - - FillDistribution(isolate, result, TRI_V8_ASCII_STRING("totalTime"), totalTime); - FillDistribution(isolate, result, TRI_V8_ASCII_STRING("requestTime"), requestTime); - FillDistribution(isolate, result, TRI_V8_ASCII_STRING("queueTime"), queueTime); - FillDistribution(isolate, result, TRI_V8_ASCII_STRING("ioTime"), ioTime); - FillDistribution(isolate, result, TRI_V8_ASCII_STRING("bytesSent"), bytesSent); - FillDistribution(isolate, result, TRI_V8_ASCII_STRING("bytesReceived"), bytesReceived); - - TRI_V8_RETURN(result); - TRI_V8_TRY_CATCH_END -} - //////////////////////////////////////////////////////////////////////////////// /// @brief computes the PBKDF2 HMAC SHA1 derived key /// @@ -3513,40 +3404,6 @@ static void JS_HMAC (const v8::FunctionCallbackInfo& args) { TRI_V8_TRY_CATCH_END } -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the current http statistics -//////////////////////////////////////////////////////////////////////////////// - -static void JS_HttpStatistics (const v8::FunctionCallbackInfo& args) { - TRI_V8_TRY_CATCH_BEGIN(isolate); - v8::HandleScope scope(isolate); - - v8::Handle result = v8::Object::New(isolate); - - StatisticsCounter httpConnections; - StatisticsCounter totalRequests; - vector methodRequests; - StatisticsCounter asyncRequests; - StatisticsDistribution connectionTime; - - TRI_FillConnectionStatistics(httpConnections, totalRequests, methodRequests, asyncRequests, connectionTime); - - // request counters - result->Set(TRI_V8_ASCII_STRING("requestsTotal"), v8::Number::New(isolate, (double) totalRequests._count)); - result->Set(TRI_V8_ASCII_STRING("requestsAsync"), v8::Number::New(isolate, (double) asyncRequests._count)); - result->Set(TRI_V8_ASCII_STRING("requestsGet"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_GET]._count)); - result->Set(TRI_V8_ASCII_STRING("requestsHead"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_HEAD]._count)); - result->Set(TRI_V8_ASCII_STRING("requestsPost"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_POST]._count)); - result->Set(TRI_V8_ASCII_STRING("requestsPut"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_PUT]._count)); - result->Set(TRI_V8_ASCII_STRING("requestsPatch"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_PATCH]._count)); - result->Set(TRI_V8_ASCII_STRING("requestsDelete"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_DELETE]._count)); - result->Set(TRI_V8_ASCII_STRING("requestsOptions"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_OPTIONS]._count)); - result->Set(TRI_V8_ASCII_STRING("requestsOther"), v8::Number::New(isolate, (double) methodRequests[(int) HttpRequest::HTTP_REQUEST_ILLEGAL]._count)); - - TRI_V8_RETURN(result); - TRI_V8_TRY_CATCH_END -} - //////////////////////////////////////////////////////////////////////////////// /// @brief executes a external program //////////////////////////////////////////////////////////////////////////////// @@ -4536,7 +4393,6 @@ void TRI_InitV8Utils (v8::Isolate* isolate, TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_BASE64DECODE"), JS_Base64Decode); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_BASE64ENCODE"), JS_Base64Encode); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_CHECK_AND_MARK_NONCE"), JS_MarkNonce); - TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_CLIENT_STATISTICS"), JS_ClientStatistics); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_CREATE_NONCE"), JS_CreateNonce); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_DOWNLOAD"), JS_Download); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_EXECUTE"), JS_Execute); @@ -4547,7 +4403,6 @@ void TRI_InitV8Utils (v8::Isolate* isolate, TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_GEN_RANDOM_SALT"), JS_RandomSalt); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_GETLINE"), JS_Getline); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_HMAC"), JS_HMAC); - TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_HTTP_STATISTICS"), JS_HttpStatistics); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_IS_IP"), JS_IsIP); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_KILL_EXTERNAL"), JS_KillExternal); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_LOAD"), JS_Load); @@ -4565,7 +4420,6 @@ void TRI_InitV8Utils (v8::Isolate* isolate, TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_READ64"), JS_Read64); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_READ_BUFFER"), JS_ReadBuffer); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_SAVE"), JS_Save); - TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_SERVER_STATISTICS"), JS_ServerStatistics); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_SHA1"), JS_Sha1); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_SHA224"), JS_Sha224); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_SHA256"), JS_Sha256); @@ -4607,11 +4461,6 @@ void TRI_InitV8Utils (v8::Isolate* isolate, #endif TRI_AddGlobalVariableVocbase(isolate, context, TRI_V8_ASCII_STRING("VERSION"), TRI_V8_ASCII_STRING(TRI_VERSION)); - TRI_AddGlobalVariableVocbase(isolate, context, TRI_V8_ASCII_STRING("CONNECTION_TIME_DISTRIBUTION"), DistributionList(isolate, TRI_ConnectionTimeDistributionVectorStatistics)); - TRI_AddGlobalVariableVocbase(isolate, context, TRI_V8_ASCII_STRING("REQUEST_TIME_DISTRIBUTION"), DistributionList(isolate, TRI_RequestTimeDistributionVectorStatistics)); - TRI_AddGlobalVariableVocbase(isolate, context, TRI_V8_ASCII_STRING("BYTES_SENT_DISTRIBUTION"), DistributionList(isolate, TRI_BytesSentDistributionVectorStatistics)); - TRI_AddGlobalVariableVocbase(isolate, context, TRI_V8_ASCII_STRING("BYTES_RECEIVED_DISTRIBUTION"), DistributionList(isolate, TRI_BytesReceivedDistributionVectorStatistics)); - TRI_AddGlobalVariableVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_PLATFORM"), TRI_V8_ASCII_STRING(TRI_PLATFORM)); TRI_InitV8Env(isolate, context, startupPath, modules); From cb434ea863f39ee56126519eb033b3c8b22af558 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Wed, 19 Aug 2015 11:20:23 +0200 Subject: [PATCH 28/29] added derived file --- .../js/modules/org/arangodb/arango-collection-common.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/arango-collection-common.js b/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/arango-collection-common.js index 48495f4e4a..9f81df907f 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/arango-collection-common.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/arango-collection-common.js @@ -990,6 +990,9 @@ ArangoCollection.prototype.replaceByExample = function (example, newValue, waitF /// The document meta-attributes such as *_id*, *_key*, *_from*, /// *_to* cannot be updated. /// +/// Partial update could also be used to append new fields, +/// if there were no old field with same name. +/// /// `collection.updateByExample(document, newValue, keepNull, waitForSync)` /// /// The optional *keepNull* parameter can be used to modify the behavior when @@ -1020,8 +1023,9 @@ ArangoCollection.prototype.replaceByExample = function (example, newValue, waitF /// /// @EXAMPLE_ARANGOSH_OUTPUT{012_documentsCollectionUpdateByExample} /// ~ db._create("example"); -/// db.example.save({ Hello : "world" }); +/// db.example.save({ Hello : "world", foo : "bar" }); /// db.example.updateByExample({ Hello: "world" }, { Hello: "foo", World: "bar" }, false); +/// db.example.byExample({ Hello: "foo" }).toArray() /// ~ db._drop("example"); /// @END_EXAMPLE_ARANGOSH_OUTPUT /// @endDocuBlock From 6076bc632e66f4db3bad6273e91b582fef66c1f2 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Wed, 19 Aug 2015 11:37:51 +0200 Subject: [PATCH 29/29] fixed Makefile --- arangod/CMakeLists.txt | 1 + arangod/Makefile.files | 1 + arangod/V8Server/v8-statistics.cpp | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arangod/CMakeLists.txt b/arangod/CMakeLists.txt index 524e73527b..8fb358e622 100644 --- a/arangod/CMakeLists.txt +++ b/arangod/CMakeLists.txt @@ -207,6 +207,7 @@ add_executable( V8Server/v8-query.cpp V8Server/v8-replication.cpp V8Server/v8-shape-conv.cpp + V8Server/v8-statistics.cpp V8Server/v8-user-structures.cpp V8Server/v8-util.cpp V8Server/v8-vocbase.cpp diff --git a/arangod/Makefile.files b/arangod/Makefile.files index 704e4c73a2..553564b12b 100644 --- a/arangod/Makefile.files +++ b/arangod/Makefile.files @@ -165,6 +165,7 @@ arangod_libarangod_a_SOURCES = \ arangod/V8Server/v8-query.cpp \ arangod/V8Server/v8-replication.cpp \ arangod/V8Server/v8-shape-conv.cpp \ + arangod/V8Server/v8-statistics.cpp \ arangod/V8Server/v8-vocbase.cpp \ arangod/V8Server/v8-vocindex.cpp \ arangod/V8Server/v8-voccursor.cpp \ diff --git a/arangod/V8Server/v8-statistics.cpp b/arangod/V8Server/v8-statistics.cpp index c34c974359..e15167fcfd 100644 --- a/arangod/V8Server/v8-statistics.cpp +++ b/arangod/V8Server/v8-statistics.cpp @@ -28,15 +28,16 @@ //////////////////////////////////////////////////////////////////////////////// #include "v8-statistics.h" +#include "Basics/process-utils.h" #include "Basics/StringUtils.h" #include "Statistics/statistics.h" #include "V8/v8-conv.h" #include "V8/v8-globals.h" +#include "V8/v8-utils.h" using namespace std; using namespace triagens::arango; using namespace triagens::basics; -using namespace triagens::httpclient; using namespace triagens::rest; ////////////////////////////////////////////////////////////////////////////////