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 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 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/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 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/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/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/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/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/UnitTests/Makefile.unittests b/UnitTests/Makefile.unittests index f2f8ffc89b..d45ad6e8e4 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 @@ -1010,7 +1025,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" 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/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/arangod/CMakeLists.txt b/arangod/CMakeLists.txt index 07fd2d6ebf..d0e74e1cc0 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 @@ -113,6 +129,17 @@ add_executable( FulltextIndex/fulltext-wordlist.cpp GeoIndex/GeoIndex.cpp HashIndex/hash-array.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 @@ -125,6 +152,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 @@ -143,7 +172,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 @@ -165,6 +206,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/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 725da7fb77..bf3daa8872 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 \ @@ -71,6 +87,17 @@ arangod_libarangod_a_SOURCES = \ arangod/FulltextIndex/fulltext-wordlist.cpp \ arangod/GeoIndex/GeoIndex.cpp \ arangod/HashIndex/hash-array.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 \ @@ -83,6 +110,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 \ @@ -101,7 +130,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 \ @@ -123,6 +164,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/Replication/ContinuousSyncer.cpp b/arangod/Replication/ContinuousSyncer.cpp index 91e7de228d..857f4181d1 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 // ----------------------------------------------------------------------------- @@ -91,7 +72,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 +84,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; } @@ -166,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; } @@ -291,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; @@ -465,15 +440,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 +503,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 +538,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; @@ -733,27 +708,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; @@ -761,18 +749,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 @@ -782,11 +768,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; @@ -810,6 +796,9 @@ int ContinuousSyncer::applyLog (SimpleHttpResult* response, ++_applier->_state._skippedOperations; } } + + // reached the end + return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// @@ -847,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) { @@ -929,7 +920,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; } } @@ -993,8 +984,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 +995,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 +1036,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/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/RestHandler/RestReplicationHandler.cpp b/arangod/RestHandler/RestReplicationHandler.cpp index b6ce3aeada..012aff4056 100644 --- a/arangod/RestHandler/RestReplicationHandler.cpp +++ b/arangod/RestHandler/RestReplicationHandler.cpp @@ -107,12 +107,30 @@ 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; } 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()) { @@ -510,6 +528,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, 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); + } + + 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 /// @@ -1069,6 +1168,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 @@ -1093,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 95d3f85c14..84ae7bb680 100644 --- a/arangod/RestHandler/RestReplicationHandler.h +++ b/arangod/RestHandler/RestReplicationHandler.h @@ -137,12 +137,31 @@ 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 //////////////////////////////////////////////////////////////////////////////// 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/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/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-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" }); 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/V8Server/v8-statistics.cpp b/arangod/V8Server/v8-statistics.cpp new file mode 100644 index 0000000000..e15167fcfd --- /dev/null +++ b/arangod/V8Server/v8-statistics.cpp @@ -0,0 +1,226 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @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/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::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..5c3fba2bf3 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" @@ -3357,8 +3358,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 //////////////////////////////////////////////////////////////////////////////// @@ -3835,6 +3841,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/arangod/VocBase/replication-applier.cpp b/arangod/VocBase/replication-applier.cpp index a3f5ed20fb..b293cd9c3a 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 //////////////////////////////////////////////////////////////////////////////// @@ -185,6 +167,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", @@ -215,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); @@ -347,6 +333,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)) { @@ -438,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) { @@ -453,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); @@ -472,9 +463,19 @@ static int SetError (TRI_replication_applier_t* applier, //////////////////////////////////////////////////////////////////////////////// static void ApplyThread (void* data) { - triagens::arango::ContinuousSyncer* s = static_cast(data); - s->run(); - delete s; + auto syncer = static_cast(data); + + // get number of running remote transactions so we can forge the transaction + // statistics + int const n = static_cast(syncer->applier()->_runningRemoteTransactions.size()); + triagens::arango::TransactionBase::setNumbers(n, n); + + try { + syncer->run(); + } + catch (...) { + } + delete syncer; } //////////////////////////////////////////////////////////////////////////////// @@ -488,6 +489,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; } @@ -501,15 +503,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) { @@ -522,17 +520,17 @@ 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); - 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); @@ -554,7 +552,7 @@ static int StopApplier (TRI_replication_applier_t* applier, state->_active = false; - SetTerminateFlag(applier, true); + applier->setTermination(true); TRI_SetProgressReplicationApplier(applier, "applier stopped", false); @@ -586,7 +584,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); @@ -733,7 +731,7 @@ TRI_replication_applier_t* TRI_CreateReplicationApplier (TRI_server_t* server, } } - SetTerminateFlag(applier, false); + applier->setTermination(false); TRI_ASSERT(applier->_databaseName != nullptr); @@ -742,58 +740,10 @@ 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); - - 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 // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @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); - -#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 //////////////////////////////////////////////////////////////////////////////// @@ -818,7 +768,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); @@ -870,7 +820,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); @@ -920,7 +870,7 @@ int TRI_ShutdownReplicationApplier (TRI_replication_applier_t* applier) { } } - SetTerminateFlag(applier, false); + applier->setTermination(false); { WRITE_LOCKER(applier->_statusLock); @@ -1288,21 +1238,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 +1326,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; } @@ -1462,6 +1414,86 @@ 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); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @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 f927d1f5ed..e9a54a2791 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; } @@ -112,24 +113,23 @@ 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 (); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief pauses and checks whether the apply thread should terminate +//////////////////////////////////////////////////////////////////////////////// + + bool wait (uint64_t); + + bool isTerminated () { + return _terminateThread.load(); } - - ~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); + + void setTermination (bool value) { + _terminateThread.store(value); } void addRemoteTransaction (triagens::arango::ReplicationTransaction* trx) { @@ -173,29 +173,10 @@ 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 // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @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 //////////////////////////////////////////////////////////////////////////////// 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..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 //////////////////////////////////////////////////////////////////////////////// @@ -1363,8 +1392,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); - size_t const n = logfiles.size(); + bool fromTickIncluded = false; + std::vector logfiles = triagens::wal::LogfileManager::instance()->getLogfilesForTickRange(tickMin, tickMax, fromTickIncluded); // setup some iteration state int res = TRI_ERROR_NO_ERROR; @@ -1377,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]; @@ -1415,7 +1446,6 @@ int TRI_DumpLogReplication (TRI_replication_dump_t* dump, } if (! MustReplicateWalMarker(dump, marker)) { - // check if we can abort searching continue; } @@ -1463,6 +1493,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 @@ -1481,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 cb18d14964..6e90caddcd 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; }; // ----------------------------------------------------------------------------- @@ -130,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/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/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; diff --git a/arangod/Wal/LogfileManager.cpp b/arangod/Wal/LogfileManager.cpp index e001d00e12..c8941bf5f7 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; } @@ -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 @@ -1318,7 +1325,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 +1394,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 +1420,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 +1438,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 +1545,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 +2031,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 +2048,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..32758ea64f 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 // ----------------------------------------------------------------------------- @@ -558,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 @@ -594,6 +617,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 +660,12 @@ namespace triagens { LogfileManagerState state (); +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the current available logfile ranges +//////////////////////////////////////////////////////////////////////////////// + + LogfileRanges ranges (); + // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- @@ -642,11 +673,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 diff --git a/arangosh/V8Client/arangodump.cpp b/arangosh/V8Client/arangodump.cpp index 2189193e2b..b5cea3ca6e 100644 --- a/arangosh/V8Client/arangodump.cpp +++ b/arangosh/V8Client/arangodump.cpp @@ -48,6 +48,11 @@ #include "SimpleHttpClient/SimpleHttpClient.h" #include "SimpleHttpClient/SimpleHttpResult.h" +#ifdef TRI_FILESYSTEM_CASE_BROKEN +#include +#else +#define hexStr "" +#endif using namespace std; using namespace triagens::basics; @@ -500,7 +505,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 +721,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 +732,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) { @@ -788,6 +841,21 @@ static int RunDump (string& errorMsg) { continue; } +#ifdef TRI_FILESYSTEM_CASE_BROKEN + 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; @@ -798,8 +866,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 + hexStr + ".structure.json"; int fd; @@ -834,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; @@ -866,6 +933,9 @@ static int RunDump (string& errorMsg) { return res; } } +#ifdef TRI_FILESYSTEM_CASE_BROKEN + TRI_Free(TRI_CORE_MEM_ZONE, hexStr); +#endif } @@ -1159,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 TRI_FILESYSTEM_CASE_BROKEN + 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 TRI_FILESYSTEM_CASE_BROKEN + TRI_Free(TRI_CORE_MEM_ZONE, hexStr); +#endif int fd; diff --git a/arangosh/V8Client/arangorestore.cpp b/arangosh/V8Client/arangorestore.cpp index c1da9131f2..dec0054d33 100644 --- a/arangosh/V8Client/arangorestore.cpp +++ b/arangosh/V8Client/arangorestore.cpp @@ -48,6 +48,12 @@ #include "SimpleHttpClient/SimpleHttpClient.h" #include "SimpleHttpClient/SimpleHttpResult.h" +#ifdef TRI_FILESYSTEM_CASE_BROKEN +#include +#else +#define hexStr "" +#endif + using namespace std; using namespace triagens::basics; using namespace triagens::httpclient; @@ -653,12 +659,21 @@ 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; } +#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 && restrictList.find(name) == restrictList.end()) { // collection name not in list @@ -766,7 +781,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"; +#ifdef TRI_FILESYSTEM_CASE_BROKEN + 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"; +#ifdef TRI_FILESYSTEM_CASE_BROKEN + TRI_Free(TRI_CORE_MEM_ZONE, hexStr); +#endif if (TRI_ExistsFile(datafile.c_str())) { // found a datafile diff --git a/arangosh/V8Client/arangosh.cpp b/arangosh/V8Client/arangosh.cpp index c0a49c8be7..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 @@ -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/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/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 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/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 diff --git a/js/server/modules/org/arangodb/foxx/controller.js b/js/server/modules/org/arangodb/foxx/controller.js index 287f170f31..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') { @@ -275,7 +253,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 +395,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 +424,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 +453,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 +482,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 +511,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 +540,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 +574,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 +621,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 +655,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 +700,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 @@ -710,33 +733,9 @@ class Controller { } //////////////////////////////////////////////////////////////////////////////// -/// @startDocuBlock JSF_foxx_controller_activateSessions -/// -/// `FoxxController#activateAuthentication(opts)` -/// -/// To activate sessions for this sessions, first call this function. -/// Provide the following arguments: -/// -/// * *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) { var sessions = require('org/arangodb/foxx/sessions'); _.extend(this, sessionControllerProps); @@ -748,11 +747,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,17 +818,64 @@ 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) { + 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/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}":` diff --git a/js/server/modules/org/arangodb/foxx/request_context.js b/js/server/modules/org/arangodb/foxx/request_context.js index 21fa5fb861..e3eed76593 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,13 +140,21 @@ class RequestContext { this[attr] = extensionWrapper(this, extensions[attr]); } } + executionBuffer.applyEachFunction(this); } //////////////////////////////////////////////////////////////////////////////// /// @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) { 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) { 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 //////////////////////////////////////////////////////////////////////////////// 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 //////////////////////////////////////////////////////////////////////////////// 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/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 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/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 /// diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 040b405e70..6e0fe388ac 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -105,22 +105,19 @@ 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/ScriptLoader.cpp - Utilities/ShellImplementation.cpp + Utilities/DummyShell.cpp Utilities/LineEditor.cpp + Utilities/ScriptLoader.cpp Utilities/ShellImplementation.cpp Utilities/ShellImplFactory.cpp Zip/ioapi.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 694fb4f3a1..33119b53d9 100644 --- a/lib/Makefile.files +++ b/lib/Makefile.files @@ -78,20 +78,18 @@ 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 \ lib/Utilities/ShellImplFactory.cpp \ @@ -105,10 +103,6 @@ if ENABLE_READLINE lib_libarango_a_SOURCES += \ lib/Utilities/ReadlineShell.cpp -else - -lib_libarango_a_SOURCES += \ - lib/Utilities/DummyShell.cpp endif ################################################################################ @@ -123,50 +117,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/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.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; 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 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);