mirror of https://gitee.com/bigwinds/arangodb
Merge remote-tracking branch 'origin/devel' into array_indexing
This commit is contained in:
commit
b708a7ae68
|
@ -0,0 +1 @@
|
|||
*.sh eol=lf
|
|
@ -14,6 +14,9 @@ js-*.h
|
|||
*.gcno
|
||||
*.gcda
|
||||
|
||||
*.diff
|
||||
*.patch
|
||||
|
||||
.libev-build-64
|
||||
.v8-build-64
|
||||
.idea
|
||||
|
@ -31,6 +34,7 @@ js-*.h
|
|||
3rdParty/zlib-1.2.7/
|
||||
|
||||
Build*
|
||||
WindowsLibraries
|
||||
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
|
|
@ -1693,7 +1693,9 @@ def _DictsToFolders(base_path, bucket, flat):
|
|||
children += folder_children
|
||||
else:
|
||||
folder_children = MSVSNew.MSVSFolder(os.path.join(base_path, folder),
|
||||
name='(' + folder + ')',
|
||||
# parentheses not supported by msbuild target parameter /t
|
||||
# name='(' + folder + ')',
|
||||
name=folder,
|
||||
entries=folder_children)
|
||||
children.append(folder_children)
|
||||
else:
|
||||
|
@ -1967,7 +1969,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
sln_projects += gyp.common.DeepDependencyTargets(target_dicts, sln_projects)
|
||||
# Create folder hierarchy.
|
||||
root_entries = _GatherSolutionFolders(
|
||||
sln_projects, project_objects, flat=msvs_version.FlatSolution())
|
||||
# ArangoDB V8 build script expects flat solution
|
||||
# sln_projects, project_objects, flat=msvs_version.FlatSolution())
|
||||
sln_projects, project_objects, flat=True)
|
||||
# Create solution.
|
||||
sln = MSVSNew.MSVSSolution(sln_path,
|
||||
entries=root_entries,
|
||||
|
|
|
@ -42,7 +42,7 @@ echo %CMD%
|
|||
|
||||
cd V8-%V8_VERSION%
|
||||
|
||||
set PATH=.\third_party\python_26\;%PATH%
|
||||
set PATH=%~dp0V8-%V8_VERSION%\third_party\python_26;%PATH%
|
||||
.\third_party\python_26\python.exe build\gyp_v8 %CMD%
|
||||
|
||||
cd build
|
||||
|
|
21
CHANGELOG
21
CHANGELOG
|
@ -1,6 +1,27 @@
|
|||
v2.7.0 (XXXX-XX-XX)
|
||||
-------------------
|
||||
|
||||
* IMPORTANT CHANGE: the filenames in dumps created by arangodump now contain
|
||||
not only the name of the dumped collection, but also an additional 32-digit hash
|
||||
value. This is done to prevent overwriting dump files in case-insensitive file
|
||||
systems when there exist multiple collections with the same name (but with
|
||||
different cases).
|
||||
|
||||
For example, if a database has two collections: `test` and `Test`, previous
|
||||
versions of ArangoDB created the files
|
||||
|
||||
* `test.structure.json` and `test.data.json` for collection `test`
|
||||
* `Test.structure.json` and `Test.data.json` for collection `Test`
|
||||
|
||||
This did not work for case-insensitive filesystems, because the files for the
|
||||
second collection would have overwritten the files of the first. arangodump in
|
||||
2.7 will create the following filenames instead:
|
||||
|
||||
* `test_098f6bcd4621d373cade4e832627b4f6.structure.json` and `test_098f6bcd4621d373cade4e832627b4f6.data.json`
|
||||
* `Test_0cbc6611f5540bd0809a388dc95a615b.structure.json` and `Test_0cbc6611f5540bd0809a388dc95a615b.data.json`
|
||||
|
||||
These filenames will be unambiguous even in case-insensitive filesystems.
|
||||
|
||||
* IMPORTANT CHANGE: make arangod actually close lingering client connections
|
||||
when idle for at least the duration specified via `--server.keep-alive-timeout`.
|
||||
In previous versions of ArangoDB, connections were not closed by the server
|
||||
|
|
|
@ -49,7 +49,6 @@ build-book:
|
|||
cd ppbooks/$(NAME); test -L SUMMARY.md || ln -s ../../$(NAME)/SUMMARY.md .
|
||||
cd ppbooks/$(NAME); test -L book.json || ln -s ../../$(NAME)/book.json .
|
||||
cd ppbooks/$(NAME); cp -a ../../$(NAME)/styles/* styles/
|
||||
cd ppbooks/$(NAME) && sed -ie 's/VERSION_NUMBER/$(newVersionNumber)/g' styles/header.js
|
||||
WD=`pwd`; \
|
||||
for pic in `find $(NAME) -name \*.png`; do \
|
||||
cd $${WD}/ppbooks; \
|
||||
|
@ -59,6 +58,10 @@ build-book:
|
|||
done
|
||||
python generateMdFiles.py $(NAME) ppbooks/
|
||||
|
||||
cd ppbooks/$(NAME) && sed -ie 's/VERSION_NUMBER/v$(newVersionNumber)/g' styles/header.js
|
||||
cd ppbooks/$(NAME) && sed -ie 's/VERSION_NUMBER/v$(newVersionNumber)/g' README.md
|
||||
cd ppbooks/$(NAME) && sed -ie 's/VERSION_NUMBER/v$(newVersionNumber)/g' book.json
|
||||
|
||||
test -d books/$(NAME) || mkdir -p books/$(NAME)
|
||||
|
||||
cd ppbooks/$(NAME) && gitbook install
|
||||
|
|
|
@ -10,43 +10,206 @@ It is required that subqueries be put inside parentheses *(* and *)* to
|
|||
explicitly mark their start and end points:
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
FOR p IN persons
|
||||
LET recommendations = (
|
||||
FOR r IN recommendations
|
||||
FILTER u.id == r.userId
|
||||
SORT u.rank DESC
|
||||
FILTER p.id == r.personId
|
||||
SORT p.rank DESC
|
||||
LIMIT 10
|
||||
RETURN r
|
||||
)
|
||||
RETURN { "user" : u, "recommendations" : recommendations }
|
||||
RETURN { person : p, recommendations : recommendations }
|
||||
```
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
COLLECT city = u.city INTO g
|
||||
RETURN { "city" : city, "numUsers" : LENGTH(g), "maxRating": MAX(
|
||||
FOR r IN g
|
||||
RETURN r.user.rating
|
||||
)}
|
||||
FOR p IN persons
|
||||
COLLECT city = p.city INTO g
|
||||
RETURN {
|
||||
city : city,
|
||||
numPersons : LENGTH(g),
|
||||
maxRating: MAX(
|
||||
FOR r IN g
|
||||
RETURN r.p.rating
|
||||
)}
|
||||
```
|
||||
|
||||
Subqueries may also include other subqueries themselves.
|
||||
Subqueries may also include other subqueries.
|
||||
|
||||
!SUBSECTION Variable expansion
|
||||
!SUBSECTION Array expansion
|
||||
|
||||
In order to access a named attribute from all elements in an array easily, AQL
|
||||
offers the shortcut operator <i>[\*]</i> for variable expansion.
|
||||
offers the shortcut operator <i>[\*]</i> for array variable expansion.
|
||||
|
||||
Using the <i>[\*]</i> operator with a variable will iterate over all elements in the
|
||||
variable thus allowing to access a particular attribute of each element. It is
|
||||
Using the <i>[\*]</i> operator with an array variable will iterate over all elements
|
||||
in the array, thus allowing to access a particular attribute of each element. It is
|
||||
required that the expanded variable is an array. The result of the <i>[\*]</i>
|
||||
operator is again an array.
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
RETURN { "user" : u, "friendNames" : u.friends[*].name }
|
||||
To demonstrate the array expansion operator, let's go on with the following three
|
||||
example *users* documents:
|
||||
|
||||
```
|
||||
[
|
||||
{
|
||||
name: "john",
|
||||
age: 35,
|
||||
friends: [
|
||||
{ name: "tina", age: 43 },
|
||||
{ name: "helga", age: 52 },
|
||||
{ name: "alfred", age: 34 }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "yves",
|
||||
age: 24,
|
||||
friends: [
|
||||
{ name: "sergei", age: 27 },
|
||||
{ name: "tiffany", age: 25 }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "sandra",
|
||||
age: 40,
|
||||
friends: [
|
||||
{ name: "bob", age: 32 },
|
||||
{ name: "elena", age: 48 }
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
In the above example, the attribute *name* is accessed for each element in the
|
||||
array *u.friends*. The result is a flat array of friend names, made available as
|
||||
the attribute *friendNames*.
|
||||
With the <i>[\*]</i> operator it becomes easy to query just the names of the
|
||||
friends for each user:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
RETURN { name: u.name, friends: u.friends[*].name }
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```
|
||||
[
|
||||
{ "name" : "john", "friends" : [ "tina", "helga", "alfred" ] },
|
||||
{ "name" : "yves", "friends" : [ "sergei", "tiffany" ] },
|
||||
{ "name" : "sandra", "friends" : [ "bob", "elena" ] }
|
||||
]
|
||||
```
|
||||
|
||||
This a shortcut for the longer, semantically equivalent query:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
RETURN { name: u.name, friends: (FOR f IN u.friends RETURN f.name) }
|
||||
```
|
||||
|
||||
While producing a result with the <i>[\*]</i> operator, it is also possible
|
||||
to filter while iterating over the array, and to create a projection using the
|
||||
current array element.
|
||||
|
||||
For example, to return only the names of friends that have an *age* value
|
||||
higher than the user herself an inline *FILTER* can be used:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
RETURN { name: u.name, friends: u.friends[* FILTER CURRENT.age > u.age].name }
|
||||
```
|
||||
|
||||
The pseudo-variable *CURRENT* can be used to access the current array element.
|
||||
The *FILTER* condition can refer to *CURRENT* or any variables valid in the
|
||||
outer scope.
|
||||
|
||||
To return a projection of the current element, use *RETURN*. If a *FILTER* is
|
||||
also present, *RETURN* must come later.
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
RETURN u.friends[* RETURN CONCAT(CURRENT.name, " is a friend of ", u.name) ]
|
||||
```
|
||||
|
||||
The above will return:
|
||||
|
||||
```
|
||||
[
|
||||
[
|
||||
"tina is a friend of john",
|
||||
"helga is a friend of john",
|
||||
"alfred is a friend of john"
|
||||
],
|
||||
[
|
||||
"sergei is a friend of yves",
|
||||
"tiffany is a friend of yves"
|
||||
],
|
||||
[
|
||||
"bob is a friend of sandra",
|
||||
"elena is a friend of sandra"
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
!SUBSECTION Array contraction
|
||||
|
||||
In order to collapse (or flatten) results in nested arrays, AQL provides the <i>[\*\*]</i>
|
||||
operator. It works similar to the <i>[\*]</i> operator, but additionally collapses nested
|
||||
arrays. How many levels are collapsed is determined by the amount of <i>\*</i> characters used.
|
||||
|
||||
For example, the following query produces an array of friend names per user:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
RETURN u.friends[*].name
|
||||
```
|
||||
|
||||
As we have multiple users, the overall result is a nested array:
|
||||
|
||||
```
|
||||
[
|
||||
[
|
||||
"tina",
|
||||
"helga",
|
||||
"alfred"
|
||||
],
|
||||
[
|
||||
"sergei",
|
||||
"tiffany"
|
||||
],
|
||||
[
|
||||
"bob",
|
||||
"elena"
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
If the goal is to get rid of the nested array, we can apply the <i>[\*\*]</i> operator on the
|
||||
result. Simplying appending <i>[\*\*]</i> to the query won't help, because *u.friends*
|
||||
is not a nested (multi-dimensional) array, but a simple (one-dimensional) array. Still,
|
||||
the <i>[\*\*]</i> can be used if it has access to a multi-dimensional nested result.
|
||||
|
||||
We can easily create a nested result like this:
|
||||
|
||||
```
|
||||
RETURN (
|
||||
FOR u IN users RETURN u.friends[*].name
|
||||
)
|
||||
```
|
||||
|
||||
By now appending the <i>[\*\*]</i> operator the end of the query, the query result becomes:
|
||||
```
|
||||
RETURN (
|
||||
FOR u IN users RETURN u.friends[*].name
|
||||
)[**]
|
||||
```
|
||||
|
||||
```
|
||||
[
|
||||
[
|
||||
"tina",
|
||||
"helga",
|
||||
"alfred",
|
||||
"sergei",
|
||||
"tiffany",
|
||||
"bob",
|
||||
"elena"
|
||||
]
|
||||
]
|
||||
```
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
An AQL query must either return a result (indicated by usage of the *RETURN*
|
||||
keyword) or execute a data-modification operation (indicated by usage
|
||||
of one of the keywords *INSERT*, *UPDATE*, *REPLACE* or *REMOVE*). The AQL
|
||||
of one of the keywords *INSERT*, *UPDATE*, *REPLACE*, *REMOVE* or *UPSERT*). The AQL
|
||||
parser will return an error if it detects more than one data-modification
|
||||
operation in the same query or if it cannot figure out if the query is meant
|
||||
to be a data retrieval or a modification operation.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
!BOOK ArangoDB Documentation
|
||||
!BOOK ArangoDB VERSION_NUMBER Documentation
|
||||
|
||||
Welcome to the ArangoDB documentation!
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"gitbook": ">=2.0.0",
|
||||
"title": "ArangoDB Documentation",
|
||||
"title": "ArangoDB VERSION_NUMBER Documentation",
|
||||
"language": "en",
|
||||
"plugins":["expandable-chapters", "addcssjs"],
|
||||
"pdf": {
|
||||
|
|
|
@ -74,7 +74,6 @@ examples:
|
|||
@srcdir@/Documentation/Books/Users \
|
||||
@srcdir@/arangod/RestHandler \
|
||||
@srcdir@/arangod/V8Server \
|
||||
@srcdir@/lib/Admin \
|
||||
> /tmp/arangosh.examples.js
|
||||
|
||||
if test -z "$(server.endpoint)"; then \
|
||||
|
|
|
@ -56,8 +56,8 @@ files = {
|
|||
"graph" : [ "js/actions/api-graph.js" ],
|
||||
"import" : [ "arangod/RestHandler/RestImportHandler.cpp" ],
|
||||
"index" : [ "js/actions/api-index.js" ],
|
||||
"job" : [ "lib/HttpServer/AsyncJobManager.h" ],
|
||||
"log" : [ "lib/Admin/RestAdminLogHandler.cpp" ],
|
||||
"job" : [ "arangod/HttpServer/AsyncJobManager.h" ],
|
||||
"log" : [ "arangod/RestHandler/RestAdminLogHandler.cpp" ],
|
||||
"query" : [ "arangod/RestHandler/RestQueryHandler.cpp" ],
|
||||
"replication" : [ "arangod/RestHandler/RestReplicationHandler.cpp" ],
|
||||
"simple" : [ "js/actions/api-simple.js", "arangod/RestHandler/RestSimpleHandler.cpp" ],
|
||||
|
@ -67,7 +67,7 @@ files = {
|
|||
"transaction" : [ "js/actions/api-transaction.js" ],
|
||||
"traversal" : [ "js/actions/api-traversal.js" ],
|
||||
"user" : [ "js/actions/_api/user/app.js" ],
|
||||
"version" : [ "lib/Admin/RestVersionHandler.cpp" ],
|
||||
"version" : [ "arangod/RestHandler/RestVersionHandler.cpp" ],
|
||||
"wal" : [ "js/actions/_admin/wal/app.js" ]
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ ${SRCDIR}/Installation/file-list-js.sh ${SRCDIR} | while read a; do
|
|||
TO="${DSTDIR}/$a"
|
||||
DIR=`dirname "${TO}"`
|
||||
|
||||
chmod a+r "${FROM}"
|
||||
test -d "${DIR}" || mkdir -p "${DIR}"
|
||||
cp -n "${FROM}" "${TO}"
|
||||
done
|
||||
|
|
|
@ -28,17 +28,16 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "ApplicationAdminServer.h"
|
||||
|
||||
#include "Admin/RestAdminLogHandler.h"
|
||||
#include "Admin/RestHandlerCreator.h"
|
||||
#include "Admin/RestJobHandler.h"
|
||||
#include "Basics/ProgramOptionsDescription.h"
|
||||
#include "Basics/logging.h"
|
||||
#include "Basics/ProgramOptionsDescription.h"
|
||||
#include "HttpServer/HttpHandlerFactory.h"
|
||||
#include "HttpServer/PathHandler.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
#include "Admin/RestVersionHandler.h"
|
||||
#include "Admin/RestDebugHelperHandler.h"
|
||||
#include "RestHandler/RestAdminLogHandler.h"
|
||||
#include "RestHandler/RestDebugHelperHandler.h"
|
||||
#include "RestHandler/RestJobHandler.h"
|
||||
#include "RestHandler/RestHandlerCreator.h"
|
||||
#include "RestHandler/RestVersionHandler.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace triagens;
|
||||
|
@ -69,9 +68,7 @@ static bool UnusedDisableAdminInterface;
|
|||
|
||||
ApplicationAdminServer::ApplicationAdminServer ()
|
||||
: ApplicationFeature("admin"),
|
||||
_allowLogViewer(false),
|
||||
_pathOptions(nullptr),
|
||||
_jobPayload(nullptr) {
|
||||
_pathOptions(nullptr) {
|
||||
|
||||
_pathOptions = new PathHandler::Options();
|
||||
}
|
||||
|
@ -81,59 +78,7 @@ ApplicationAdminServer::ApplicationAdminServer ()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ApplicationAdminServer::~ApplicationAdminServer () {
|
||||
delete _jobPayload;
|
||||
delete reinterpret_cast<PathHandler::Options*>(_pathOptions);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a log viewer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ApplicationAdminServer::allowLogViewer () {
|
||||
_allowLogViewer = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds the http handlers
|
||||
///
|
||||
/// Note that the server does not claim ownership of the factory.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ApplicationAdminServer::addBasicHandlers (HttpHandlerFactory* factory,
|
||||
string const& prefix,
|
||||
Dispatcher* dispatcher,
|
||||
AsyncJobManager* jobManager) {
|
||||
factory->addHandler(prefix + "/version", RestHandlerCreator<RestVersionHandler>::createNoData, 0);
|
||||
factory->addHandler(prefix + "/debug-helper", RestHandlerCreator<RestDebugHelperHandler>::createNoData, 0);
|
||||
|
||||
if (_jobPayload == nullptr) {
|
||||
_jobPayload = new pair<Dispatcher*, AsyncJobManager*>(dispatcher, jobManager);
|
||||
}
|
||||
|
||||
factory->addPrefixHandler(prefix + "/job",
|
||||
RestHandlerCreator<RestJobHandler>::createData< pair<Dispatcher*, AsyncJobManager*>* >,
|
||||
_jobPayload);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds the http handlers for administration
|
||||
///
|
||||
/// Note that the server does not claim ownership of the factory.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ApplicationAdminServer::addHandlers (HttpHandlerFactory* factory, string const& prefix) {
|
||||
|
||||
// .............................................................................
|
||||
// add log viewer
|
||||
// .............................................................................
|
||||
|
||||
if (_allowLogViewer) {
|
||||
factory->addHandler(prefix + "/log", RestHandlerCreator<RestAdminLogHandler>::createNoData, 0);
|
||||
}
|
||||
delete _pathOptions;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
#define ARANGODB_ADMIN_APPLICATION_ADMIN_SERVER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "ApplicationServer/ApplicationFeature.h"
|
||||
#include "HttpServer/PathHandler.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- forward declarations
|
||||
|
@ -81,38 +81,6 @@ namespace triagens {
|
|||
|
||||
~ApplicationAdminServer ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a log viewer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void allowLogViewer ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds the http handlers
|
||||
///
|
||||
/// Note that the server does not claim ownership of the factory.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void addBasicHandlers (rest::HttpHandlerFactory*,
|
||||
std::string const &prefix,
|
||||
rest::Dispatcher*,
|
||||
rest::AsyncJobManager*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds the http handlers for administration
|
||||
///
|
||||
/// Note that the server does not claim ownership of the factory.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void addHandlers (rest::HttpHandlerFactory*,
|
||||
std::string const& prefix);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- ApplicationFeature methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -143,23 +111,11 @@ namespace triagens {
|
|||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief allow log viewer requests
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _allowLogViewer;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief path options for the admin directory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void* _pathOptions;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief data that needs to be freed at shutdown
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::pair<rest::Dispatcher*, rest::AsyncJobManager*>* _jobPayload;
|
||||
triagens::rest::PathHandler::Options* _pathOptions;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ AstNode const Ast::ZeroNode{ static_cast<int64_t>(0), VALUE_TYPE_INT };
|
|||
/// @brief initialise a singleton empty string node instance
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode const Ast::EmptyStringNode{ "", VALUE_TYPE_STRING };
|
||||
AstNode const Ast::EmptyStringNode{ "", 0, VALUE_TYPE_STRING };
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief inverse comparison operators
|
||||
|
@ -225,6 +225,7 @@ AstNode* Ast::createNodeExample (AstNode const* variable,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeFor (char const* variableName,
|
||||
size_t nameLength,
|
||||
AstNode const* expression,
|
||||
bool isUserDefinedVariable) {
|
||||
if (variableName == nullptr) {
|
||||
|
@ -233,7 +234,7 @@ AstNode* Ast::createNodeFor (char const* variableName,
|
|||
|
||||
AstNode* node = createNode(NODE_TYPE_FOR);
|
||||
|
||||
AstNode* variable = createNodeVariable(variableName, isUserDefinedVariable);
|
||||
AstNode* variable = createNodeVariable(variableName, nameLength, isUserDefinedVariable);
|
||||
node->addMember(variable);
|
||||
node->addMember(expression);
|
||||
|
||||
|
@ -245,6 +246,7 @@ AstNode* Ast::createNodeFor (char const* variableName,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeLet (char const* variableName,
|
||||
size_t nameLength,
|
||||
AstNode const* expression,
|
||||
bool isUserDefinedVariable) {
|
||||
if (variableName == nullptr) {
|
||||
|
@ -253,7 +255,7 @@ AstNode* Ast::createNodeLet (char const* variableName,
|
|||
|
||||
AstNode* node = createNode(NODE_TYPE_LET);
|
||||
|
||||
AstNode* variable = createNodeVariable(variableName, isUserDefinedVariable);
|
||||
AstNode* variable = createNodeVariable(variableName, nameLength, isUserDefinedVariable);
|
||||
node->addMember(variable);
|
||||
node->addMember(expression);
|
||||
|
||||
|
@ -282,6 +284,7 @@ AstNode* Ast::createNodeLet (AstNode const* variable,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeLet (char const* variableName,
|
||||
size_t nameLength,
|
||||
AstNode const* expression,
|
||||
AstNode const* condition) {
|
||||
if (variableName == nullptr) {
|
||||
|
@ -290,7 +293,7 @@ AstNode* Ast::createNodeLet (char const* variableName,
|
|||
|
||||
AstNode* node = createNode(NODE_TYPE_LET);
|
||||
|
||||
AstNode* variable = createNodeVariable(variableName, true);
|
||||
AstNode* variable = createNodeVariable(variableName, nameLength, true);
|
||||
node->addMember(variable);
|
||||
node->addMember(expression);
|
||||
node->addMember(condition);
|
||||
|
@ -352,7 +355,7 @@ AstNode* Ast::createNodeRemove (AstNode const* expression,
|
|||
node->addMember(options);
|
||||
node->addMember(collection);
|
||||
node->addMember(expression);
|
||||
node->addMember(createNodeVariable(Variable::NAME_OLD, false));
|
||||
node->addMember(createNodeVariable(TRI_CHAR_LENGTH_PAIR(Variable::NAME_OLD), false));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -375,7 +378,7 @@ AstNode* Ast::createNodeInsert (AstNode const* expression,
|
|||
node->addMember(options);
|
||||
node->addMember(collection);
|
||||
node->addMember(expression);
|
||||
node->addMember(createNodeVariable(Variable::NAME_NEW, false));
|
||||
node->addMember(createNodeVariable(TRI_CHAR_LENGTH_PAIR(Variable::NAME_NEW), false));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -406,8 +409,8 @@ AstNode* Ast::createNodeUpdate (AstNode const* keyExpression,
|
|||
node->addMember(&NopNode);
|
||||
}
|
||||
|
||||
node->addMember(createNodeVariable(Variable::NAME_OLD, false));
|
||||
node->addMember(createNodeVariable(Variable::NAME_NEW, false));
|
||||
node->addMember(createNodeVariable(TRI_CHAR_LENGTH_PAIR(Variable::NAME_OLD), false));
|
||||
node->addMember(createNodeVariable(TRI_CHAR_LENGTH_PAIR(Variable::NAME_NEW), false));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -438,8 +441,8 @@ AstNode* Ast::createNodeReplace (AstNode const* keyExpression,
|
|||
node->addMember(&NopNode);
|
||||
}
|
||||
|
||||
node->addMember(createNodeVariable(Variable::NAME_OLD, false));
|
||||
node->addMember(createNodeVariable(Variable::NAME_NEW, false));
|
||||
node->addMember(createNodeVariable(TRI_CHAR_LENGTH_PAIR(Variable::NAME_OLD), false));
|
||||
node->addMember(createNodeVariable(TRI_CHAR_LENGTH_PAIR(Variable::NAME_NEW), false));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -470,7 +473,7 @@ AstNode* Ast::createNodeUpsert (AstNodeType type,
|
|||
node->addMember(updateExpression);
|
||||
|
||||
node->addMember(createNodeReference(Variable::NAME_OLD));
|
||||
node->addMember(createNodeVariable(Variable::NAME_NEW, false));
|
||||
node->addMember(createNodeVariable(TRI_CHAR_LENGTH_PAIR(Variable::NAME_NEW), false));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -493,6 +496,7 @@ AstNode* Ast::createNodeDistinct (AstNode const* value) {
|
|||
|
||||
AstNode* Ast::createNodeCollect (AstNode const* list,
|
||||
char const* name,
|
||||
size_t nameLength,
|
||||
AstNode const* keepVariables,
|
||||
AstNode const* options) {
|
||||
AstNode* node = createNode(NODE_TYPE_COLLECT);
|
||||
|
@ -501,13 +505,13 @@ AstNode* Ast::createNodeCollect (AstNode const* list,
|
|||
// no options given. now use default options
|
||||
options = &NopNode;
|
||||
}
|
||||
node->addMember(options);
|
||||
|
||||
node->addMember(options);
|
||||
node->addMember(list);
|
||||
|
||||
// INTO
|
||||
if (name != nullptr) {
|
||||
AstNode* variable = createNodeVariable(name, true);
|
||||
AstNode* variable = createNodeVariable(name, nameLength, true);
|
||||
node->addMember(variable);
|
||||
|
||||
// KEEP
|
||||
|
@ -517,6 +521,7 @@ AstNode* Ast::createNodeCollect (AstNode const* list,
|
|||
}
|
||||
else {
|
||||
TRI_ASSERT(keepVariables == nullptr);
|
||||
TRI_ASSERT(nameLength == 0);
|
||||
}
|
||||
|
||||
return node;
|
||||
|
@ -528,6 +533,7 @@ AstNode* Ast::createNodeCollect (AstNode const* list,
|
|||
|
||||
AstNode* Ast::createNodeCollectExpression (AstNode const* list,
|
||||
char const* name,
|
||||
size_t nameLength,
|
||||
AstNode const* expression,
|
||||
AstNode const* options) {
|
||||
AstNode* node = createNode(NODE_TYPE_COLLECT_EXPRESSION);
|
||||
|
@ -536,11 +542,11 @@ AstNode* Ast::createNodeCollectExpression (AstNode const* list,
|
|||
// no options given. now use default options
|
||||
options = &NopNode;
|
||||
}
|
||||
node->addMember(options);
|
||||
|
||||
node->addMember(options);
|
||||
node->addMember(list);
|
||||
|
||||
AstNode* variable = createNodeVariable(name, true);
|
||||
AstNode* variable = createNodeVariable(name, nameLength, true);
|
||||
node->addMember(variable);
|
||||
|
||||
node->addMember(expression);
|
||||
|
@ -554,6 +560,7 @@ AstNode* Ast::createNodeCollectExpression (AstNode const* list,
|
|||
|
||||
AstNode* Ast::createNodeCollectCount (AstNode const* list,
|
||||
char const* name,
|
||||
size_t nameLength,
|
||||
AstNode const* options) {
|
||||
AstNode* node = createNode(NODE_TYPE_COLLECT_COUNT);
|
||||
|
||||
|
@ -561,11 +568,11 @@ AstNode* Ast::createNodeCollectCount (AstNode const* list,
|
|||
// no options given. now use default options
|
||||
options = &NopNode;
|
||||
}
|
||||
node->addMember(options);
|
||||
|
||||
node->addMember(options);
|
||||
node->addMember(list);
|
||||
|
||||
AstNode* variable = createNodeVariable(name, true);
|
||||
AstNode* variable = createNodeVariable(name, nameLength, true);
|
||||
node->addMember(variable);
|
||||
|
||||
return node;
|
||||
|
@ -613,13 +620,14 @@ AstNode* Ast::createNodeLimit (AstNode const* offset,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeAssign (char const* variableName,
|
||||
size_t nameLength,
|
||||
AstNode const* expression) {
|
||||
if (variableName == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
AstNode* node = createNode(NODE_TYPE_ASSIGN);
|
||||
AstNode* variable = createNodeVariable(variableName, true);
|
||||
AstNode* variable = createNodeVariable(variableName, nameLength, true);
|
||||
node->addMember(variable);
|
||||
node->addMember(expression);
|
||||
|
||||
|
@ -631,8 +639,9 @@ AstNode* Ast::createNodeAssign (char const* variableName,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeVariable (char const* name,
|
||||
size_t nameLength,
|
||||
bool isUserDefined) {
|
||||
if (name == nullptr || *name == '\0') {
|
||||
if (name == nullptr || nameLength == 0) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
|
@ -641,12 +650,12 @@ AstNode* Ast::createNodeVariable (char const* name,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (_scopes.existsVariable(name)) {
|
||||
if (_scopes.existsVariable(name, nameLength)) {
|
||||
_query->registerError(TRI_ERROR_QUERY_VARIABLE_REDECLARED, name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto variable = _variables.createVariable(name, isUserDefined);
|
||||
auto variable = _variables.createVariable(name, nameLength, isUserDefined);
|
||||
_scopes.addVariable(variable);
|
||||
|
||||
AstNode* node = createNode(NODE_TYPE_VARIABLE);
|
||||
|
@ -671,7 +680,7 @@ AstNode* Ast::createNodeCollection (char const* name,
|
|||
}
|
||||
|
||||
AstNode* node = createNode(NODE_TYPE_COLLECTION);
|
||||
node->setStringValue(name);
|
||||
node->setStringValue(name, strlen(name));
|
||||
|
||||
_query->collections()->add(name, accessType);
|
||||
|
||||
|
@ -682,13 +691,32 @@ AstNode* Ast::createNodeCollection (char const* name,
|
|||
/// @brief create an AST reference node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeReference (char const* variableName) {
|
||||
AstNode* Ast::createNodeReference (char const* variableName,
|
||||
size_t nameLength) {
|
||||
if (variableName == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
AstNode* node = createNode(NODE_TYPE_REFERENCE);
|
||||
|
||||
auto variable = _scopes.getVariable(std::string(variableName, nameLength));
|
||||
|
||||
if (variable == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "variable not found in reference AstNode");
|
||||
}
|
||||
|
||||
node->setData(variable);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST reference node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeReference (std::string const& variableName) {
|
||||
AstNode* node = createNode(NODE_TYPE_REFERENCE);
|
||||
|
||||
auto variable = _scopes.getVariable(variableName);
|
||||
|
||||
if (variable == nullptr) {
|
||||
|
@ -715,14 +743,15 @@ AstNode* Ast::createNodeReference (Variable const* variable) {
|
|||
/// @brief create an AST parameter node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeParameter (char const* name) {
|
||||
AstNode* Ast::createNodeParameter (char const* name,
|
||||
size_t length) {
|
||||
if (name == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
AstNode* node = createNode(NODE_TYPE_PARAMETER);
|
||||
|
||||
node->setStringValue(name);
|
||||
node->setStringValue(name, length);
|
||||
|
||||
// insert bind parameter name into list of found parameters
|
||||
_bindParameters.emplace(name);
|
||||
|
@ -776,14 +805,15 @@ AstNode* Ast::createNodeTernaryOperator (AstNode const* condition,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeAttributeAccess (AstNode const* accessed,
|
||||
char const* attributeName) {
|
||||
char const* attributeName,
|
||||
size_t nameLength) {
|
||||
if (attributeName == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
AstNode* node = createNode(NODE_TYPE_ATTRIBUTE_ACCESS);
|
||||
node->addMember(accessed);
|
||||
node->setStringValue(attributeName);
|
||||
node->setStringValue(attributeName, nameLength);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -795,7 +825,7 @@ AstNode* Ast::createNodeAttributeAccess (AstNode const* accessed,
|
|||
AstNode* Ast::createNodeBoundAttributeAccess (AstNode const* accessed,
|
||||
AstNode const* parameter) {
|
||||
AstNode* node = createNode(NODE_TYPE_BOUND_ATTRIBUTE_ACCESS);
|
||||
node->setStringValue(parameter->getStringValue());
|
||||
node->setStringValue(parameter->getStringValue(), parameter->getStringLength());
|
||||
node->addMember(accessed);
|
||||
node->addMember(parameter);
|
||||
|
||||
|
@ -880,6 +910,7 @@ AstNode* Ast::createNodeExpansion (int64_t levels,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeIterator (char const* variableName,
|
||||
size_t nameLength,
|
||||
AstNode const* expanded) {
|
||||
if (variableName == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
|
@ -887,7 +918,7 @@ AstNode* Ast::createNodeIterator (char const* variableName,
|
|||
|
||||
AstNode* node = createNode(NODE_TYPE_ITERATOR);
|
||||
|
||||
AstNode* variable = createNodeVariable(variableName, false);
|
||||
AstNode* variable = createNodeVariable(variableName, nameLength, false);
|
||||
node->addMember(variable);
|
||||
node->addMember(expanded);
|
||||
|
||||
|
@ -955,7 +986,8 @@ AstNode* Ast::createNodeValueDouble (double value) {
|
|||
/// @brief create an AST string value node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeValueString (char const* value) {
|
||||
AstNode* Ast::createNodeValueString (char const* value,
|
||||
size_t length) {
|
||||
if (value == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
@ -969,7 +1001,7 @@ AstNode* Ast::createNodeValueString (char const* value) {
|
|||
|
||||
AstNode* node = createNode(NODE_TYPE_VALUE);
|
||||
node->setValueType(VALUE_TYPE_STRING);
|
||||
node->setStringValue(value);
|
||||
node->setStringValue(value, length);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -997,13 +1029,14 @@ AstNode* Ast::createNodeObject () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* Ast::createNodeObjectElement (char const* attributeName,
|
||||
size_t nameLength,
|
||||
AstNode const* expression) {
|
||||
if (attributeName == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
AstNode* node = createNode(NODE_TYPE_OBJECT_ELEMENT);
|
||||
node->setStringValue(attributeName);
|
||||
node->setStringValue(attributeName, nameLength);
|
||||
node->addMember(expression);
|
||||
|
||||
return node;
|
||||
|
@ -1069,8 +1102,8 @@ AstNode* Ast::createNodeFunctionCall (char const* functionName,
|
|||
// user-defined function
|
||||
node = createNode(NODE_TYPE_FCALL_USER);
|
||||
// register the function name
|
||||
char* fname = _query->registerString(normalized.first.c_str(), normalized.first.size(), false);
|
||||
node->setStringValue(fname);
|
||||
char* fname = _query->registerString(normalized.first);
|
||||
node->setStringValue(fname, normalized.first.size());
|
||||
|
||||
_functionsMayAccessDocuments = true;
|
||||
}
|
||||
|
@ -1112,12 +1145,13 @@ void Ast::injectBindParameters (BindParameters& parameters) {
|
|||
if (node->type == NODE_TYPE_PARAMETER) {
|
||||
// found a bind parameter in the query string
|
||||
char const* param = node->getStringValue();
|
||||
size_t const length = node->getStringLength();
|
||||
|
||||
if (param == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
auto it = p.find(std::string(param));
|
||||
auto it = p.find(std::string(param, length));
|
||||
|
||||
if (it == p.end()) {
|
||||
// query uses a bind parameter that was not defined by the user
|
||||
|
@ -1142,7 +1176,8 @@ void Ast::injectBindParameters (BindParameters& parameters) {
|
|||
}
|
||||
|
||||
// turn node into a collection node
|
||||
char const* name = _query->registerString(value->_value._string.data, value->_value._string.length - 1, false);
|
||||
size_t const length = value->_value._string.length - 1;
|
||||
char const* name = _query->registerString(value->_value._string.data, length);
|
||||
|
||||
node = createNodeCollection(name, isWriteCollection ? TRI_TRANSACTION_WRITE : TRI_TRANSACTION_READ);
|
||||
|
||||
|
@ -1178,12 +1213,12 @@ void Ast::injectBindParameters (BindParameters& parameters) {
|
|||
|
||||
if (name->type != NODE_TYPE_VALUE ||
|
||||
name->value.type != VALUE_TYPE_STRING ||
|
||||
*name->value.value._string == '\0') {
|
||||
name->value.length == 0) {
|
||||
// if no string value was inserted for the parameter name, this is an error
|
||||
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE, node->getStringValue());
|
||||
}
|
||||
// convert into a regular attribute access node to simplify handling later
|
||||
return createNodeAttributeAccess(node->getMember(0), name->getStringValue());
|
||||
return createNodeAttributeAccess(node->getMember(0), name->getStringValue(), name->getStringLength());
|
||||
}
|
||||
|
||||
return node;
|
||||
|
@ -1477,6 +1512,7 @@ TopLevelAttributes Ast::getReferencedAttributes (AstNode const* node,
|
|||
|
||||
// traversal state
|
||||
char const* attributeName = nullptr;
|
||||
size_t nameLength = 0;
|
||||
isSafeForOptimization = true;
|
||||
|
||||
auto visitor = [&](AstNode const* node, void* data) -> void {
|
||||
|
@ -1486,6 +1522,7 @@ TopLevelAttributes Ast::getReferencedAttributes (AstNode const* node,
|
|||
|
||||
if (node->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||
attributeName = node->getStringValue();
|
||||
nameLength = node->getStringLength();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1512,17 +1549,18 @@ TopLevelAttributes Ast::getReferencedAttributes (AstNode const* node,
|
|||
|
||||
if (it == result.end()) {
|
||||
// insert variable and attributeName
|
||||
result.emplace(std::make_pair(variable, std::unordered_set<std::string>({ std::string(attributeName) })));
|
||||
result.emplace(variable, std::unordered_set<std::string>({ std::string(attributeName, nameLength) }));
|
||||
}
|
||||
else {
|
||||
// insert attributeName only
|
||||
(*it).second.emplace(std::string(attributeName));
|
||||
(*it).second.emplace(std::string(attributeName, nameLength));
|
||||
}
|
||||
|
||||
// fall-through
|
||||
}
|
||||
|
||||
attributeName = nullptr;
|
||||
nameLength = 0;
|
||||
};
|
||||
|
||||
traverseReadOnly(node, visitor, doNothingVisitor, doNothingVisitor, nullptr);
|
||||
|
@ -1545,7 +1583,7 @@ AstNode* Ast::clone (AstNode const* node) {
|
|||
type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
||||
type == NODE_TYPE_OBJECT_ELEMENT ||
|
||||
type == NODE_TYPE_FCALL_USER) {
|
||||
copy->setStringValue(node->getStringValue());
|
||||
copy->setStringValue(node->getStringValue(), node->getStringLength());
|
||||
}
|
||||
else if (type == NODE_TYPE_VARIABLE ||
|
||||
type == NODE_TYPE_REFERENCE ||
|
||||
|
@ -1574,7 +1612,7 @@ AstNode* Ast::clone (AstNode const* node) {
|
|||
break;
|
||||
case VALUE_TYPE_STRING:
|
||||
copy->value.type = VALUE_TYPE_STRING;
|
||||
copy->setStringValue(node->getStringValue());
|
||||
copy->setStringValue(node->getStringValue(), node->getStringLength());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1582,7 +1620,7 @@ AstNode* Ast::clone (AstNode const* node) {
|
|||
// recursively clone subnodes
|
||||
size_t const n = node->numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
copy->addMember(clone(node->getMember(i)));
|
||||
copy->addMember(clone(node->getMemberUnchecked(i)));
|
||||
}
|
||||
|
||||
return copy;
|
||||
|
@ -1594,6 +1632,7 @@ AstNode* Ast::clone (AstNode const* node) {
|
|||
|
||||
AstNodeType Ast::ReverseOperator (AstNodeType type) {
|
||||
auto it = ReversedOperators.find(static_cast<int>(type));
|
||||
|
||||
if (it == ReversedOperators.end()) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "invalid node type for inversed operator");
|
||||
}
|
||||
|
@ -1626,7 +1665,7 @@ AstNode* Ast::makeConditionFromExample (AstNode const* node) {
|
|||
|
||||
|
||||
AstNode* result = nullptr;
|
||||
std::vector<char const*> attributeParts{ };
|
||||
std::vector<std::pair<char const*, size_t>> attributeParts{ };
|
||||
|
||||
std::function<void(AstNode const*)> createCondition = [&] (AstNode const* object) -> void {
|
||||
TRI_ASSERT(object->type == NODE_TYPE_OBJECT);
|
||||
|
@ -1640,7 +1679,7 @@ AstNode* Ast::makeConditionFromExample (AstNode const* node) {
|
|||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE, "expecting object literal with literal attribute names in example");
|
||||
}
|
||||
|
||||
attributeParts.emplace_back(member->getStringValue());
|
||||
attributeParts.emplace_back(std::make_pair(member->getStringValue(), member->getStringLength()));
|
||||
|
||||
auto value = member->getMember(0);
|
||||
|
||||
|
@ -1649,8 +1688,8 @@ AstNode* Ast::makeConditionFromExample (AstNode const* node) {
|
|||
}
|
||||
else {
|
||||
auto access = variable;
|
||||
for (size_t i = 0; i < attributeParts.size(); ++i) {
|
||||
access = createNodeAttributeAccess(access, attributeParts[i]);
|
||||
for (auto const& it : attributeParts) {
|
||||
access = createNodeAttributeAccess(access, it.first, it.second);
|
||||
}
|
||||
|
||||
auto condition = createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_EQ, access, value);
|
||||
|
@ -2284,13 +2323,13 @@ AstNode* Ast::optimizeIndexedAccess (AstNode* node) {
|
|||
// found a string value (e.g. a['foo']). now turn this into
|
||||
// an attribute access (e.g. a.foo) in order to make the node qualify
|
||||
// for being turned into an index range later
|
||||
char const* indexValue = index->value.value._string;
|
||||
char const* indexValue = index->getStringValue();
|
||||
|
||||
if (indexValue != nullptr &&
|
||||
(indexValue[0] < '0' || indexValue[0] > '9')) {
|
||||
// we have to be careful with numeric values here...
|
||||
// e.g. array['0'] is not the same as array.0 but must remain a['0'] or (a[0])
|
||||
return createNodeAttributeAccess(node->getMember(0), index->getStringValue());
|
||||
return createNodeAttributeAccess(node->getMember(0), indexValue, index->getStringLength());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2404,13 +2443,15 @@ AstNode* Ast::nodeFromJson (TRI_json_t const* json,
|
|||
|
||||
if (json->_type == TRI_JSON_STRING ||
|
||||
json->_type == TRI_JSON_STRING_REFERENCE) {
|
||||
size_t const length = json->_value._string.length - 1;
|
||||
|
||||
if (copyStringValues) {
|
||||
// we must copy string values!
|
||||
char const* value = _query->registerString(json->_value._string.data, json->_value._string.length - 1, false);
|
||||
return createNodeValueString(value);
|
||||
char const* value = _query->registerString(json->_value._string.data, length);
|
||||
return createNodeValueString(value, length);
|
||||
}
|
||||
// we can get away without copying string values
|
||||
return createNodeValueString(json->_value._string.data);
|
||||
return createNodeValueString(json->_value._string.data, length);
|
||||
}
|
||||
|
||||
if (json->_type == TRI_JSON_ARRAY) {
|
||||
|
@ -2436,17 +2477,15 @@ AstNode* Ast::nodeFromJson (TRI_json_t const* json,
|
|||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "unexpected type found in object node");
|
||||
}
|
||||
|
||||
char const* attributeName;
|
||||
char const* attributeName = key->_value._string.data;
|
||||
size_t const nameLength = key->_value._string.length - 1;
|
||||
|
||||
if (copyStringValues) {
|
||||
// create a copy of the string value
|
||||
attributeName = _query->registerString(key->_value._string.data, key->_value._string.length - 1, false);
|
||||
}
|
||||
else {
|
||||
// use string value by reference
|
||||
attributeName = key->_value._string.data;
|
||||
attributeName = _query->registerString(key->_value._string.data, nameLength);
|
||||
}
|
||||
|
||||
node->addMember(createNodeObjectElement(attributeName, nodeFromJson(value, copyStringValues)));
|
||||
node->addMember(createNodeObjectElement(attributeName, nameLength, nodeFromJson(value, copyStringValues)));
|
||||
}
|
||||
|
||||
return node;
|
||||
|
|
|
@ -239,14 +239,16 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeFor (char const*,
|
||||
size_t,
|
||||
AstNode const*,
|
||||
bool = false);
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST let node, without an IF condition
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeLet (char const*,
|
||||
size_t,
|
||||
AstNode const*,
|
||||
bool);
|
||||
|
||||
|
@ -262,6 +264,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeLet (char const*,
|
||||
size_t,
|
||||
AstNode const*,
|
||||
AstNode const*);
|
||||
|
||||
|
@ -341,6 +344,7 @@ namespace triagens {
|
|||
|
||||
AstNode* createNodeCollect (AstNode const*,
|
||||
char const*,
|
||||
size_t,
|
||||
AstNode const*,
|
||||
AstNode const*);
|
||||
|
||||
|
@ -350,6 +354,7 @@ namespace triagens {
|
|||
|
||||
AstNode* createNodeCollectExpression (AstNode const*,
|
||||
char const*,
|
||||
size_t,
|
||||
AstNode const*,
|
||||
AstNode const*);
|
||||
|
||||
|
@ -359,6 +364,7 @@ namespace triagens {
|
|||
|
||||
AstNode* createNodeCollectCount (AstNode const*,
|
||||
char const*,
|
||||
size_t length,
|
||||
AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -386,6 +392,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeAssign (char const*,
|
||||
size_t,
|
||||
AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -393,6 +400,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeVariable (char const*,
|
||||
size_t,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -406,7 +414,14 @@ namespace triagens {
|
|||
/// @brief create an AST reference node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeReference (char const*);
|
||||
AstNode* createNodeReference (char const*,
|
||||
size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST reference node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeReference (std::string const&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST reference node
|
||||
|
@ -418,7 +433,8 @@ namespace triagens {
|
|||
/// @brief create an AST parameter node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeParameter (char const*);
|
||||
AstNode* createNodeParameter (char const*,
|
||||
size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST unary operator
|
||||
|
@ -448,7 +464,8 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeAttributeAccess (AstNode const*,
|
||||
char const*);
|
||||
char const*,
|
||||
size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST attribute access node w/ bind parameter
|
||||
|
@ -487,6 +504,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeIterator (char const*,
|
||||
size_t,
|
||||
AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -517,7 +535,8 @@ namespace triagens {
|
|||
/// @brief create an AST string value node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeValueString (char const*);
|
||||
AstNode* createNodeValueString (char const*,
|
||||
size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an AST array node
|
||||
|
@ -536,6 +555,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* createNodeObjectElement (char const*,
|
||||
size_t,
|
||||
AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -368,8 +368,11 @@ int triagens::aql::CompareAstNodes (AstNode const* lhs,
|
|||
/// @brief returns whether or not the string is empty
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEmptyString (char const* p) {
|
||||
while (*p != '\0') {
|
||||
static bool IsEmptyString (char const* p,
|
||||
size_t length) {
|
||||
char const* e = p + length;
|
||||
|
||||
while (p < e) {
|
||||
if (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != '\f' && *p != '\b') {
|
||||
return false;
|
||||
}
|
||||
|
@ -440,12 +443,13 @@ AstNode::AstNode (int64_t v,
|
|||
/// @brief create a string node, with defining a value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode::AstNode (char const* v,
|
||||
AstNode::AstNode (char const* v,
|
||||
size_t length,
|
||||
AstNodeValueType valueType)
|
||||
: AstNode(NODE_TYPE_VALUE, valueType) {
|
||||
|
||||
TRI_ASSERT(valueType == VALUE_TYPE_STRING);
|
||||
value.value._string = v;
|
||||
setStringValue(v, length);
|
||||
TRI_ASSERT_EXPENSIVE(flags == 0);
|
||||
TRI_ASSERT_EXPENSIVE(computedJson == nullptr);
|
||||
}
|
||||
|
@ -467,10 +471,12 @@ AstNode::AstNode (Ast* ast,
|
|||
case NODE_TYPE_COLLECTION:
|
||||
case NODE_TYPE_PARAMETER:
|
||||
case NODE_TYPE_ATTRIBUTE_ACCESS:
|
||||
case NODE_TYPE_FCALL_USER:
|
||||
case NODE_TYPE_FCALL_USER: {
|
||||
std::string const str(JsonHelper::getStringValue(json.json(), "name", ""));
|
||||
value.type = VALUE_TYPE_STRING;
|
||||
setStringValue(query->registerString(JsonHelper::getStringValue(json.json(), "name", ""), false));
|
||||
setStringValue(query->registerString(str), str.size());
|
||||
break;
|
||||
}
|
||||
case NODE_TYPE_VALUE: {
|
||||
int vType = JsonHelper::checkAndGetNumericValue<int>(json.json(), "vTypeID");
|
||||
validateValueType(vType);
|
||||
|
@ -488,9 +494,11 @@ AstNode::AstNode (Ast* ast,
|
|||
case VALUE_TYPE_DOUBLE:
|
||||
setDoubleValue(JsonHelper::checkAndGetNumericValue<double>(json.json(), "value"));
|
||||
break;
|
||||
case VALUE_TYPE_STRING:
|
||||
setStringValue(query->registerString(JsonHelper::checkAndGetStringValue(json.json(), "value"), false));
|
||||
case VALUE_TYPE_STRING: {
|
||||
std::string const str (JsonHelper::checkAndGetStringValue(json.json(), "value"));
|
||||
setStringValue(query->registerString(str), str.size());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
}
|
||||
}
|
||||
|
@ -515,7 +523,8 @@ AstNode::AstNode (Ast* ast,
|
|||
break;
|
||||
}
|
||||
case NODE_TYPE_OBJECT_ELEMENT: {
|
||||
setStringValue(query->registerString(JsonHelper::getStringValue(json.json(), "name", ""), false));
|
||||
std::string const str(JsonHelper::getStringValue(json.json(), "name", ""));
|
||||
setStringValue(query->registerString(str), str.size());
|
||||
break;
|
||||
}
|
||||
case NODE_TYPE_EXPANSION: {
|
||||
|
@ -725,7 +734,7 @@ TRI_json_t* AstNode::toJsonValue (TRI_memory_zone_t* zone) const {
|
|||
case VALUE_TYPE_DOUBLE:
|
||||
return TRI_CreateNumberJson(zone, value.value._double);
|
||||
case VALUE_TYPE_STRING:
|
||||
return TRI_CreateStringCopyJson(zone, value.value._string, strlen(value.value._string));
|
||||
return TRI_CreateStringCopyJson(zone, value.value._string, value.length);
|
||||
// TODO: can we get away with a string reference only??
|
||||
// this would speed things up considerably!
|
||||
// return TRI_CreateStringReferenceJson(zone, value.value._string, strlen(value.value._string));
|
||||
|
@ -830,8 +839,7 @@ TRI_json_t* AstNode::toJson (TRI_memory_zone_t* zone,
|
|||
type == NODE_TYPE_OBJECT_ELEMENT ||
|
||||
type == NODE_TYPE_FCALL_USER) {
|
||||
// dump "name" of node
|
||||
auto const* strValue = getStringValue();
|
||||
if (TRI_InitStringCopyJson(zone, &json, strValue, strlen(strValue)) != TRI_ERROR_NO_ERROR) {
|
||||
if (TRI_InitStringCopyJson(zone, &json, getStringValue(), getStringLength()) != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeJson(zone, node);
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
@ -978,11 +986,11 @@ AstNode* AstNode::castToNumber (Ast* ast) {
|
|||
case VALUE_TYPE_STRING:
|
||||
try {
|
||||
// try converting string to number
|
||||
double v = std::stod(value.value._string);
|
||||
double v = std::stod(std::string(value.value._string, value.length));
|
||||
return ast->createNodeValueDouble(v);
|
||||
}
|
||||
catch (...) {
|
||||
if (IsEmptyString(value.value._string)) {
|
||||
if (IsEmptyString(value.value._string, value.length)) {
|
||||
// empty string => 0
|
||||
return ast->createNodeValueInt(0);
|
||||
}
|
||||
|
@ -1034,9 +1042,9 @@ AstNode* AstNode::castToString (Ast* ast) {
|
|||
triagens::basics::StringBuffer buffer(TRI_UNKNOWN_MEM_ZONE);
|
||||
stringify(&buffer, false, false);
|
||||
|
||||
char const* value = ast->query()->registerString(buffer.c_str(), buffer.length(), false);
|
||||
char const* value = ast->query()->registerString(buffer.c_str(), buffer.length());
|
||||
TRI_ASSERT(value != nullptr);
|
||||
return ast->createNodeValueString(value);
|
||||
return ast->createNodeValueString(value, buffer.length());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1115,9 +1123,9 @@ bool AstNode::isTrue () const {
|
|||
case VALUE_TYPE_INT:
|
||||
return (value.value._int != 0);
|
||||
case VALUE_TYPE_DOUBLE:
|
||||
return value.value._double != 0.0;
|
||||
return (value.value._double != 0.0);
|
||||
case VALUE_TYPE_STRING:
|
||||
return (*value.value._string != '\0');
|
||||
return (value.length != 0);
|
||||
}
|
||||
}
|
||||
else if (type == NODE_TYPE_ARRAY ||
|
||||
|
@ -1156,13 +1164,13 @@ bool AstNode::isFalse () const {
|
|||
case VALUE_TYPE_NULL:
|
||||
return true;
|
||||
case VALUE_TYPE_BOOL:
|
||||
return ! value.value._bool;
|
||||
return (! value.value._bool);
|
||||
case VALUE_TYPE_INT:
|
||||
return (value.value._int == 0);
|
||||
case VALUE_TYPE_DOUBLE:
|
||||
return value.value._double == 0.0;
|
||||
return (value.value._double == 0.0);
|
||||
case VALUE_TYPE_STRING:
|
||||
return (*value.value._string == '\0');
|
||||
return (value.length == 0);
|
||||
}
|
||||
}
|
||||
else if (type == NODE_TYPE_ARRAY ||
|
||||
|
@ -1704,7 +1712,7 @@ void AstNode::stringify (triagens::basics::StringBuffer* buffer,
|
|||
TRI_ASSERT(member->numMembers() == 1);
|
||||
|
||||
buffer->appendChar('"');
|
||||
buffer->appendJsonEncoded(member->getStringValue());
|
||||
buffer->appendJsonEncoded(member->getStringValue(), member->getStringLength());
|
||||
buffer->appendText(TRI_CHAR_LENGTH_PAIR("\":"));
|
||||
|
||||
member->getMember(0)->stringify(buffer, verbose, failIfLong);
|
||||
|
@ -1936,7 +1944,7 @@ void AstNode::appendValue (triagens::basics::StringBuffer* buffer) const {
|
|||
|
||||
case VALUE_TYPE_STRING: {
|
||||
buffer->appendChar('"');
|
||||
buffer->appendJsonEncoded(value.value._string);
|
||||
buffer->appendJsonEncoded(value.value._string, value.length);
|
||||
buffer->appendChar('"');
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -108,6 +108,7 @@ namespace triagens {
|
|||
void* _data;
|
||||
}
|
||||
value;
|
||||
uint32_t length; // only used for string values
|
||||
AstNodeValueType type;
|
||||
};
|
||||
|
||||
|
@ -226,7 +227,7 @@ namespace triagens {
|
|||
/// @brief create a string node, with defining a value type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
explicit AstNode (char const*, AstNodeValueType);
|
||||
explicit AstNode (char const*, size_t, AstNodeValueType);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the node from JSON
|
||||
|
@ -655,12 +656,25 @@ namespace triagens {
|
|||
return value.value._string;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the string value of a node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline size_t getStringLength () const {
|
||||
return static_cast<size_t>(value.length);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the string value of a node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void setStringValue (char const* v) {
|
||||
inline void setStringValue (char const* v,
|
||||
size_t length) {
|
||||
// note: v may contain the NUL byte
|
||||
TRI_ASSERT(v == nullptr || strlen(v) <= length);
|
||||
|
||||
value.value._string = v;
|
||||
value.length = length;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -457,7 +457,7 @@ namespace triagens {
|
|||
size_t atMost,
|
||||
bool skipping,
|
||||
AqlItemBlock*& result,
|
||||
size_t& skipped);
|
||||
size_t& skipped) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief _inputRegisterValues
|
||||
|
@ -1153,7 +1153,7 @@ namespace triagens {
|
|||
size_t atMost,
|
||||
bool skipping,
|
||||
AqlItemBlock*& result,
|
||||
size_t& skipped);
|
||||
size_t& skipped) override;
|
||||
|
||||
bool hasMore () override final;
|
||||
|
||||
|
@ -1203,7 +1203,7 @@ namespace triagens {
|
|||
size_t atMost,
|
||||
bool skipping,
|
||||
AqlItemBlock*& result,
|
||||
size_t& skipped);
|
||||
size_t& skipped) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief writes the current group data into the result
|
||||
|
@ -1271,7 +1271,7 @@ namespace triagens {
|
|||
size_t atMost,
|
||||
bool skipping,
|
||||
AqlItemBlock*& result,
|
||||
size_t& skipped);
|
||||
size_t& skipped) override;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -1423,7 +1423,7 @@ namespace triagens {
|
|||
size_t atMost,
|
||||
bool skipping,
|
||||
AqlItemBlock*& result,
|
||||
size_t& skipped);
|
||||
size_t& skipped) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief _offset
|
||||
|
@ -1854,7 +1854,7 @@ namespace triagens {
|
|||
size_t atMost,
|
||||
bool skipping,
|
||||
AqlItemBlock*& result,
|
||||
size_t& skipped);
|
||||
size_t& skipped) override;
|
||||
|
||||
};
|
||||
|
||||
|
@ -2205,13 +2205,13 @@ namespace triagens {
|
|||
/// @brief hasMoreForShard: any more for shard <shardId>?
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool hasMoreForShard (std::string const& shardId);
|
||||
bool hasMoreForShard (std::string const& shardId) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remainingForShard: remaining for shard <shardId>?
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int64_t remainingForShard (std::string const& shardId);
|
||||
int64_t remainingForShard (std::string const& shardId) override;
|
||||
|
||||
|
||||
private:
|
||||
|
@ -2225,7 +2225,7 @@ namespace triagens {
|
|||
bool skipping,
|
||||
AqlItemBlock*& result,
|
||||
size_t& skipped,
|
||||
std::string const& shardId);
|
||||
std::string const& shardId) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief _posForClient:
|
||||
|
@ -2275,7 +2275,7 @@ namespace triagens {
|
|||
/// @brief remainingForShard: remaining for shard <shardId>?
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int64_t remainingForShard (std::string const& shardId) {
|
||||
int64_t remainingForShard (std::string const& shardId) override {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -2283,7 +2283,7 @@ namespace triagens {
|
|||
/// @brief hasMoreForShard: any more for shard <shardId>?
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool hasMoreForShard (std::string const& shardId);
|
||||
bool hasMoreForShard (std::string const& shardId) override;
|
||||
|
||||
|
||||
private:
|
||||
|
@ -2297,7 +2297,7 @@ namespace triagens {
|
|||
bool skipping,
|
||||
AqlItemBlock*& result,
|
||||
size_t& skipped,
|
||||
std::string const& shardId);
|
||||
std::string const& shardId) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getBlockForClient: try to get at atLeast/atMost pairs into
|
||||
|
|
|
@ -1643,7 +1643,7 @@ namespace triagens {
|
|||
/// @brief can the node throw?
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool canThrow () {
|
||||
bool canThrow () override {
|
||||
return _expression->canThrow();
|
||||
}
|
||||
|
||||
|
@ -1796,7 +1796,7 @@ namespace triagens {
|
|||
/// return true just because a dependent node can throw an exception.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool canThrow ();
|
||||
bool canThrow () override;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
|
|
|
@ -502,7 +502,7 @@ v8::Handle<v8::Value> Executor::toV8 (v8::Isolate* isolate,
|
|||
v8::Handle<v8::Object> result = v8::Object::New(isolate);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto sub = node->getMember(i);
|
||||
result->ForceSet(TRI_V8_STRING(sub->getStringValue()), toV8(isolate, sub->getMember(0)));
|
||||
result->ForceSet(TRI_V8_PAIR_STRING(sub->getStringValue(), sub->getStringLength()), toV8(isolate, sub->getMember(0)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -518,7 +518,7 @@ v8::Handle<v8::Value> Executor::toV8 (v8::Isolate* isolate,
|
|||
case VALUE_TYPE_DOUBLE:
|
||||
return v8::Number::New(isolate, static_cast<double>(node->value.value._double));
|
||||
case VALUE_TYPE_STRING:
|
||||
return TRI_V8_STRING(node->value.value._string);
|
||||
return TRI_V8_PAIR_STRING(node->value.value._string, node->value.length);
|
||||
}
|
||||
}
|
||||
return v8::Null(isolate);
|
||||
|
@ -624,11 +624,12 @@ void Executor::generateCodeExpression (AstNode const* node) {
|
|||
/// @brief generates code for a string value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Executor::generateCodeString (char const* value) {
|
||||
void Executor::generateCodeString (char const* value,
|
||||
size_t length) {
|
||||
TRI_ASSERT(value != nullptr);
|
||||
|
||||
_buffer->appendChar('"');
|
||||
_buffer->appendJsonEncoded(value);
|
||||
_buffer->appendJsonEncoded(value, length);
|
||||
_buffer->appendChar('"');
|
||||
}
|
||||
|
||||
|
@ -638,7 +639,7 @@ void Executor::generateCodeString (char const* value) {
|
|||
|
||||
void Executor::generateCodeString (std::string const& value) {
|
||||
_buffer->appendChar('"');
|
||||
_buffer->appendJsonEncoded(value.c_str());
|
||||
_buffer->appendJsonEncoded(value.c_str(), value.size());
|
||||
_buffer->appendChar('"');
|
||||
}
|
||||
|
||||
|
@ -753,7 +754,7 @@ void Executor::generateCodeDynamicObject (AstNode const* node) {
|
|||
|
||||
if (member->type == NODE_TYPE_OBJECT_ELEMENT) {
|
||||
_buffer->appendText(TRI_CHAR_LENGTH_PAIR("o["));
|
||||
generateCodeString(member->getStringValue());
|
||||
generateCodeString(member->getStringValue(), member->getStringLength());
|
||||
_buffer->appendText(TRI_CHAR_LENGTH_PAIR("]="));
|
||||
generateCodeNode(member->getMember(0));
|
||||
}
|
||||
|
@ -802,7 +803,7 @@ void Executor::generateCodeRegularObject (AstNode const* node) {
|
|||
auto member = node->getMember(i);
|
||||
|
||||
if (member != nullptr) {
|
||||
generateCodeString(member->getStringValue());
|
||||
generateCodeString(member->getStringValue(), member->getStringLength());
|
||||
_buffer->appendChar(':');
|
||||
generateCodeNode(member->getMember(0));
|
||||
}
|
||||
|
@ -909,7 +910,7 @@ void Executor::generateCodeReference (AstNode const* node) {
|
|||
auto variable = static_cast<Variable*>(node->getData());
|
||||
|
||||
_buffer->appendText(TRI_CHAR_LENGTH_PAIR("vars["));
|
||||
generateCodeString(variable->name.c_str());
|
||||
generateCodeString(variable->name);
|
||||
_buffer->appendChar(']');
|
||||
}
|
||||
|
||||
|
@ -924,7 +925,7 @@ void Executor::generateCodeVariable (AstNode const* node) {
|
|||
auto variable = static_cast<Variable*>(node->getData());
|
||||
|
||||
_buffer->appendText(TRI_CHAR_LENGTH_PAIR("vars["));
|
||||
generateCodeString(variable->name.c_str());
|
||||
generateCodeString(variable->name);
|
||||
_buffer->appendChar(']');
|
||||
}
|
||||
|
||||
|
@ -936,10 +937,8 @@ void Executor::generateCodeCollection (AstNode const* node) {
|
|||
TRI_ASSERT(node != nullptr);
|
||||
TRI_ASSERT(node->numMembers() == 0);
|
||||
|
||||
char const* name = node->getStringValue();
|
||||
|
||||
_buffer->appendText(TRI_CHAR_LENGTH_PAIR("_AQL.GET_DOCUMENTS("));
|
||||
generateCodeString(name);
|
||||
generateCodeString(node->getStringValue(), node->getStringLength());
|
||||
_buffer->appendChar(')');
|
||||
}
|
||||
|
||||
|
@ -979,8 +978,7 @@ void Executor::generateCodeFunctionCall (AstNode const* node) {
|
|||
(conversion == Function::CONVERSION_REQUIRED || conversion == Function::CONVERSION_OPTIONAL)) {
|
||||
// the parameter at this position is a collection name that is converted to a string
|
||||
// do a parameter conversion from a collection parameter to a collection name parameter
|
||||
char const* name = member->getStringValue();
|
||||
generateCodeString(name);
|
||||
generateCodeString(member->getStringValue(), member->getStringLength());
|
||||
}
|
||||
else if (conversion == Function::CONVERSION_REQUIRED) {
|
||||
// the parameter at the position is not a collection name... fail
|
||||
|
@ -1002,15 +1000,12 @@ void Executor::generateCodeUserFunctionCall (AstNode const* node) {
|
|||
TRI_ASSERT(node != nullptr);
|
||||
TRI_ASSERT(node->numMembers() == 1);
|
||||
|
||||
char const* name = node->getStringValue();
|
||||
TRI_ASSERT(name != nullptr);
|
||||
|
||||
auto args = node->getMember(0);
|
||||
TRI_ASSERT(args != nullptr);
|
||||
TRI_ASSERT(args->type == NODE_TYPE_ARRAY);
|
||||
|
||||
_buffer->appendText(TRI_CHAR_LENGTH_PAIR("_AQL.FCALL_USER("));
|
||||
generateCodeString(name);
|
||||
generateCodeString(node->getStringValue(), node->getStringLength());
|
||||
_buffer->appendChar(',');
|
||||
|
||||
generateCodeNode(args);
|
||||
|
@ -1116,7 +1111,7 @@ void Executor::generateCodeNamedAccess (AstNode const* node) {
|
|||
_buffer->appendText(TRI_CHAR_LENGTH_PAIR("_AQL.DOCUMENT_MEMBER("));
|
||||
generateCodeNode(node->getMember(0));
|
||||
_buffer->appendChar(',');
|
||||
generateCodeString(node->getStringValue());
|
||||
generateCodeString(node->getStringValue(), node->getStringLength());
|
||||
_buffer->appendChar(')');
|
||||
}
|
||||
|
||||
|
|
|
@ -136,7 +136,8 @@ namespace triagens {
|
|||
/// @brief generates code for a string value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void generateCodeString (char const*);
|
||||
void generateCodeString (char const*,
|
||||
size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generates code for a string value
|
||||
|
|
|
@ -675,8 +675,7 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node,
|
|||
auto arg = member->getMemberUnchecked(i);
|
||||
|
||||
if (arg->type == NODE_TYPE_COLLECTION) {
|
||||
char const* collectionName = arg->getStringValue();
|
||||
parameters.emplace_back(AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, collectionName, strlen(collectionName))), nullptr);
|
||||
parameters.emplace_back(AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, arg->getStringValue(), arg->getStringLength())), nullptr);
|
||||
}
|
||||
else {
|
||||
auto value = executeSimpleExpression(arg, &myCollection, trx, argv, startPos, vars, regs, false);
|
||||
|
@ -1084,7 +1083,7 @@ std::pair<std::string, std::string> Expression::getAttributeAccess () {
|
|||
}
|
||||
|
||||
while (expNode->type == triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||
attributeVector.emplace_back(expNode->getStringValue());
|
||||
attributeVector.emplace_back(std::string(expNode->getStringValue(), expNode->getStringLength()));
|
||||
expNode = expNode->getMember(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -719,7 +719,7 @@ AqlValue Functions::Like (triagens::aql::Query* query,
|
|||
AppendAsString(buffer, regex.json());
|
||||
size_t const length = buffer.length();
|
||||
|
||||
std::string const pattern = std::move(BuildRegexPattern(buffer.c_str(), length, caseInsensitive));
|
||||
std::string const pattern = BuildRegexPattern(buffer.c_str(), length, caseInsensitive);
|
||||
RegexMatcher* matcher = nullptr;
|
||||
|
||||
if (RegexCache != nullptr) {
|
||||
|
|
|
@ -667,10 +667,7 @@ class PropagateConstantAttributesHelper {
|
|||
TRI_ASSERT(name.empty());
|
||||
|
||||
while (attribute->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||
char const* attributeName = attribute->getStringValue();
|
||||
|
||||
TRI_ASSERT(attributeName != nullptr);
|
||||
name = std::string(".") + std::string(attributeName) + name;
|
||||
name = std::string(".") + std::string(attribute->getStringValue(), attribute->getStringLength()) + name;
|
||||
attribute = attribute->getMember(0);
|
||||
}
|
||||
|
||||
|
@ -1760,8 +1757,7 @@ static void FindVarAndAttr (ExecutionPlan const* plan,
|
|||
FindVarAndAttr(plan, node->getMember(0), enumCollVar, attr);
|
||||
|
||||
if (enumCollVar != nullptr) {
|
||||
char const* attributeName = node->getStringValue();
|
||||
attr.append(attributeName);
|
||||
attr.append(node->getStringValue(), node->getStringLength());
|
||||
attr.push_back('.');
|
||||
}
|
||||
return;
|
||||
|
@ -3213,7 +3209,7 @@ struct FilterCondition {
|
|||
attributeName.push_back('.');
|
||||
}
|
||||
|
||||
attributeName.append(node->getStringValue());
|
||||
attributeName.append(node->getStringValue(), node->getStringLength());
|
||||
}
|
||||
else if (node->type == NODE_TYPE_REFERENCE) {
|
||||
auto variable = static_cast<Variable const*>(node->getData());
|
||||
|
|
|
@ -252,10 +252,11 @@ void Parser::pushArrayElement (AstNode* node) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::pushObjectElement (char const* attributeName,
|
||||
size_t nameLength,
|
||||
AstNode* node) {
|
||||
auto object = static_cast<AstNode*>(peekStack());
|
||||
TRI_ASSERT(object->type == NODE_TYPE_OBJECT);
|
||||
auto element = _ast->createNodeObjectElement(attributeName, node);
|
||||
auto element = _ast->createNodeObjectElement(attributeName, nameLength, node);
|
||||
object->addMember(element);
|
||||
}
|
||||
|
||||
|
|
|
@ -286,7 +286,8 @@ namespace triagens {
|
|||
/// @brief push an AstNode into the object element on top of the stack
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void pushObjectElement (char const*,
|
||||
void pushObjectElement (char const*,
|
||||
size_t,
|
||||
AstNode*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -335,7 +335,7 @@ Query* Query::clone (QueryPart part,
|
|||
}
|
||||
|
||||
// clone all variables
|
||||
for (auto it : _ast->variables()->variables(true)) {
|
||||
for (auto& it : _ast->variables()->variables(true)) {
|
||||
auto var = _ast->variables()->getVariable(it.first);
|
||||
TRI_ASSERT(var != nullptr);
|
||||
clone->ast()->variables()->createVariable(var);
|
||||
|
@ -1055,8 +1055,7 @@ Executor* Query::executor () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* Query::registerString (char const* p,
|
||||
size_t length,
|
||||
bool mustUnescape) {
|
||||
size_t length) {
|
||||
|
||||
if (p == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
|
@ -1067,18 +1066,11 @@ char* Query::registerString (char const* p,
|
|||
return const_cast<char*>(EmptyString);
|
||||
}
|
||||
|
||||
char* copy = nullptr;
|
||||
if (mustUnescape) {
|
||||
size_t outLength;
|
||||
copy = TRI_UnescapeUtf8String(TRI_UNKNOWN_MEM_ZONE, p, length, &outLength);
|
||||
if (length < ShortStringStorage::MaxStringLength) {
|
||||
return _shortStringStorage.registerString(p, length);
|
||||
}
|
||||
else {
|
||||
if (length < ShortStringStorage::MaxStringLength) {
|
||||
return _shortStringStorage.registerString(p, length);
|
||||
}
|
||||
|
||||
copy = TRI_DuplicateString2Z(TRI_UNKNOWN_MEM_ZONE, p, length);
|
||||
}
|
||||
char* copy = TRI_DuplicateString2Z(TRI_UNKNOWN_MEM_ZONE, p, length);
|
||||
|
||||
if (copy == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
|
@ -1099,10 +1091,43 @@ char* Query::registerString (char const* p,
|
|||
/// the string is freed when the query is destroyed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* Query::registerString (std::string const& p,
|
||||
bool mustUnescape) {
|
||||
char* Query::registerString (std::string const& p) {
|
||||
return registerString(p.c_str(), p.length());
|
||||
}
|
||||
|
||||
return registerString(p.c_str(), p.length(), mustUnescape);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a potentially UTF-8-escaped string
|
||||
/// the string is freed when the query is destroyed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* Query::registerEscapedString (char const* p,
|
||||
size_t length,
|
||||
size_t& outLength) {
|
||||
|
||||
if (p == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
// optimization for the empty string
|
||||
outLength = 0;
|
||||
return const_cast<char*>(EmptyString);
|
||||
}
|
||||
|
||||
char* copy = TRI_UnescapeUtf8String(TRI_UNKNOWN_MEM_ZONE, p, length, &outLength);
|
||||
|
||||
if (copy == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
try {
|
||||
_strings.emplace_back(copy);
|
||||
}
|
||||
catch (...) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1249,18 +1274,18 @@ uint64_t Query::hash () const {
|
|||
// handle "fullCount" option. if this option is set, the query result will
|
||||
// be different to when it is not set!
|
||||
if (getBooleanOption("fullcount", false)) {
|
||||
hash = fasthash64("fullcount:true", strlen("fullcount:true"), hash);
|
||||
hash = fasthash64(TRI_CHAR_LENGTH_PAIR("fullcount:true"), hash);
|
||||
}
|
||||
else {
|
||||
hash = fasthash64("fullcount:false", strlen("fullcount:false"), hash);
|
||||
hash = fasthash64(TRI_CHAR_LENGTH_PAIR("fullcount:false"), hash);
|
||||
}
|
||||
|
||||
// handle "count" option
|
||||
if (getBooleanOption("count", false)) {
|
||||
hash = fasthash64("count:true", strlen("count:true"), hash);
|
||||
hash = fasthash64(TRI_CHAR_LENGTH_PAIR("count:true"), hash);
|
||||
}
|
||||
else {
|
||||
hash = fasthash64("count:false", strlen("count:false"), hash);
|
||||
hash = fasthash64(TRI_CHAR_LENGTH_PAIR("count:false"), hash);
|
||||
}
|
||||
|
||||
// blend query hash with bind parameters
|
||||
|
|
|
@ -385,16 +385,23 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* registerString (char const*,
|
||||
size_t,
|
||||
bool);
|
||||
size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a string
|
||||
/// the string is freed when the query is destroyed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* registerString (std::string const&,
|
||||
bool);
|
||||
char* registerString (std::string const&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a potentially UTF-8-escaped string
|
||||
/// the string is freed when the query is destroyed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* registerEscapedString (char const*,
|
||||
size_t,
|
||||
size_t&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the engine, if prepared
|
||||
|
|
|
@ -31,14 +31,13 @@
|
|||
#define ARANGODB_AQL_REST_AQL_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Dispatcher/Dispatcher.h"
|
||||
#include "Admin/RestBaseHandler.h"
|
||||
#include "V8Server/ApplicationV8.h"
|
||||
#include "RestServer/VocbaseContext.h"
|
||||
#include "RestHandler/RestVocbaseBaseHandler.h"
|
||||
#include "Aql/QueryRegistry.h"
|
||||
#include "Aql/types.h"
|
||||
#include "Dispatcher/Dispatcher.h"
|
||||
#include "RestHandler/RestBaseHandler.h"
|
||||
#include "RestHandler/RestVocbaseBaseHandler.h"
|
||||
#include "RestServer/VocbaseContext.h"
|
||||
#include "V8Server/ApplicationV8.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- forward declarations
|
||||
|
|
|
@ -95,8 +95,9 @@ void Scope::addVariable (Variable* variable) {
|
|||
/// @brief checks if a variable exists in the scope
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Scope::existsVariable (char const* name) const {
|
||||
return (getVariable(name) != nullptr);
|
||||
bool Scope::existsVariable (char const* name,
|
||||
size_t nameLength) const {
|
||||
return (getVariable(name, nameLength) != nullptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -111,8 +112,9 @@ bool Scope::existsVariable (std::string const& name) const {
|
|||
/// @brief returns a variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* Scope::getVariable (char const* name) const {
|
||||
std::string const varname(name);
|
||||
Variable const* Scope::getVariable (char const* name,
|
||||
size_t nameLength) const {
|
||||
std::string const varname(name, nameLength);
|
||||
|
||||
auto it = _variables.find(varname);
|
||||
|
||||
|
@ -143,17 +145,18 @@ Variable const* Scope::getVariable (std::string const& name) const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* Scope::getVariable (char const* name,
|
||||
size_t nameLength,
|
||||
bool allowSpecial) const {
|
||||
auto variable = getVariable(name);
|
||||
auto variable = getVariable(name, nameLength);
|
||||
|
||||
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);
|
||||
variable = getVariable(TRI_CHAR_LENGTH_PAIR(Variable::NAME_OLD));
|
||||
}
|
||||
else if (strcmp(name, "NEW") == 0) {
|
||||
variable = getVariable(Variable::NAME_NEW);
|
||||
variable = getVariable(TRI_CHAR_LENGTH_PAIR(Variable::NAME_NEW));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,15 +272,35 @@ void Scopes::addVariable (Variable* variable) {
|
|||
/// @brief checks whether a variable exists in any scope
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Scopes::existsVariable (char const* name) const {
|
||||
return (getVariable(name) != nullptr);
|
||||
bool Scopes::existsVariable (char const* name,
|
||||
size_t nameLength) const {
|
||||
return (getVariable(name, nameLength) != nullptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a variable by name - this respects the current scopes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* Scopes::getVariable (char const* name) const {
|
||||
Variable const* Scopes::getVariable (char const* name,
|
||||
size_t nameLength) const {
|
||||
TRI_ASSERT(! _activeScopes.empty());
|
||||
|
||||
for (auto it = _activeScopes.rbegin(); it != _activeScopes.rend(); ++it) {
|
||||
auto variable = (*it)->getVariable(name, nameLength);
|
||||
|
||||
if (variable != nullptr) {
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a variable by name - this respects the current scopes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* Scopes::getVariable (std::string const& name) const {
|
||||
TRI_ASSERT(! _activeScopes.empty());
|
||||
|
||||
for (auto it = _activeScopes.rbegin(); it != _activeScopes.rend(); ++it) {
|
||||
|
@ -296,11 +319,12 @@ Variable const* Scopes::getVariable (char const* name) const {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* Scopes::getVariable (char const* name,
|
||||
size_t nameLength,
|
||||
bool allowSpecial) const {
|
||||
TRI_ASSERT(! _activeScopes.empty());
|
||||
|
||||
for (auto it = _activeScopes.rbegin(); it != _activeScopes.rend(); ++it) {
|
||||
auto variable = (*it)->getVariable(name, allowSpecial);
|
||||
auto variable = (*it)->getVariable(name, nameLength, allowSpecial);
|
||||
|
||||
if (variable != nullptr) {
|
||||
return variable;
|
||||
|
|
|
@ -107,7 +107,8 @@ namespace triagens {
|
|||
/// @brief checks if a variable exists in the scope
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool existsVariable (char const*) const;
|
||||
bool existsVariable (char const*,
|
||||
size_t) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks if a variable exists in the scope
|
||||
|
@ -119,7 +120,8 @@ namespace triagens {
|
|||
/// @brief return a variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* getVariable (char const*) const;
|
||||
Variable const* getVariable (char const*,
|
||||
size_t) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a variable
|
||||
|
@ -132,7 +134,9 @@ namespace triagens {
|
|||
/// as OLD and NEW
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* getVariable (char const*, bool) const;
|
||||
Variable const* getVariable (char const*,
|
||||
size_t,
|
||||
bool) const;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
|
@ -241,20 +245,30 @@ namespace triagens {
|
|||
/// @brief checks whether a variable exists in any scope
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool existsVariable (char const*) const;
|
||||
bool existsVariable (char const*,
|
||||
size_t) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a variable by name - this respects the current scopes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* getVariable (char const*) const;
|
||||
Variable const* getVariable (char const*,
|
||||
size_t) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a variable by name - this respects the current scopes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable const* getVariable (std::string 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;
|
||||
Variable const* getVariable (char const*,
|
||||
size_t,
|
||||
bool) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the $CURRENT variable
|
||||
|
|
|
@ -87,17 +87,18 @@ std::unordered_map<VariableId, std::string const> VariableGenerator::variables (
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable* VariableGenerator::createVariable (char const* name,
|
||||
size_t length,
|
||||
bool isUserDefined) {
|
||||
TRI_ASSERT(name != nullptr);
|
||||
|
||||
auto variable = new Variable(std::string(name), nextId());
|
||||
auto variable = new Variable(std::string(name, length), nextId());
|
||||
|
||||
if (isUserDefined) {
|
||||
TRI_ASSERT(variable->isUserDefined());
|
||||
}
|
||||
|
||||
try {
|
||||
_variables.emplace(std::make_pair(variable->id, variable));
|
||||
_variables.emplace(variable->id, variable);
|
||||
}
|
||||
catch (...) {
|
||||
// prevent memleak
|
||||
|
@ -121,7 +122,7 @@ Variable* VariableGenerator::createVariable (std::string const& name,
|
|||
}
|
||||
|
||||
try {
|
||||
_variables.emplace(std::make_pair(variable->id, variable));
|
||||
_variables.emplace(variable->id, variable);
|
||||
}
|
||||
catch (...) {
|
||||
// prevent memleak
|
||||
|
@ -137,7 +138,7 @@ Variable* VariableGenerator::createVariable (Variable const* original) {
|
|||
auto variable = original->clone();
|
||||
|
||||
try {
|
||||
_variables.emplace(std::make_pair(variable->id, variable));
|
||||
_variables.emplace(variable->id, variable);
|
||||
}
|
||||
catch (...) {
|
||||
// prevent memleak
|
||||
|
@ -163,7 +164,7 @@ Variable* VariableGenerator::createVariable (triagens::basics::Json const& json)
|
|||
}
|
||||
|
||||
try {
|
||||
_variables.emplace(std::make_pair(variable->id, variable));
|
||||
_variables.emplace(variable->id, variable);
|
||||
}
|
||||
catch (...) {
|
||||
// prevent memleak
|
||||
|
|
|
@ -79,6 +79,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable* createVariable (char const*,
|
||||
size_t,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -116,11 +116,14 @@ union YYSTYPE
|
|||
#line 17 "arangod/Aql/grammar.y" /* yacc.c:1909 */
|
||||
|
||||
triagens::aql::AstNode* node;
|
||||
char* strval;
|
||||
struct {
|
||||
char* value;
|
||||
size_t length;
|
||||
} strval;
|
||||
bool boolval;
|
||||
int64_t intval;
|
||||
|
||||
#line 124 "arangod/Aql/grammar.hpp" /* yacc.c:1909 */
|
||||
#line 127 "arangod/Aql/grammar.hpp" /* yacc.c:1909 */
|
||||
};
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
%union {
|
||||
triagens::aql::AstNode* node;
|
||||
char* strval;
|
||||
struct {
|
||||
char* value;
|
||||
size_t length;
|
||||
} strval;
|
||||
bool boolval;
|
||||
int64_t intval;
|
||||
}
|
||||
|
@ -256,7 +259,7 @@ for_statement:
|
|||
T_FOR variable_name T_IN expression {
|
||||
parser->ast()->scopes()->start(triagens::aql::AQL_SCOPE_FOR);
|
||||
|
||||
auto node = parser->ast()->createNodeFor($2, $4);
|
||||
auto node = parser->ast()->createNodeFor($2.value, $2.length, $4, true);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
;
|
||||
|
@ -283,15 +286,15 @@ let_list:
|
|||
|
||||
let_element:
|
||||
variable_name T_ASSIGN expression {
|
||||
auto node = parser->ast()->createNodeLet($1, $3, true);
|
||||
auto node = parser->ast()->createNodeLet($1.value, $1.length, $3, true);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
;
|
||||
|
||||
count_into:
|
||||
T_WITH T_STRING T_INTO variable_name {
|
||||
if (! TRI_CaseEqualString($2, "COUNT")) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected qualifier '%s', expecting 'COUNT'", $2, yylloc.first_line, yylloc.first_column);
|
||||
if (! TRI_CaseEqualString($2.value, "COUNT")) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected qualifier '%s', expecting 'COUNT'", $2.value, yylloc.first_line, yylloc.first_column);
|
||||
}
|
||||
|
||||
$$ = $4;
|
||||
|
@ -326,7 +329,7 @@ collect_statement:
|
|||
scopes->start(triagens::aql::AQL_SCOPE_COLLECT);
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeCollectCount(parser->ast()->createNodeArray(), $2, $3);
|
||||
auto node = parser->ast()->createNodeCollectCount(parser->ast()->createNodeArray(), $2.value, $2.length, $3);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| collect_variable_list count_into options {
|
||||
|
@ -353,7 +356,7 @@ collect_statement:
|
|||
}
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeCollectCount($1, $2, $3);
|
||||
auto node = parser->ast()->createNodeCollectCount($1, $2.value, $2.length, $3);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| collect_variable_list optional_into options {
|
||||
|
@ -380,7 +383,7 @@ collect_statement:
|
|||
}
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeCollect($1, $2, nullptr, $3);
|
||||
auto node = parser->ast()->createNodeCollect($1, $2.value, $2.length, nullptr, $3);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| collect_variable_list optional_into keep options {
|
||||
|
@ -407,12 +410,12 @@ collect_statement:
|
|||
}
|
||||
}
|
||||
|
||||
if ($2 == nullptr &&
|
||||
if ($2.value == nullptr &&
|
||||
$3 != nullptr) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "use of 'KEEP' without 'INTO'", yylloc.first_line, yylloc.first_column);
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeCollect($1, $2, $3, $4);
|
||||
auto node = parser->ast()->createNodeCollect($1, $2.value, $2.length, $3, $4);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
| collect_variable_list T_INTO variable_name T_ASSIGN expression options {
|
||||
|
@ -439,7 +442,7 @@ collect_statement:
|
|||
}
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeCollectExpression($1, $3, $5, $6);
|
||||
auto node = parser->ast()->createNodeCollectExpression($1, $3.value, $3.length, $5, $6);
|
||||
parser->ast()->addOperation(node);
|
||||
}
|
||||
;
|
||||
|
@ -453,27 +456,29 @@ collect_list:
|
|||
|
||||
collect_element:
|
||||
variable_name T_ASSIGN expression {
|
||||
auto node = parser->ast()->createNodeAssign($1, $3);
|
||||
auto node = parser->ast()->createNodeAssign($1.value, $1.length, $3);
|
||||
parser->pushArrayElement(node);
|
||||
}
|
||||
;
|
||||
|
||||
optional_into:
|
||||
/* empty */ {
|
||||
$$ = nullptr;
|
||||
$$.value = nullptr;
|
||||
$$.length = 0;
|
||||
}
|
||||
| T_INTO variable_name {
|
||||
$$ = $2;
|
||||
$$.value = $2.value;
|
||||
$$.length = $2.length;
|
||||
}
|
||||
;
|
||||
|
||||
variable_list:
|
||||
variable_name {
|
||||
if (! parser->ast()->scopes()->existsVariable($1)) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "use of unknown variable '%s' for KEEP", $1, yylloc.first_line, yylloc.first_column);
|
||||
if (! parser->ast()->scopes()->existsVariable($1.value, $1.length)) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "use of unknown variable '%s' for KEEP", $1.value, yylloc.first_line, yylloc.first_column);
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeReference($1);
|
||||
auto node = parser->ast()->createNodeReference($1.value, $1.length);
|
||||
if (node == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
@ -483,11 +488,11 @@ variable_list:
|
|||
parser->pushArrayElement(node);
|
||||
}
|
||||
| variable_list T_COMMA variable_name {
|
||||
if (! parser->ast()->scopes()->existsVariable($3)) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "use of unknown variable '%s' for KEEP", $3, yylloc.first_line, yylloc.first_column);
|
||||
if (! parser->ast()->scopes()->existsVariable($3.value, $3.length)) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "use of unknown variable '%s' for KEEP", $3.value, yylloc.first_line, yylloc.first_column);
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeReference($3);
|
||||
auto node = parser->ast()->createNodeReference($3.value, $3.length);
|
||||
if (node == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
@ -500,8 +505,8 @@ variable_list:
|
|||
|
||||
keep:
|
||||
T_STRING {
|
||||
if (! TRI_CaseEqualString($1, "KEEP")) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected qualifier '%s', expecting 'KEEP'", $1, yylloc.first_line, yylloc.first_column);
|
||||
if (! TRI_CaseEqualString($1.value, "KEEP")) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected qualifier '%s', expecting 'KEEP'", $1.value, yylloc.first_line, yylloc.first_column);
|
||||
}
|
||||
|
||||
auto node = parser->ast()->createNodeArray();
|
||||
|
@ -669,7 +674,7 @@ upsert_statement:
|
|||
T_UPSERT {
|
||||
// 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));
|
||||
parser->pushStack(parser->ast()->createNodeVariable(TRI_CHAR_LENGTH_PAIR(Variable::NAME_OLD), true));
|
||||
} expression T_INSERT expression update_or_replace expression in_or_into_collection options {
|
||||
if (! parser->configureWriteQuery(AQL_QUERY_UPSERT, $8, $9)) {
|
||||
YYABORT;
|
||||
|
@ -684,10 +689,10 @@ upsert_statement:
|
|||
|
||||
scopes->start(triagens::aql::AQL_SCOPE_FOR);
|
||||
std::string const variableName = std::move(parser->ast()->variables()->nextName());
|
||||
auto forNode = parser->ast()->createNodeFor(variableName.c_str(), $8, false);
|
||||
auto forNode = parser->ast()->createNodeFor(variableName.c_str(), variableName.size(), $8, false);
|
||||
parser->ast()->addOperation(forNode);
|
||||
|
||||
auto filterNode = parser->ast()->createNodeUpsertFilter(parser->ast()->createNodeReference(variableName.c_str()), $3);
|
||||
auto filterNode = parser->ast()->createNodeUpsertFilter(parser->ast()->createNodeReference(variableName), $3);
|
||||
parser->ast()->addOperation(filterNode);
|
||||
|
||||
auto offsetValue = parser->ast()->createNodeValueInt(0);
|
||||
|
@ -695,7 +700,7 @@ upsert_statement:
|
|||
auto limitNode = parser->ast()->createNodeLimit(offsetValue, limitValue);
|
||||
parser->ast()->addOperation(limitNode);
|
||||
|
||||
auto refNode = parser->ast()->createNodeReference(variableName.c_str());
|
||||
auto refNode = parser->ast()->createNodeReference(variableName);
|
||||
auto returnNode = parser->ast()->createNodeReturn(refNode);
|
||||
parser->ast()->addOperation(returnNode);
|
||||
scopes->endNested();
|
||||
|
@ -704,14 +709,14 @@ upsert_statement:
|
|||
scopes->endCurrent();
|
||||
|
||||
std::string const subqueryName = std::move(parser->ast()->variables()->nextName());
|
||||
auto subQuery = parser->ast()->createNodeLet(subqueryName.c_str(), subqueryNode, false);
|
||||
auto subQuery = parser->ast()->createNodeLet(subqueryName.c_str(), subqueryName.size(), subqueryNode, false);
|
||||
parser->ast()->addOperation(subQuery);
|
||||
|
||||
auto index = parser->ast()->createNodeValueInt(0);
|
||||
auto firstDoc = parser->ast()->createNodeLet(variableNode, parser->ast()->createNodeIndexedAccess(parser->ast()->createNodeReference(subqueryName.c_str()), index));
|
||||
auto firstDoc = parser->ast()->createNodeLet(variableNode, parser->ast()->createNodeIndexedAccess(parser->ast()->createNodeReference(subqueryName), index));
|
||||
parser->ast()->addOperation(firstDoc);
|
||||
|
||||
auto node = parser->ast()->createNodeUpsert(static_cast<AstNodeType>($6), parser->ast()->createNodeReference(Variable::NAME_OLD), $5, $7, $8, $9);
|
||||
auto node = parser->ast()->createNodeUpsert(static_cast<AstNodeType>($6), parser->ast()->createNodeReference(TRI_CHAR_LENGTH_PAIR(Variable::NAME_OLD)), $5, $7, $8, $9);
|
||||
parser->ast()->addOperation(node);
|
||||
parser->setWriteNode(node);
|
||||
}
|
||||
|
@ -757,30 +762,25 @@ expression:
|
|||
function_name:
|
||||
T_STRING {
|
||||
$$ = $1;
|
||||
|
||||
if ($$ == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
}
|
||||
| function_name T_SCOPE T_STRING {
|
||||
if ($1 == nullptr || $3 == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
std::string temp($1);
|
||||
std::string temp($1.value, $1.length);
|
||||
temp.append("::");
|
||||
temp.append($3);
|
||||
$$ = parser->query()->registerString(temp.c_str(), temp.size(), false);
|
||||
temp.append($3.value, $3.length);
|
||||
auto p = parser->query()->registerString(temp);
|
||||
|
||||
if ($$ == nullptr) {
|
||||
if (p == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
$$.value = p;
|
||||
$$.length = temp.size();
|
||||
}
|
||||
;
|
||||
|
||||
function_call:
|
||||
function_name {
|
||||
parser->pushStack($1);
|
||||
parser->pushStack($1.value);
|
||||
|
||||
auto node = parser->ast()->createNodeArray();
|
||||
parser->pushStack(node);
|
||||
|
@ -878,10 +878,10 @@ expression_or_query:
|
|||
parser->ast()->scopes()->endCurrent();
|
||||
|
||||
std::string const variableName = std::move(parser->ast()->variables()->nextName());
|
||||
auto subQuery = parser->ast()->createNodeLet(variableName.c_str(), node, false);
|
||||
auto subQuery = parser->ast()->createNodeLet(variableName.c_str(), variableName.size(), node, false);
|
||||
parser->ast()->addOperation(subQuery);
|
||||
|
||||
$$ = parser->ast()->createNodeReference(variableName.c_str());
|
||||
$$ = parser->ast()->createNodeReference(variableName);
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -933,12 +933,12 @@ options:
|
|||
$$ = nullptr;
|
||||
}
|
||||
| T_STRING object {
|
||||
if ($1 == nullptr || $2 == nullptr) {
|
||||
if ($2 == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (! TRI_CaseEqualString($1, "OPTIONS")) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected qualifier '%s', expecting 'OPTIONS'", $1, yylloc.first_line, yylloc.first_column);
|
||||
if (! TRI_CaseEqualString($1.value, "OPTIONS")) {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "unexpected qualifier '%s', expecting 'OPTIONS'", $1.value, yylloc.first_line, yylloc.first_column);
|
||||
}
|
||||
|
||||
$$ = $2;
|
||||
|
@ -972,32 +972,28 @@ 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, true);
|
||||
auto variable = ast->scopes()->getVariable($1.value, $1.length, true);
|
||||
|
||||
if (variable == nullptr) {
|
||||
// variable does not exist
|
||||
parser->registerParseError(TRI_ERROR_QUERY_VARIABLE_NAME_UNKNOWN, "use of unknown variable '%s' in object literal", $1, yylloc.first_line, yylloc.first_column);
|
||||
parser->registerParseError(TRI_ERROR_QUERY_VARIABLE_NAME_UNKNOWN, "use of unknown variable '%s' in object literal", $1.value, yylloc.first_line, yylloc.first_column);
|
||||
}
|
||||
|
||||
// create a reference to the variable
|
||||
auto node = ast->createNodeReference(variable);
|
||||
parser->pushObjectElement($1, node);
|
||||
parser->pushObjectElement($1.value, $1.length, node);
|
||||
}
|
||||
| object_element_name T_COLON expression {
|
||||
// attribute-name : attribute-value
|
||||
parser->pushObjectElement($1, $3);
|
||||
parser->pushObjectElement($1.value, $1.length, $3);
|
||||
}
|
||||
| T_PARAMETER T_COLON expression {
|
||||
// bind-parameter : attribute-value
|
||||
if ($1 == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (strlen($1) < 1 || $1[0] == '@') {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE, TRI_errno_string(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE), $1, yylloc.first_line, yylloc.first_column);
|
||||
if ($1.length < 1 || $1.value[0] == '@') {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE, TRI_errno_string(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE), $1.value, yylloc.first_line, yylloc.first_column);
|
||||
}
|
||||
|
||||
auto param = parser->ast()->createNodeParameter($1);
|
||||
auto param = parser->ast()->createNodeParameter($1.value, $1.length);
|
||||
parser->pushObjectElement(param, $3);
|
||||
}
|
||||
| T_ARRAY_OPEN expression T_ARRAY_CLOSE T_COLON expression {
|
||||
|
@ -1051,15 +1047,15 @@ reference:
|
|||
auto ast = parser->ast();
|
||||
AstNode* node = nullptr;
|
||||
|
||||
auto variable = ast->scopes()->getVariable($1, true);
|
||||
auto variable = ast->scopes()->getVariable($1.value, $1.length, true);
|
||||
|
||||
if (variable == nullptr) {
|
||||
// variable does not exist
|
||||
// now try special variables
|
||||
if (ast->scopes()->canUseCurrentVariable() && strcmp($1, "CURRENT") == 0) {
|
||||
if (ast->scopes()->canUseCurrentVariable() && strcmp($1.value, "CURRENT") == 0) {
|
||||
variable = ast->scopes()->getCurrentVariable();
|
||||
}
|
||||
else if (strcmp($1, Variable::NAME_CURRENT) == 0) {
|
||||
else if (strcmp($1.value, Variable::NAME_CURRENT) == 0) {
|
||||
variable = ast->scopes()->getCurrentVariable();
|
||||
}
|
||||
}
|
||||
|
@ -1071,7 +1067,7 @@ reference:
|
|||
|
||||
if (node == nullptr) {
|
||||
// variable not found. so it must have been a collection
|
||||
node = ast->createNodeCollection($1, TRI_TRANSACTION_READ);
|
||||
node = ast->createNodeCollection($1.value, TRI_TRANSACTION_READ);
|
||||
}
|
||||
|
||||
TRI_ASSERT(node != nullptr);
|
||||
|
@ -1112,10 +1108,10 @@ reference:
|
|||
parser->ast()->scopes()->endCurrent();
|
||||
|
||||
std::string const variableName = std::move(parser->ast()->variables()->nextName());
|
||||
auto subQuery = parser->ast()->createNodeLet(variableName.c_str(), node, false);
|
||||
auto subQuery = parser->ast()->createNodeLet(variableName.c_str(), variableName.size(), node, false);
|
||||
parser->ast()->addOperation(subQuery);
|
||||
|
||||
$$ = parser->ast()->createNodeReference(variableName.c_str());
|
||||
$$ = parser->ast()->createNodeReference(variableName);
|
||||
}
|
||||
| reference '.' T_STRING %prec REFERENCE {
|
||||
// named variable access, e.g. variable.reference
|
||||
|
@ -1125,11 +1121,11 @@ reference:
|
|||
// patch the bottom-most one
|
||||
auto current = const_cast<AstNode*>(parser->ast()->findExpansionSubNode($1));
|
||||
TRI_ASSERT(current->type == NODE_TYPE_EXPANSION);
|
||||
current->changeMember(1, parser->ast()->createNodeAttributeAccess(current->getMember(1), $3));
|
||||
current->changeMember(1, parser->ast()->createNodeAttributeAccess(current->getMember(1), $3.value, $3.length));
|
||||
$$ = $1;
|
||||
}
|
||||
else {
|
||||
$$ = parser->ast()->createNodeAttributeAccess($1, $3);
|
||||
$$ = parser->ast()->createNodeAttributeAccess($1, $3.value, $3.length);
|
||||
}
|
||||
}
|
||||
| reference '.' bind_parameter %prec REFERENCE {
|
||||
|
@ -1170,19 +1166,18 @@ reference:
|
|||
|
||||
// create a temporary iterator variable
|
||||
std::string const nextName = parser->ast()->variables()->nextName() + "_";
|
||||
char const* iteratorName = nextName.c_str();
|
||||
|
||||
if ($1->type == NODE_TYPE_EXPANSION) {
|
||||
auto iterator = parser->ast()->createNodeIterator(iteratorName, $1->getMember(1));
|
||||
auto iterator = parser->ast()->createNodeIterator(nextName.c_str(), nextName.size(), $1->getMember(1));
|
||||
parser->pushStack(iterator);
|
||||
}
|
||||
else {
|
||||
auto iterator = parser->ast()->createNodeIterator(iteratorName, $1);
|
||||
auto iterator = parser->ast()->createNodeIterator(nextName.c_str(), nextName.size(), $1);
|
||||
parser->pushStack(iterator);
|
||||
}
|
||||
|
||||
auto scopes = parser->ast()->scopes();
|
||||
scopes->stackCurrentVariable(scopes->getVariable(iteratorName));
|
||||
scopes->stackCurrentVariable(scopes->getVariable(nextName));
|
||||
} optional_array_filter optional_array_limit optional_array_return T_ARRAY_CLOSE %prec EXPANSION {
|
||||
auto scopes = parser->ast()->scopes();
|
||||
scopes->unstackCurrentVariable();
|
||||
|
@ -1193,12 +1188,12 @@ reference:
|
|||
auto variable = static_cast<Variable const*>(variableNode->getData());
|
||||
|
||||
if ($1->type == NODE_TYPE_EXPANSION) {
|
||||
auto expand = parser->ast()->createNodeExpansion($3, iterator, parser->ast()->createNodeReference(variable->name.c_str()), $5, $6, $7);
|
||||
auto expand = parser->ast()->createNodeExpansion($3, iterator, parser->ast()->createNodeReference(variable->name), $5, $6, $7);
|
||||
$1->changeMember(1, expand);
|
||||
$$ = $1;
|
||||
}
|
||||
else {
|
||||
$$ = parser->ast()->createNodeExpansion($3, iterator, parser->ast()->createNodeReference(variable->name.c_str()), $5, $6, $7);
|
||||
$$ = parser->ast()->createNodeExpansion($3, iterator, parser->ast()->createNodeReference(variable->name), $5, $6, $7);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
@ -1231,7 +1226,7 @@ numeric_value:
|
|||
|
||||
value_literal:
|
||||
T_QUOTED_STRING {
|
||||
$$ = parser->ast()->createNodeValueString($1);
|
||||
$$ = parser->ast()->createNodeValueString($1.value, $1.length);
|
||||
}
|
||||
| numeric_value {
|
||||
$$ = $1;
|
||||
|
@ -1249,51 +1244,31 @@ value_literal:
|
|||
|
||||
collection_name:
|
||||
T_STRING {
|
||||
if ($1 == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
$$ = parser->ast()->createNodeCollection($1, TRI_TRANSACTION_WRITE);
|
||||
$$ = parser->ast()->createNodeCollection($1.value, TRI_TRANSACTION_WRITE);
|
||||
}
|
||||
| T_QUOTED_STRING {
|
||||
if ($1 == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
$$ = parser->ast()->createNodeCollection($1, TRI_TRANSACTION_WRITE);
|
||||
$$ = parser->ast()->createNodeCollection($1.value, TRI_TRANSACTION_WRITE);
|
||||
}
|
||||
| T_PARAMETER {
|
||||
if ($1 == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (strlen($1) < 2 || $1[0] != '@') {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE, TRI_errno_string(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE), $1, yylloc.first_line, yylloc.first_column);
|
||||
if ($1.length < 2 || $1.value[0] != '@') {
|
||||
parser->registerParseError(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE, TRI_errno_string(TRI_ERROR_QUERY_BIND_PARAMETER_TYPE), $1.value, yylloc.first_line, yylloc.first_column);
|
||||
}
|
||||
|
||||
$$ = parser->ast()->createNodeParameter($1);
|
||||
$$ = parser->ast()->createNodeParameter($1.value, $1.length);
|
||||
}
|
||||
;
|
||||
|
||||
bind_parameter:
|
||||
T_PARAMETER {
|
||||
$$ = parser->ast()->createNodeParameter($1);
|
||||
$$ = parser->ast()->createNodeParameter($1.value, $1.length);
|
||||
}
|
||||
;
|
||||
|
||||
object_element_name:
|
||||
T_STRING {
|
||||
if ($1 == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
$$ = $1;
|
||||
}
|
||||
| T_QUOTED_STRING {
|
||||
if ($1 == nullptr) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
$$ = $1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1349,7 +1349,8 @@ case 51:
|
|||
YY_RULE_SETUP
|
||||
{
|
||||
/* unquoted string */
|
||||
yylval->strval = yyextra->query()->registerString(yytext, yyleng, false);
|
||||
yylval->strval.value = yyextra->query()->registerString(yytext, yyleng);
|
||||
yylval->strval.length = yyleng;
|
||||
return T_STRING;
|
||||
}
|
||||
YY_BREAK
|
||||
|
@ -1366,7 +1367,9 @@ YY_RULE_SETUP
|
|||
{
|
||||
/* end of backtick-enclosed string */
|
||||
BEGIN(INITIAL);
|
||||
yylval->strval = yyextra->query()->registerString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, true);
|
||||
size_t outLength;
|
||||
yylval->strval.value = yyextra->query()->registerEscapedString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, outLength);
|
||||
yylval->strval.length = outLength;
|
||||
return T_STRING;
|
||||
}
|
||||
YY_BREAK
|
||||
|
@ -1404,7 +1407,9 @@ YY_RULE_SETUP
|
|||
{
|
||||
/* end of quote-enclosed string */
|
||||
BEGIN(INITIAL);
|
||||
yylval->strval = yyextra->query()->registerString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, true);
|
||||
size_t outLength;
|
||||
yylval->strval.value = yyextra->query()->registerEscapedString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, outLength);
|
||||
yylval->strval.length = outLength;
|
||||
return T_QUOTED_STRING;
|
||||
}
|
||||
YY_BREAK
|
||||
|
@ -1442,7 +1447,9 @@ YY_RULE_SETUP
|
|||
{
|
||||
/* end of quote-enclosed string */
|
||||
BEGIN(INITIAL);
|
||||
yylval->strval = yyextra->query()->registerString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, true);
|
||||
size_t outLength;
|
||||
yylval->strval.value = yyextra->query()->registerEscapedString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, outLength);
|
||||
yylval->strval.length = outLength;
|
||||
return T_QUOTED_STRING;
|
||||
}
|
||||
YY_BREAK
|
||||
|
@ -1525,7 +1532,8 @@ YY_RULE_SETUP
|
|||
{
|
||||
/* bind parameters must start with a @
|
||||
if followed by another @, this is a collection name parameter */
|
||||
yylval->strval = yyextra->query()->registerString(yytext + 1, yyleng - 1, false);
|
||||
yylval->strval.value = yyextra->query()->registerString(yytext + 1, yyleng - 1);
|
||||
yylval->strval.length = yyleng - 1;
|
||||
return T_PARAMETER;
|
||||
}
|
||||
YY_BREAK
|
||||
|
|
|
@ -279,7 +279,8 @@ namespace triagens {
|
|||
|
||||
($?[a-zA-Z][_a-zA-Z0-9]*|_+[a-zA-Z]+[_a-zA-Z0-9]*) {
|
||||
/* unquoted string */
|
||||
yylval->strval = yyextra->query()->registerString(yytext, yyleng, false);
|
||||
yylval->strval.value = yyextra->query()->registerString(yytext, yyleng);
|
||||
yylval->strval.length = yyleng;
|
||||
return T_STRING;
|
||||
}
|
||||
|
||||
|
@ -292,7 +293,9 @@ namespace triagens {
|
|||
<BACKTICK>` {
|
||||
/* end of backtick-enclosed string */
|
||||
BEGIN(INITIAL);
|
||||
yylval->strval = yyextra->query()->registerString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, true);
|
||||
size_t outLength;
|
||||
yylval->strval.value = yyextra->query()->registerEscapedString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, outLength);
|
||||
yylval->strval.length = outLength;
|
||||
return T_STRING;
|
||||
}
|
||||
|
||||
|
@ -319,7 +322,9 @@ namespace triagens {
|
|||
<DOUBLE_QUOTE>\" {
|
||||
/* end of quote-enclosed string */
|
||||
BEGIN(INITIAL);
|
||||
yylval->strval = yyextra->query()->registerString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, true);
|
||||
size_t outLength;
|
||||
yylval->strval.value = yyextra->query()->registerEscapedString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, outLength);
|
||||
yylval->strval.length = outLength;
|
||||
return T_QUOTED_STRING;
|
||||
}
|
||||
|
||||
|
@ -346,7 +351,9 @@ namespace triagens {
|
|||
<SINGLE_QUOTE>' {
|
||||
/* end of quote-enclosed string */
|
||||
BEGIN(INITIAL);
|
||||
yylval->strval = yyextra->query()->registerString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, true);
|
||||
size_t outLength;
|
||||
yylval->strval.value = yyextra->query()->registerEscapedString(yyextra->marker(), yyextra->offset() - (yyextra->marker() - yyextra->queryString()) - 1, outLength);
|
||||
yylval->strval.length = outLength;
|
||||
return T_QUOTED_STRING;
|
||||
}
|
||||
|
||||
|
@ -417,7 +424,8 @@ namespace triagens {
|
|||
@@?(_+[a-zA-Z0-9]+[a-zA-Z0-9_]*|[a-zA-Z0-9][a-zA-Z0-9_]*) {
|
||||
/* bind parameters must start with a @
|
||||
if followed by another @, this is a collection name parameter */
|
||||
yylval->strval = yyextra->query()->registerString(yytext + 1, yyleng - 1, false);
|
||||
yylval->strval.value = yyextra->query()->registerString(yytext + 1, yyleng - 1);
|
||||
yylval->strval.length = yyleng - 1;
|
||||
return T_PARAMETER;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,13 +58,6 @@ add_executable(
|
|||
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
|
||||
|
@ -153,20 +146,26 @@ add_executable(
|
|||
Replication/InitialSyncer.cpp
|
||||
Replication/Syncer.cpp
|
||||
Rest/AnyServer.cpp
|
||||
Rest/Handler.cpp
|
||||
RestHandler/RestAdminBaseHandler.cpp
|
||||
RestHandler/RestAdminLogHandler.cpp
|
||||
RestHandler/RestBaseHandler.cpp
|
||||
RestHandler/RestBatchHandler.cpp
|
||||
RestHandler/RestDebugHelperHandler.cpp
|
||||
RestHandler/RestCursorHandler.cpp
|
||||
RestHandler/RestDocumentHandler.cpp
|
||||
RestHandler/RestEdgeHandler.cpp
|
||||
RestHandler/RestExportHandler.cpp
|
||||
RestHandler/RestImportHandler.cpp
|
||||
RestHandler/RestJobHandler.cpp
|
||||
RestHandler/RestPleaseUpgradeHandler.cpp
|
||||
RestHandler/RestQueryCacheHandler.cpp
|
||||
RestHandler/RestQueryHandler.cpp
|
||||
RestHandler/RestReplicationHandler.cpp
|
||||
RestHandler/RestShutdownHandler.cpp
|
||||
RestHandler/RestSimpleHandler.cpp
|
||||
RestHandler/RestSimpleQueryHandler.cpp
|
||||
RestHandler/RestUploadHandler.cpp
|
||||
RestHandler/RestVersionHandler.cpp
|
||||
RestHandler/RestVocbaseBaseHandler.cpp
|
||||
RestServer/ArangoServer.cpp
|
||||
RestServer/ConsoleThread.cpp
|
||||
|
@ -297,7 +296,7 @@ install_config(arango-dfdb)
|
|||
|
||||
install(
|
||||
DIRECTORY ${PROJECT_BINARY_DIR}/js
|
||||
DESTINATION share/arangodb/js)
|
||||
DESTINATION share/arangodb)
|
||||
|
||||
################################################################################
|
||||
### @brief install log directory
|
||||
|
|
|
@ -28,15 +28,14 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RestShardHandler.h"
|
||||
|
||||
#include "Basics/ConditionLocker.h"
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "Cluster/ClusterComm.h"
|
||||
#include "Dispatcher/Dispatcher.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
#include "HttpServer/HttpServer.h"
|
||||
#include "HttpServer/HttpHandlerFactory.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace triagens::arango;
|
||||
|
|
|
@ -31,8 +31,7 @@
|
|||
#define ARANGODB_CLUSTER_REST_SHARD_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Admin/RestBaseHandler.h"
|
||||
#include "RestHandler/RestBaseHandler.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "Basics/Exceptions.h"
|
||||
#include "Basics/Mutex.h"
|
||||
#include "Dispatcher/Job.h"
|
||||
#include "Rest/Handler.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
|
||||
struct TRI_server_t;
|
||||
|
||||
|
@ -118,7 +118,7 @@ namespace triagens {
|
|||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void cleanup (rest::DispatcherQueue* queue);
|
||||
void cleanup (rest::DispatcherQueue* queue) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
|
@ -133,7 +133,7 @@ namespace triagens {
|
|||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void handleError (basics::Exception const& ex) {
|
||||
void handleError (basics::Exception const& ex) override {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief abstract class for handlers
|
||||
/// @brief abstract class for http handlers
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
|
@ -28,8 +28,8 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HttpHandler.h"
|
||||
|
||||
#include "Basics/logging.h"
|
||||
#include "Dispatcher/Dispatcher.h"
|
||||
#include "HttpServer/HttpServerJob.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
|
||||
|
@ -48,7 +48,8 @@ using namespace triagens::rest;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler::HttpHandler (HttpRequest* request)
|
||||
: _request(request),
|
||||
: _dispatcherThread(nullptr),
|
||||
_request(request),
|
||||
_response(nullptr),
|
||||
_server(nullptr) {
|
||||
}
|
||||
|
@ -66,6 +67,45 @@ HttpHandler::~HttpHandler () {
|
|||
// --SECTION-- virtual public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the queue name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t HttpHandler::queue () const {
|
||||
return Dispatcher::STANDARD_QUEUE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the thread which currently dealing with the job
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandler::setDispatcherThread (DispatcherThread* dispatcherThread) {
|
||||
_dispatcherThread = dispatcherThread;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief prepares for execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandler::prepareExecute () {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tries to cancel an execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HttpHandler::finalizeExecute () {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tries to cancel an execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool HttpHandler::cancel () {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds a response
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -30,9 +30,11 @@
|
|||
#ifndef ARANGODB_HTTP_SERVER_HTTP_HANDLER_H
|
||||
#define ARANGODB_HTTP_SERVER_HTTP_HANDLER_H 1
|
||||
|
||||
#include "Rest/Handler.h"
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/Exceptions.h"
|
||||
#include "Dispatcher/Job.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
#include "Statistics/StatisticsAgent.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- forward declarations
|
||||
|
@ -40,8 +42,10 @@
|
|||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
class Dispatcher;
|
||||
class HttpHandlerFactory;
|
||||
class HttpRequest;
|
||||
class HttpServer;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class HttpHandler
|
||||
|
@ -51,7 +55,7 @@ namespace triagens {
|
|||
/// @brief abstract class for http handlers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HttpHandler : public Handler {
|
||||
class HttpHandler : public RequestStatisticsAgent {
|
||||
HttpHandler (HttpHandler const&) = delete;
|
||||
HttpHandler& operator= (HttpHandler const&) = delete;
|
||||
|
||||
|
@ -75,7 +79,59 @@ namespace triagens {
|
|||
/// @brief destructs a handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
~HttpHandler ();
|
||||
virtual ~HttpHandler ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief status of execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum status_e {
|
||||
HANDLER_DONE,
|
||||
HANDLER_REQUEUE,
|
||||
HANDLER_FAILED
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief result of execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class status_t {
|
||||
public:
|
||||
status_t ()
|
||||
: status(HANDLER_FAILED) {
|
||||
}
|
||||
|
||||
explicit
|
||||
status_t (status_e status)
|
||||
: status(status) {
|
||||
}
|
||||
|
||||
Job::status_t jobStatus () {
|
||||
switch (status) {
|
||||
case HttpHandler::HANDLER_DONE:
|
||||
return Job::status_t(Job::JOB_DONE);
|
||||
|
||||
case HttpHandler::HANDLER_REQUEUE: {
|
||||
Job::status_t result(Job::JOB_REQUEUE);
|
||||
result.sleep = sleep;
|
||||
return result;
|
||||
}
|
||||
|
||||
case HttpHandler::HANDLER_FAILED:
|
||||
default:
|
||||
return Job::status_t(Job::JOB_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
status_e status;
|
||||
double sleep;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- virtual public methods
|
||||
|
@ -83,6 +139,55 @@ namespace triagens {
|
|||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true if a handler is executed directly
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual bool isDirect () const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the queue name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual size_t queue () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the thread which currently dealing with the job
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void setDispatcherThread (DispatcherThread*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief prepares execution of a handler, has to be called before execute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void prepareExecute ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes a handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual status_t execute () = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief finalizes execution of a handler, has to be called after execute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void finalizeExecute ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tries to cancel an execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual bool cancel ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handles error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void handleError (basics::Exception const&) = 0;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds a response
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -149,6 +254,12 @@ namespace triagens {
|
|||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief current dispatcher thread
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DispatcherThread* _dispatcherThread;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the request
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace {
|
|||
return status_t(HANDLER_DONE);
|
||||
};
|
||||
|
||||
void handleError (const Exception& error) {
|
||||
void handleError (const Exception& error) override {
|
||||
_response = createResponse(HttpResponse::SERVICE_UNAVAILABLE);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -349,9 +349,9 @@ bool HttpServer::handleRequest (HttpCommTask* task,
|
|||
while (true) {
|
||||
// directly execute the handler within the scheduler thread
|
||||
if (handler->isDirect()) {
|
||||
Handler::status_t status = handleRequestDirectly(task, handler.get());
|
||||
HttpHandler::status_t status = handleRequestDirectly(task, handler.get());
|
||||
|
||||
if (status.status != Handler::HANDLER_REQUEUE) {
|
||||
if (status.status != HttpHandler::HANDLER_REQUEUE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -438,8 +438,8 @@ bool HttpServer::openEndpoint (Endpoint* endpoint) {
|
|||
/// @brief handle request directly
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler::status_t HttpServer::handleRequestDirectly (HttpCommTask* task, HttpHandler* handler) {
|
||||
Handler::status_t status(Handler::HANDLER_FAILED);
|
||||
HttpHandler::status_t HttpServer::handleRequestDirectly (HttpCommTask* task, HttpHandler* handler) {
|
||||
HttpHandler::status_t status(HttpHandler::HANDLER_FAILED);
|
||||
|
||||
RequestStatisticsAgentSetRequestStart(handler);
|
||||
|
||||
|
@ -469,7 +469,7 @@ Handler::status_t HttpServer::handleRequestDirectly (HttpCommTask* task, HttpHan
|
|||
|
||||
handler->finalizeExecute();
|
||||
|
||||
if (status.status == Handler::HANDLER_REQUEUE) {
|
||||
if (status.status == HttpHandler::HANDLER_REQUEUE) {
|
||||
handler->RequestStatisticsAgent::transfer(task);
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -32,11 +32,11 @@
|
|||
#ifndef ARANGODB_HTTP_SERVER_HTTP_SERVER_H
|
||||
#define ARANGODB_HTTP_SERVER_HTTP_SERVER_H 1
|
||||
|
||||
#include "Scheduler/TaskManager.h"
|
||||
#include "Basics/Mutex.h"
|
||||
#include "Basics/SpinLock.h"
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
#include "Rest/ConnectionInfo.h"
|
||||
#include "Rest/Handler.h"
|
||||
#include "Scheduler/TaskManager.h"
|
||||
|
||||
// #define TRI_USE_SPIN_LOCK_GENERAL_SERVER 1
|
||||
|
||||
|
@ -51,7 +51,6 @@ namespace triagens {
|
|||
class EndpointList;
|
||||
class HttpServerJob;
|
||||
class HttpCommTask;
|
||||
class HttpHandler;
|
||||
class HttpHandlerFactory;
|
||||
class Job;
|
||||
class ListenTask;
|
||||
|
@ -277,7 +276,7 @@ namespace triagens {
|
|||
/// @brief handle request directly
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler::status_t handleRequestDirectly (HttpCommTask* task, HttpHandler * handler);
|
||||
HttpHandler::status_t handleRequestDirectly (HttpCommTask* task, HttpHandler* handler);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shut downs a handler for a task
|
||||
|
|
|
@ -124,7 +124,7 @@ Job::status_t HttpServerJob::work () {
|
|||
|
||||
RequestStatisticsAgentSetRequestStart(_handler);
|
||||
_handler->prepareExecute();
|
||||
Handler::status_t status;
|
||||
HttpHandler::status_t status;
|
||||
|
||||
try {
|
||||
status = _handler->execute();
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#define ARANGODB_HTTP_SERVER_PATH_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "HttpServer/HttpHandler.h"
|
||||
|
||||
namespace triagens {
|
||||
|
@ -108,7 +107,7 @@ namespace triagens {
|
|||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void handleError (const basics::Exception&);
|
||||
void handleError (const basics::Exception&) override;
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
|
|
|
@ -16,13 +16,6 @@ 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 \
|
||||
|
@ -111,20 +104,26 @@ arangod_libarangod_a_SOURCES = \
|
|||
arangod/Replication/InitialSyncer.cpp \
|
||||
arangod/Replication/Syncer.cpp \
|
||||
arangod/Rest/AnyServer.cpp \
|
||||
arangod/Rest/Handler.cpp \
|
||||
arangod/RestHandler/RestAdminBaseHandler.cpp \
|
||||
arangod/RestHandler/RestAdminLogHandler.cpp \
|
||||
arangod/RestHandler/RestBaseHandler.cpp \
|
||||
arangod/RestHandler/RestBatchHandler.cpp \
|
||||
arangod/RestHandler/RestCursorHandler.cpp \
|
||||
arangod/RestHandler/RestDebugHelperHandler.cpp \
|
||||
arangod/RestHandler/RestDocumentHandler.cpp \
|
||||
arangod/RestHandler/RestEdgeHandler.cpp \
|
||||
arangod/RestHandler/RestExportHandler.cpp \
|
||||
arangod/RestHandler/RestImportHandler.cpp \
|
||||
arangod/RestHandler/RestJobHandler.cpp \
|
||||
arangod/RestHandler/RestPleaseUpgradeHandler.cpp \
|
||||
arangod/RestHandler/RestQueryCacheHandler.cpp \
|
||||
arangod/RestHandler/RestQueryHandler.cpp \
|
||||
arangod/RestHandler/RestReplicationHandler.cpp \
|
||||
arangod/RestHandler/RestShutdownHandler.cpp \
|
||||
arangod/RestHandler/RestSimpleHandler.cpp \
|
||||
arangod/RestHandler/RestSimpleQueryHandler.cpp \
|
||||
arangod/RestHandler/RestUploadHandler.cpp \
|
||||
arangod/RestHandler/RestVersionHandler.cpp \
|
||||
arangod/RestHandler/RestVocbaseBaseHandler.cpp \
|
||||
arangod/RestServer/ArangoServer.cpp \
|
||||
arangod/RestServer/ConsoleThread.cpp \
|
||||
|
|
|
@ -166,9 +166,9 @@ int ContinuousSyncer::run () {
|
|||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
// stop ourselves
|
||||
TRI_StopReplicationApplier(_applier, false);
|
||||
_applier->stop(false);
|
||||
|
||||
return TRI_SetErrorReplicationApplier(_applier, res, errorMsg.c_str());
|
||||
return _applier->setError(res, errorMsg.c_str());
|
||||
}
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
|
@ -176,10 +176,10 @@ int ContinuousSyncer::run () {
|
|||
}
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_SetErrorReplicationApplier(_applier, res, errorMsg.c_str());
|
||||
_applier->setError(res, errorMsg.c_str());
|
||||
|
||||
// stop ourselves
|
||||
TRI_StopReplicationApplier(_applier, false);
|
||||
_applier->stop(false);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ int ContinuousSyncer::run () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ContinuousSyncer::setProgress (char const* msg) {
|
||||
TRI_SetProgressReplicationApplier(_applier, msg, true);
|
||||
_applier->setProgress(msg, true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -780,7 +780,7 @@ int ContinuousSyncer::applyLog (SimpleHttpResult* response,
|
|||
else {
|
||||
ignoreCount--;
|
||||
LOG_WARNING("ignoring replication error for database '%s': %s",
|
||||
_applier->_databaseName,
|
||||
_applier->databaseName(),
|
||||
errorMsg.c_str());
|
||||
errorMsg = "";
|
||||
}
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief abstract class for handlers
|
||||
///
|
||||
/// @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 2009-2014, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Handler.h"
|
||||
|
||||
#include "Dispatcher/Dispatcher.h"
|
||||
|
||||
using namespace triagens::rest;
|
||||
using namespace std;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler::Handler ()
|
||||
: _dispatcherThread(nullptr) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructs a handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler::~Handler () {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the queue name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Handler::queue () const {
|
||||
return Dispatcher::STANDARD_QUEUE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the thread which currently dealing with the job
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Handler::setDispatcherThread (DispatcherThread* dispatcherThread) {
|
||||
_dispatcherThread = dispatcherThread;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief prepares for execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Handler::prepareExecute () {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tries to cancel an execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Handler::finalizeExecute () {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tries to cancel an execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Handler::cancel () {
|
||||
return false;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -1,208 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief abstract class for handlers
|
||||
///
|
||||
/// @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 2009-2014, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_REST_HANDLER_H
|
||||
#define ARANGODB_REST_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/Exceptions.h"
|
||||
#include "Dispatcher/Job.h"
|
||||
#include "Statistics/StatisticsAgent.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- forward declarations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
||||
class Dispatcher;
|
||||
class HttpServer;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class Handler
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief abstract class for handlers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class Handler : public RequestStatisticsAgent {
|
||||
private:
|
||||
Handler (Handler const&);
|
||||
Handler& operator= (Handler const&);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief status of execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum status_e {
|
||||
HANDLER_DONE,
|
||||
HANDLER_REQUEUE,
|
||||
HANDLER_FAILED
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief result of execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class status_t {
|
||||
public:
|
||||
status_t ()
|
||||
: status(HANDLER_FAILED) {
|
||||
}
|
||||
|
||||
explicit
|
||||
status_t (status_e status)
|
||||
: status(status) {
|
||||
}
|
||||
|
||||
Job::status_t jobStatus () {
|
||||
switch (status) {
|
||||
case Handler::HANDLER_DONE:
|
||||
return Job::status_t(Job::JOB_DONE);
|
||||
|
||||
case Handler::HANDLER_REQUEUE: {
|
||||
Job::status_t result(Job::JOB_REQUEUE);
|
||||
result.sleep = sleep;
|
||||
return result;
|
||||
}
|
||||
|
||||
case Handler::HANDLER_FAILED:
|
||||
default:
|
||||
return Job::status_t(Job::JOB_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
status_e status;
|
||||
double sleep;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructs a handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~Handler ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns true if a handler is executed directly
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual bool isDirect () const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the queue name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual size_t queue () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the thread which currently dealing with the job
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void setDispatcherThread (DispatcherThread*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief prepares execution of a handler, has to be called before execute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void prepareExecute ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes a handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual status_t execute () = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief finalizes execution of a handler, has to be called after execute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void finalizeExecute ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tries to cancel an execution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual bool cancel ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief handles error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void handleError (basics::Exception const&) = 0;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- protected variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief current dispatcher thread
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DispatcherThread* _dispatcherThread;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -27,12 +27,11 @@
|
|||
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_ADMIN_REST_ADMIN_BASE_HANDLER_H
|
||||
#define ARANGODB_ADMIN_REST_ADMIN_BASE_HANDLER_H 1
|
||||
#ifndef ARANGODB_REST_HANDLER_REST_ADMIN_BASE_HANDLER_H
|
||||
#define ARANGODB_REST_HANDLER_REST_ADMIN_BASE_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Admin/RestBaseHandler.h"
|
||||
#include "RestHandler/RestBaseHandler.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace admin {
|
||||
|
@ -57,7 +56,7 @@ namespace triagens {
|
|||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RestAdminBaseHandler (rest::HttpRequest* request);
|
||||
explicit RestAdminBaseHandler (rest::HttpRequest* request);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -27,12 +27,11 @@
|
|||
/// @author Copyright 2010-2014, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_ADMIN_REST_ADMIN_LOG_HANDLER_H
|
||||
#define ARANGODB_ADMIN_REST_ADMIN_LOG_HANDLER_H 1
|
||||
#ifndef ARANGODB_REST_HANDLER_REST_ADMIN_LOG_HANDLER_H
|
||||
#define ARANGODB_REST_HANDLER_REST_ADMIN_LOG_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Admin/RestAdminBaseHandler.h"
|
||||
#include "RestHandler/RestAdminBaseHandler.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace admin {
|
|
@ -60,7 +60,7 @@ RestBatchHandler::~RestBatchHandler () {
|
|||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Handler methods
|
||||
// --SECTION-- HttpHandler methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -184,13 +184,13 @@ RestBatchHandler::~RestBatchHandler () {
|
|||
/// @END_EXAMPLE_ARANGOSH_RUN
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler::status_t RestBatchHandler::execute () {
|
||||
HttpHandler::status_t RestBatchHandler::execute () {
|
||||
// extract the request type
|
||||
const HttpRequest::HttpRequestType type = _request->requestType();
|
||||
|
||||
if (type != HttpRequest::HTTP_REQUEST_POST && type != HttpRequest::HTTP_REQUEST_PUT) {
|
||||
generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
return status_t(Handler::HANDLER_DONE);
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
}
|
||||
|
||||
string boundary;
|
||||
|
@ -198,7 +198,7 @@ Handler::status_t RestBatchHandler::execute () {
|
|||
// invalid content-type or boundary sent
|
||||
if (! getBoundary(&boundary)) {
|
||||
generateError(HttpResponse::BAD, TRI_ERROR_HTTP_BAD_PARAMETER, "invalid content-type or boundary received");
|
||||
return status_t(Handler::HANDLER_FAILED);
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
LOG_TRACE("boundary of multipart-message is '%s'", boundary.c_str());
|
||||
|
@ -230,7 +230,7 @@ Handler::status_t RestBatchHandler::execute () {
|
|||
generateError(HttpResponse::BAD, TRI_ERROR_HTTP_BAD_PARAMETER, "invalid multipart message received");
|
||||
LOG_WARNING("received a corrupted multipart message");
|
||||
|
||||
return status_t(Handler::HANDLER_FAILED);
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
// split part into header & body
|
||||
|
@ -273,7 +273,7 @@ Handler::status_t RestBatchHandler::execute () {
|
|||
if (request == nullptr) {
|
||||
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return status_t(Handler::HANDLER_FAILED);
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
// we do not have a client task id here
|
||||
|
@ -301,10 +301,10 @@ Handler::status_t RestBatchHandler::execute () {
|
|||
|
||||
generateError(HttpResponse::BAD, TRI_ERROR_INTERNAL, "could not create handler for batch part processing");
|
||||
|
||||
return status_t(Handler::HANDLER_FAILED);
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
Handler::status_t status(Handler::HANDLER_FAILED);
|
||||
HttpHandler::status_t status(HttpHandler::HANDLER_FAILED);
|
||||
|
||||
do {
|
||||
handler->prepareExecute();
|
||||
|
@ -324,15 +324,15 @@ Handler::status_t RestBatchHandler::execute () {
|
|||
}
|
||||
handler->finalizeExecute();
|
||||
}
|
||||
while (status.status == Handler::HANDLER_REQUEUE);
|
||||
while (status.status == HttpHandler::HANDLER_REQUEUE);
|
||||
|
||||
|
||||
if (status.status == Handler::HANDLER_FAILED) {
|
||||
if (status.status == HttpHandler::HANDLER_FAILED) {
|
||||
// one of the handlers failed, we must exit now
|
||||
delete handler;
|
||||
generateError(HttpResponse::BAD, TRI_ERROR_INTERNAL, "executing a handler for batch part failed");
|
||||
|
||||
return status_t(Handler::HANDLER_FAILED);
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
HttpResponse* partResponse = handler->getResponse();
|
||||
|
@ -341,7 +341,7 @@ Handler::status_t RestBatchHandler::execute () {
|
|||
delete handler;
|
||||
generateError(HttpResponse::BAD, TRI_ERROR_INTERNAL, "could not create a response for batch part request");
|
||||
|
||||
return status_t(Handler::HANDLER_FAILED);
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
const HttpResponse::HttpResponseCode code = partResponse->responseCode();
|
||||
|
@ -389,7 +389,7 @@ Handler::status_t RestBatchHandler::execute () {
|
|||
}
|
||||
|
||||
// success
|
||||
return status_t(Handler::HANDLER_DONE);
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -96,7 +96,7 @@ namespace triagens {
|
|||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RestBatchHandler (rest::HttpRequest*);
|
||||
explicit RestBatchHandler (rest::HttpRequest*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructor
|
||||
|
@ -105,7 +105,7 @@ namespace triagens {
|
|||
~RestBatchHandler ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Handler methods
|
||||
// --SECTION-- HttpHandler methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
@ -114,7 +114,7 @@ namespace triagens {
|
|||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler::status_t execute ();
|
||||
HttpHandler::status_t execute ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
|
|
|
@ -26,14 +26,12 @@
|
|||
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_ADMIN_REST_DEBUG_HELPER_HANDLER_H
|
||||
#define ARANGODB_ADMIN_REST_DEBUG_HELPER_HANDLER_H 1
|
||||
#ifndef ARANGODB_REST_HANDLER_REST_DEBUG_HELPER_HANDLER_H
|
||||
#define ARANGODB_REST_HNDLER_REST_DEBUG_HELPER_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Admin/RestBaseHandler.h"
|
||||
|
||||
#include "Rest/HttpResponse.h"
|
||||
#include "RestHandler/RestBaseHandler.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace admin {
|
||||
|
@ -58,7 +56,7 @@ namespace triagens {
|
|||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RestDebugHelperHandler (rest::HttpRequest*);
|
||||
explicit RestDebugHelperHandler (rest::HttpRequest*);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Handler methods
|
|
@ -28,18 +28,17 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RestJobHandler.h"
|
||||
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/conversions.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/tri-strings.h"
|
||||
#include "Dispatcher/Dispatcher.h"
|
||||
#include "HttpServer/AsyncJobManager.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
|
||||
using namespace triagens::admin;
|
||||
using namespace triagens::basics;
|
||||
using namespace triagens::rest;
|
||||
using namespace triagens::admin;
|
||||
using namespace std;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -55,7 +54,7 @@ using namespace std;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RestJobHandler::RestJobHandler (HttpRequest* request,
|
||||
pair<Dispatcher*, AsyncJobManager*>* data)
|
||||
std::pair<Dispatcher*, AsyncJobManager*>* data)
|
||||
: RestBaseHandler(request),
|
||||
_dispatcher(data->first),
|
||||
_jobManager(data->second) {
|
|
@ -27,13 +27,12 @@
|
|||
/// @author Copyright 2010-2014, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_ADMIN_REST_JOB_HANDLER_H
|
||||
#define ARANGODB_ADMIN_REST_JOB_HANDLER_H 1
|
||||
#ifndef ARANGODB_REST_HANDLER_REST_JOB_HANDLER_H
|
||||
#define ARANGODB_REST_HANDLER_REST_JOB_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Admin/RestBaseHandler.h"
|
||||
#include "HttpServer/AsyncJobManager.h"
|
||||
#include "RestHandler/RestBaseHandler.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace rest {
|
|
@ -81,7 +81,7 @@ namespace triagens {
|
|||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void handleError (const basics::Exception&);
|
||||
void handleError (const basics::Exception&) override;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,14 +83,14 @@ RestReplicationHandler::~RestReplicationHandler () {
|
|||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Handler methods
|
||||
// --SECTION-- HttpHandler methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler::status_t RestReplicationHandler::execute () {
|
||||
HttpHandler::status_t RestReplicationHandler::execute () {
|
||||
// extract the request type
|
||||
const HttpRequest::HttpRequestType type = _request->requestType();
|
||||
|
||||
|
@ -195,7 +195,7 @@ Handler::status_t RestReplicationHandler::execute () {
|
|||
}
|
||||
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(Handler::HANDLER_DONE);
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
}
|
||||
|
||||
handleCommandSync();
|
||||
|
@ -223,7 +223,7 @@ Handler::status_t RestReplicationHandler::execute () {
|
|||
}
|
||||
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(Handler::HANDLER_DONE);
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
}
|
||||
|
||||
handleCommandApplierStart();
|
||||
|
@ -234,7 +234,7 @@ Handler::status_t RestReplicationHandler::execute () {
|
|||
}
|
||||
|
||||
if (isCoordinatorError()) {
|
||||
return status_t(Handler::HANDLER_DONE);
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
}
|
||||
|
||||
handleCommandApplierStop();
|
||||
|
@ -268,7 +268,7 @@ Handler::status_t RestReplicationHandler::execute () {
|
|||
"invalid command");
|
||||
}
|
||||
|
||||
return status_t(Handler::HANDLER_DONE);
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
}
|
||||
|
||||
BAD_CALL:
|
||||
|
@ -281,7 +281,7 @@ BAD_CALL:
|
|||
generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
return status_t(Handler::HANDLER_DONE);
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -3764,9 +3764,7 @@ void RestReplicationHandler::handleCommandApplierStart () {
|
|||
initialTick = (TRI_voc_tick_t) StringUtils::uint64(value);
|
||||
}
|
||||
|
||||
int res = TRI_StartReplicationApplier(_vocbase->_replicationApplier,
|
||||
initialTick,
|
||||
found);
|
||||
int res = _vocbase->_replicationApplier->start(initialTick, found);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
if (res == TRI_ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION ||
|
||||
|
@ -3830,7 +3828,7 @@ void RestReplicationHandler::handleCommandApplierStart () {
|
|||
void RestReplicationHandler::handleCommandApplierStop () {
|
||||
TRI_ASSERT(_vocbase->_replicationApplier != nullptr);
|
||||
|
||||
int res = TRI_StopReplicationApplier(_vocbase->_replicationApplier, true);
|
||||
int res = _vocbase->_replicationApplier->stop(true);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
generateError(HttpResponse::SERVER_ERROR, res);
|
||||
|
@ -3981,7 +3979,7 @@ void RestReplicationHandler::handleCommandApplierGetState () {
|
|||
void RestReplicationHandler::handleCommandApplierDeleteState () {
|
||||
TRI_ASSERT(_vocbase->_replicationApplier != nullptr);
|
||||
|
||||
int res = TRI_ForgetReplicationApplier(_vocbase->_replicationApplier);
|
||||
int res = _vocbase->_replicationApplier->forget();
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
generateError(HttpResponse::SERVER_ERROR, res);
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace triagens {
|
|||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RestReplicationHandler (rest::HttpRequest*);
|
||||
explicit RestReplicationHandler (rest::HttpRequest*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructor
|
||||
|
@ -75,7 +75,7 @@ namespace triagens {
|
|||
~RestReplicationHandler ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Handler methods
|
||||
// --SECTION-- HttpHandler methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
@ -84,7 +84,7 @@ namespace triagens {
|
|||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler::status_t execute ();
|
||||
HttpHandler::status_t execute ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public static methods
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
#define ARANGODB_ADMIN_REST_SHUTDOWN_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Admin/RestBaseHandler.h"
|
||||
#include "ApplicationServer/ApplicationServer.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
#include "RestHandler/RestBaseHandler.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace admin {
|
|
@ -1,137 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief document changes subscription handler
|
||||
///
|
||||
/// @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 2010-2014, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RestSubscribeHandler.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
#include "VocBase/document-collection.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace triagens::basics;
|
||||
using namespace triagens::rest;
|
||||
using namespace triagens::arango;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RestSubscribeHandler::RestSubscribeHandler (HttpRequest* request)
|
||||
: RestVocbaseBaseHandler(request) {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Handler methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HttpHandler::status_t RestSubscribeHandler::execute () {
|
||||
// extract the sub-request type
|
||||
HttpRequest::HttpRequestType type = _request->requestType();
|
||||
|
||||
switch (type) {
|
||||
case HttpRequest::HTTP_REQUEST_POST: addSubscription(); break;
|
||||
|
||||
case HttpRequest::HTTP_REQUEST_ILLEGAL:
|
||||
default: {
|
||||
generateNotImplemented("ILLEGAL " + DOCUMENT_PATH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// this handler is done
|
||||
return status_t(HANDLER_DONE);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void RestSubscribeHandler::addSubscription () {
|
||||
std::unique_ptr<TRI_json_t> json(parseJsonBody());
|
||||
|
||||
if (json == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (json->_type != TRI_JSON_OBJECT) {
|
||||
generateError(HttpResponse::BAD, TRI_ERROR_TYPE_ERROR, "expecting object in body");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<TRI_voc_cid_t> collections;
|
||||
|
||||
auto const* value = TRI_LookupObjectJson(json.get(), "collections");
|
||||
|
||||
if (TRI_IsArrayJson(value)) {
|
||||
for (size_t i = 0; i < TRI_LengthArrayJson(value); ++i) {
|
||||
auto n = static_cast<TRI_json_t const*>(TRI_AtVector(&value->_value._objects, i));
|
||||
|
||||
if (! TRI_IsStringJson(n)) {
|
||||
generateError(HttpResponse::BAD, TRI_ERROR_TYPE_ERROR, "expecting array of strings for 'collections'");
|
||||
return;
|
||||
}
|
||||
|
||||
TRI_vocbase_col_t const* collection = TRI_LookupCollectionByNameVocBase(_vocbase, n->_value._string.data);
|
||||
|
||||
if (collection == nullptr) {
|
||||
generateError(HttpResponse::NOT_FOUND, TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
collections.emplace_back(collection->_cid);
|
||||
}
|
||||
}
|
||||
|
||||
if (collections.empty()) {
|
||||
generateError(HttpResponse::BAD, TRI_ERROR_TYPE_ERROR, "expecting array of strings for 'collections'");
|
||||
return;
|
||||
}
|
||||
|
||||
_response = createResponse(HttpResponse::OK);
|
||||
_response->setHeader("transfer-encoding", "chunked");
|
||||
_response->body().appendText("ok");
|
||||
|
||||
AddChangeListeners(_request->clientTaskId(), collections);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -1,98 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief document change subscription handler
|
||||
///
|
||||
/// @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 2010-2014, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_REST_HANDLER_REST_SUBSCRIBE_HANDLER_H
|
||||
#define ARANGODB_REST_HANDLER_REST_SUBSCRIBE_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "RestHandler/RestVocbaseBaseHandler.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class RestSubscribeHandler
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace triagens {
|
||||
namespace arango {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief document changes subscription handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RestSubscribeHandler : public RestVocbaseBaseHandler {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RestSubscribeHandler (rest::HttpRequest*);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Handler methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
status_t execute () override final;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void addSubscription ();
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -61,21 +61,21 @@ RestUploadHandler::~RestUploadHandler () {
|
|||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Handler methods
|
||||
// --SECTION-- HttpHandler methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler::status_t RestUploadHandler::execute () {
|
||||
HttpHandler::status_t RestUploadHandler::execute () {
|
||||
// extract the request type
|
||||
const HttpRequest::HttpRequestType type = _request->requestType();
|
||||
|
||||
if (type != HttpRequest::HTTP_REQUEST_POST) {
|
||||
generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||
|
||||
return status_t(Handler::HANDLER_DONE);
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
}
|
||||
|
||||
char* filename = nullptr;
|
||||
|
@ -85,7 +85,7 @@ Handler::status_t RestUploadHandler::execute () {
|
|||
if (TRI_GetTempName("uploads", &filename, false, systemError, errorMessage) != TRI_ERROR_NO_ERROR) {
|
||||
errorMessage = "could not generate temp file: " + errorMessage;
|
||||
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, errorMessage);
|
||||
return status_t(Handler::HANDLER_FAILED);
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
char* relative = TRI_GetFilename(filename);
|
||||
|
@ -109,7 +109,7 @@ Handler::status_t RestUploadHandler::execute () {
|
|||
TRI_Free(TRI_CORE_MEM_ZONE, relative);
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, filename);
|
||||
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "invalid multipart request");
|
||||
return status_t(Handler::HANDLER_FAILED);
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ Handler::status_t RestUploadHandler::execute () {
|
|||
TRI_Free(TRI_CORE_MEM_ZONE, relative);
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, filename);
|
||||
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not save file");
|
||||
return status_t(Handler::HANDLER_FAILED);
|
||||
return status_t(HttpHandler::HANDLER_FAILED);
|
||||
}
|
||||
|
||||
char* fullName = TRI_Concatenate2File("uploads", relative);
|
||||
|
@ -142,7 +142,7 @@ Handler::status_t RestUploadHandler::execute () {
|
|||
TRI_DestroyJson(TRI_UNKNOWN_MEM_ZONE, &json);
|
||||
|
||||
// success
|
||||
return status_t(Handler::HANDLER_DONE);
|
||||
return status_t(HttpHandler::HANDLER_DONE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace triagens {
|
|||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RestUploadHandler (rest::HttpRequest*);
|
||||
explicit RestUploadHandler (rest::HttpRequest*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructor
|
||||
|
@ -63,7 +63,7 @@ namespace triagens {
|
|||
~RestUploadHandler ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Handler methods
|
||||
// --SECTION-- HttpHandler methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
@ -72,7 +72,7 @@ namespace triagens {
|
|||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Handler::status_t execute ();
|
||||
HttpHandler::status_t execute ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief parses a multi-part request body and determines the boundaries of
|
||||
|
|
|
@ -28,10 +28,8 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RestVersionHandler.h"
|
||||
|
||||
#include "Basics/json.h"
|
||||
#include "Basics/tri-strings.h"
|
||||
#include "Basics/conversions.h"
|
||||
#include "Rest/AnyServer.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
#include "Rest/Version.h"
|
|
@ -27,14 +27,12 @@
|
|||
/// @author Copyright 2010-2014, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_ADMIN_REST_VERSION_HANDLER_H
|
||||
#define ARANGODB_ADMIN_REST_VERSION_HANDLER_H 1
|
||||
#ifndef ARANGODB_REST_HANDLER_REST_VERSION_HANDLER_H
|
||||
#define ARANGODB_REST_HANDLER_REST_VERSION_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Admin/RestBaseHandler.h"
|
||||
|
||||
#include "Rest/HttpResponse.h"
|
||||
#include "RestHandler/RestBaseHandler.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace admin {
|
||||
|
@ -59,7 +57,7 @@ namespace triagens {
|
|||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RestVersionHandler (rest::HttpRequest*);
|
||||
explicit RestVersionHandler (rest::HttpRequest*);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Handler methods
|
|
@ -31,12 +31,11 @@
|
|||
#define ARANGODB_REST_HANDLER_REST_VOCBASE_BASE_HANDLER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
#include "Admin/RestBaseHandler.h"
|
||||
#include "Basics/json.h"
|
||||
#include "Basics/logging.h"
|
||||
#include "Basics/json-utilities.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
#include "RestHandler/RestBaseHandler.h"
|
||||
#include "RestServer/VocbaseContext.h"
|
||||
#include "Utils/transactions.h"
|
||||
|
||||
|
@ -150,7 +149,7 @@ namespace triagens {
|
|||
/// @brief constructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RestVocbaseBaseHandler (rest::HttpRequest*);
|
||||
explicit RestVocbaseBaseHandler (rest::HttpRequest*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructor
|
||||
|
@ -425,13 +424,13 @@ namespace triagens {
|
|||
/// @brief prepareExecute, to react to X-Arango-Nolock header
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void prepareExecute ();
|
||||
virtual void prepareExecute () override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief finalizeExecute, to react to X-Arango-Nolock header
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void finalizeExecute ();
|
||||
virtual void finalizeExecute () override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief _nolockHeaderFound
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
#include "Actions/RestActionHandler.h"
|
||||
#include "Actions/actions.h"
|
||||
#include "Admin/ApplicationAdminServer.h"
|
||||
#include "Admin/RestHandlerCreator.h"
|
||||
#include "Admin/RestShutdownHandler.h"
|
||||
#include "Aql/Query.h"
|
||||
#include "Aql/QueryCache.h"
|
||||
#include "Aql/RestAqlHandler.h"
|
||||
|
@ -63,19 +61,25 @@
|
|||
#include "Rest/InitialiseRest.h"
|
||||
#include "Rest/OperationMode.h"
|
||||
#include "Rest/Version.h"
|
||||
#include "RestHandler/RestAdminLogHandler.h"
|
||||
#include "RestHandler/RestBatchHandler.h"
|
||||
#include "RestHandler/RestCursorHandler.h"
|
||||
#include "RestHandler/RestDebugHelperHandler.h"
|
||||
#include "RestHandler/RestDocumentHandler.h"
|
||||
#include "RestHandler/RestEdgeHandler.h"
|
||||
#include "RestHandler/RestExportHandler.h"
|
||||
#include "RestHandler/RestHandlerCreator.h"
|
||||
#include "RestHandler/RestImportHandler.h"
|
||||
#include "RestHandler/RestJobHandler.h"
|
||||
#include "RestHandler/RestPleaseUpgradeHandler.h"
|
||||
#include "RestHandler/RestQueryCacheHandler.h"
|
||||
#include "RestHandler/RestQueryHandler.h"
|
||||
#include "RestHandler/RestReplicationHandler.h"
|
||||
#include "RestHandler/RestShutdownHandler.h"
|
||||
#include "RestHandler/RestSimpleHandler.h"
|
||||
#include "RestHandler/RestSimpleQueryHandler.h"
|
||||
#include "RestHandler/RestUploadHandler.h"
|
||||
#include "RestHandler/RestVersionHandler.h"
|
||||
#include "RestServer/ConsoleThread.h"
|
||||
#include "RestServer/VocbaseContext.h"
|
||||
#include "Scheduler/ApplicationScheduler.h"
|
||||
|
@ -127,13 +131,7 @@ void ArangoServer::defineHandlers (HttpHandlerFactory* factory) {
|
|||
|
||||
// First the "_api" handlers:
|
||||
|
||||
// add "/version" handler
|
||||
_applicationAdminServer->addBasicHandlers(
|
||||
factory, "/_api",
|
||||
_applicationDispatcher->dispatcher(),
|
||||
_jobManager);
|
||||
|
||||
// add a upgrade warning
|
||||
// add an upgrade warning
|
||||
factory->addPrefixHandler("/_msg/please-upgrade",
|
||||
RestHandlerCreator<RestPleaseUpgradeHandler>::createNoData);
|
||||
|
||||
|
@ -144,7 +142,7 @@ void ArangoServer::defineHandlers (HttpHandlerFactory* factory) {
|
|||
// add "/cursor" handler
|
||||
factory->addPrefixHandler(RestVocbaseBaseHandler::CURSOR_PATH,
|
||||
RestHandlerCreator<RestCursorHandler>::createData<std::pair<ApplicationV8*, aql::QueryRegistry*>*>,
|
||||
_pairForAql);
|
||||
_pairForAqlHandler);
|
||||
|
||||
// add "/document" handler
|
||||
factory->addPrefixHandler(RestVocbaseBaseHandler::DOCUMENT_PATH,
|
||||
|
@ -169,17 +167,17 @@ void ArangoServer::defineHandlers (HttpHandlerFactory* factory) {
|
|||
// add "/simple/all" handler
|
||||
factory->addPrefixHandler(RestVocbaseBaseHandler::SIMPLE_QUERY_ALL_PATH,
|
||||
RestHandlerCreator<RestSimpleQueryHandler>::createData<std::pair<ApplicationV8*, aql::QueryRegistry*>*>,
|
||||
_pairForAql);
|
||||
_pairForAqlHandler);
|
||||
|
||||
// add "/simple/lookup-by-key" handler
|
||||
factory->addPrefixHandler(RestVocbaseBaseHandler::SIMPLE_LOOKUP_PATH,
|
||||
RestHandlerCreator<RestSimpleHandler>::createData<std::pair<ApplicationV8*, aql::QueryRegistry*>*>,
|
||||
_pairForAql);
|
||||
_pairForAqlHandler);
|
||||
|
||||
// add "/simple/remove-by-key" handler
|
||||
factory->addPrefixHandler(RestVocbaseBaseHandler::SIMPLE_REMOVE_PATH,
|
||||
RestHandlerCreator<RestSimpleHandler>::createData<std::pair<ApplicationV8*, aql::QueryRegistry*>*>,
|
||||
_pairForAql);
|
||||
_pairForAqlHandler);
|
||||
|
||||
// add "/upload" handler
|
||||
factory->addPrefixHandler(RestVocbaseBaseHandler::UPLOAD_PATH,
|
||||
|
@ -193,7 +191,7 @@ void ArangoServer::defineHandlers (HttpHandlerFactory* factory) {
|
|||
// add "/aql" handler
|
||||
factory->addPrefixHandler("/_api/aql",
|
||||
RestHandlerCreator<aql::RestAqlHandler>::createData<std::pair<ApplicationV8*, aql::QueryRegistry*>*>,
|
||||
_pairForAql);
|
||||
_pairForAqlHandler);
|
||||
|
||||
factory->addPrefixHandler("/_api/query",
|
||||
RestHandlerCreator<RestQueryHandler>::createData<ApplicationV8*>,
|
||||
|
@ -202,21 +200,40 @@ void ArangoServer::defineHandlers (HttpHandlerFactory* factory) {
|
|||
factory->addPrefixHandler("/_api/query-cache",
|
||||
RestHandlerCreator<RestQueryCacheHandler>::createNoData);
|
||||
|
||||
// And now the "_admin" handlers
|
||||
// And now some handlers which are registered in both /_api and /_admin
|
||||
factory->addPrefixHandler("/_api/job",
|
||||
RestHandlerCreator<triagens::admin::RestJobHandler>::createData<pair<Dispatcher*, AsyncJobManager*>*>,
|
||||
_pairForJobHandler);
|
||||
|
||||
// add "/_admin/version" handler
|
||||
_applicationAdminServer->addBasicHandlers(
|
||||
factory, "/_admin",
|
||||
_applicationDispatcher->dispatcher(),
|
||||
_jobManager);
|
||||
factory->addHandler("/_api/version",
|
||||
RestHandlerCreator<triagens::admin::RestVersionHandler>::createNoData,
|
||||
nullptr);
|
||||
|
||||
factory->addHandler("/_api/debug-helper",
|
||||
RestHandlerCreator<triagens::admin::RestDebugHelperHandler>::createNoData,
|
||||
nullptr);
|
||||
|
||||
// And now the _admin handlers
|
||||
factory->addPrefixHandler("/_admin/job",
|
||||
RestHandlerCreator<triagens::admin::RestJobHandler>::createData<pair<Dispatcher*, AsyncJobManager*>*>,
|
||||
_pairForJobHandler);
|
||||
|
||||
factory->addHandler("/_admin/version",
|
||||
RestHandlerCreator<triagens::admin::RestVersionHandler>::createNoData,
|
||||
nullptr);
|
||||
|
||||
factory->addHandler("/_admin/debug-helper",
|
||||
RestHandlerCreator<triagens::admin::RestDebugHelperHandler>::createNoData,
|
||||
nullptr);
|
||||
|
||||
// further admin handlers
|
||||
factory->addHandler("/_admin/log",
|
||||
RestHandlerCreator<triagens::admin::RestAdminLogHandler>::createNoData,
|
||||
nullptr);
|
||||
|
||||
// add "/_admin/shutdown" handler
|
||||
factory->addPrefixHandler("/_admin/shutdown",
|
||||
RestHandlerCreator<RestShutdownHandler>::createData<void*>,
|
||||
static_cast<void*>(_applicationServer));
|
||||
|
||||
// add admin handlers
|
||||
_applicationAdminServer->addHandlers(factory, "/_admin");
|
||||
RestHandlerCreator<triagens::admin::RestShutdownHandler>::createData<void*>,
|
||||
static_cast<void*>(_applicationServer));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -359,7 +376,8 @@ ArangoServer::ArangoServer (int argc, char** argv)
|
|||
_foxxQueuesPollInterval(1.0),
|
||||
_server(nullptr),
|
||||
_queryRegistry(nullptr),
|
||||
_pairForAql(nullptr),
|
||||
_pairForAqlHandler(nullptr),
|
||||
_pairForJobHandler(nullptr),
|
||||
_indexPool(nullptr),
|
||||
_threadAffinity(0) {
|
||||
|
||||
|
@ -484,7 +502,6 @@ void ArangoServer::buildApplicationServer () {
|
|||
_applicationAdminServer = new ApplicationAdminServer();
|
||||
|
||||
_applicationServer->addFeature(_applicationAdminServer);
|
||||
_applicationAdminServer->allowLogViewer();
|
||||
|
||||
// .............................................................................
|
||||
// define server options
|
||||
|
@ -918,7 +935,7 @@ int ArangoServer::startupServer () {
|
|||
|
||||
startupProgress();
|
||||
|
||||
const auto role = ServerState::instance()->getRole();
|
||||
auto const role = ServerState::instance()->getRole();
|
||||
|
||||
// now we can create the queues
|
||||
if (startServer) {
|
||||
|
@ -958,9 +975,8 @@ int ArangoServer::startupServer () {
|
|||
|
||||
startupProgress();
|
||||
|
||||
_pairForAql = new std::pair<ApplicationV8*, aql::QueryRegistry*>;
|
||||
_pairForAql->first = _applicationV8;
|
||||
_pairForAql->second = _queryRegistry;
|
||||
_pairForAqlHandler = new std::pair<ApplicationV8*, aql::QueryRegistry*>(_applicationV8, _queryRegistry);
|
||||
_pairForJobHandler = new std::pair<Dispatcher*, AsyncJobManager*>(_applicationDispatcher->dispatcher(), _jobManager);
|
||||
|
||||
// ...........................................................................
|
||||
// create endpoints and handlers
|
||||
|
@ -1152,8 +1168,10 @@ int ArangoServer::startupServer () {
|
|||
|
||||
delete _queryRegistry;
|
||||
_queryRegistry = nullptr;
|
||||
delete _pairForAql;
|
||||
_pairForAql = nullptr;
|
||||
delete _pairForAqlHandler;
|
||||
_pairForAqlHandler = nullptr;
|
||||
delete _pairForJobHandler;
|
||||
_pairForJobHandler = nullptr;
|
||||
|
||||
closeDatabases();
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "Basics/Common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Basics/win-utils.h"
|
||||
#include "Basics/win-utils.h"
|
||||
#endif
|
||||
|
||||
#include "Rest/AnyServer.h"
|
||||
|
@ -60,6 +60,7 @@ namespace triagens {
|
|||
class ApplicationEndpointServer;
|
||||
class ApplicationScheduler;
|
||||
class AsyncJobManager;
|
||||
class Dispatcher;
|
||||
class HttpServer;
|
||||
class HttpsServer;
|
||||
}
|
||||
|
@ -695,7 +696,13 @@ namespace triagens {
|
|||
/// this will be removed once we have a global struct with "everything useful"
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::pair<ApplicationV8*, aql::QueryRegistry*>* _pairForAql;
|
||||
std::pair<ApplicationV8*, aql::QueryRegistry*>* _pairForAqlHandler;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief ptr to pair used for job manager rest handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::pair<triagens::rest::Dispatcher*, triagens::rest::AsyncJobManager*>* _pairForJobHandler;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief thread pool for background parallel index creation
|
||||
|
|
|
@ -137,7 +137,7 @@ namespace triagens {
|
|||
/// @brief whether or not the thread is chatty on shutdown
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool isSilent () {
|
||||
bool isSilent () override {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace triagens {
|
|||
/// @brief get a task specific description in JSON format
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void getDescription (struct TRI_json_t*) const;
|
||||
virtual void getDescription (struct TRI_json_t*) const override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief resets the timer
|
||||
|
|
|
@ -99,37 +99,37 @@ namespace triagens {
|
|||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void eventLoop (EventLoop);
|
||||
void eventLoop (EventLoop) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void wakeupLoop (EventLoop);
|
||||
void wakeupLoop (EventLoop) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventToken installSocketEvent (EventLoop, EventType, Task*, TRI_socket_t);
|
||||
EventToken installSocketEvent (EventLoop, EventType, Task*, TRI_socket_t) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void startSocketEvents (EventToken);
|
||||
void startSocketEvents (EventToken) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void stopSocketEvents (EventToken);
|
||||
void stopSocketEvents (EventToken) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventToken installAsyncEvent (EventLoop, Task*);
|
||||
EventToken installAsyncEvent (EventLoop, Task*) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
|
@ -141,43 +141,43 @@ namespace triagens {
|
|||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventToken installTimerEvent (EventLoop, Task*, double timeout);
|
||||
EventToken installTimerEvent (EventLoop, Task*, double timeout) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void clearTimer (EventToken);
|
||||
void clearTimer (EventToken) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void rearmTimer (EventToken, double timeout);
|
||||
void rearmTimer (EventToken, double timeout) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventToken installPeriodicEvent (EventLoop, Task*, double offset, double interval);
|
||||
EventToken installPeriodicEvent (EventLoop, Task*, double offset, double interval) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void rearmPeriodic (EventToken, double offset, double timeout);
|
||||
void rearmPeriodic (EventToken, double offset, double timeout) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventToken installSignalEvent (EventLoop, Task*, int signal);
|
||||
EventToken installSignalEvent (EventLoop, Task*, int signal) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// {@inheritDoc}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void uninstallEvent (EventToken);
|
||||
void uninstallEvent (EventToken) override;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace triagens {
|
|||
/// @brief get a task specific description in JSON format
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void getDescription (struct TRI_json_t*) const;
|
||||
virtual void getDescription (struct TRI_json_t*) const override;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -525,9 +525,7 @@ static void JS_StartApplierReplication (const v8::FunctionCallbackInfo<v8::Value
|
|||
useTick = true;
|
||||
}
|
||||
|
||||
int res = TRI_StartReplicationApplier(vocbase->_replicationApplier,
|
||||
initialTick,
|
||||
useTick);
|
||||
int res = vocbase->_replicationApplier->start(initialTick, useTick);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(res, "cannot start replication applier");
|
||||
|
@ -559,7 +557,7 @@ static void JS_ShutdownApplierReplication (const v8::FunctionCallbackInfo<v8::Va
|
|||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
int res = TRI_ShutdownReplicationApplier(vocbase->_replicationApplier);
|
||||
int res = vocbase->_replicationApplier->shutdown();
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(res, "cannot shut down replication applier");
|
||||
|
@ -626,7 +624,7 @@ static void JS_ForgetApplierReplication (const v8::FunctionCallbackInfo<v8::Valu
|
|||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
int res = TRI_ForgetReplicationApplier(vocbase->_replicationApplier);
|
||||
int res = vocbase->_replicationApplier->forget();
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_V8_THROW_EXCEPTION(res);
|
||||
|
|
|
@ -198,10 +198,6 @@ void TRI_InitV8Statistics (v8::Isolate* isolate,
|
|||
v8::Handle<v8::Context> context) {
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
// check the isolate
|
||||
TRI_v8_global_t* v8g = TRI_GetV8Globals(isolate);
|
||||
TRI_ASSERT(v8g != nullptr);
|
||||
|
||||
// .............................................................................
|
||||
// create the global functions
|
||||
// .............................................................................
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "replication-applier.h"
|
||||
|
||||
#include "Basics/conversions.h"
|
||||
#include "Basics/files.h"
|
||||
#include "Basics/json.h"
|
||||
|
@ -213,14 +212,10 @@ static int LoadConfiguration (TRI_vocbase_t* vocbase,
|
|||
return TRI_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
TRI_json_t* json = TRI_JsonFile(TRI_CORE_MEM_ZONE, filename, nullptr);
|
||||
std::unique_ptr<TRI_json_t> json(TRI_JsonFile(TRI_UNKNOWN_MEM_ZONE, filename, nullptr));
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, filename);
|
||||
|
||||
if (! TRI_IsObjectJson(json)) {
|
||||
if (json != nullptr) {
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
}
|
||||
|
||||
if (! TRI_IsObjectJson(json.get())) {
|
||||
return TRI_ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION;
|
||||
}
|
||||
|
||||
|
@ -244,7 +239,7 @@ static int LoadConfiguration (TRI_vocbase_t* vocbase,
|
|||
}
|
||||
|
||||
// read the endpoint
|
||||
TRI_json_t* value = TRI_LookupObjectJson(json, "endpoint");
|
||||
TRI_json_t const* value = TRI_LookupObjectJson(json.get(), "endpoint");
|
||||
|
||||
if (! TRI_IsStringJson(value)) {
|
||||
res = TRI_ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION;
|
||||
|
@ -256,7 +251,7 @@ static int LoadConfiguration (TRI_vocbase_t* vocbase,
|
|||
}
|
||||
|
||||
// read the database name
|
||||
value = TRI_LookupObjectJson(json, "database");
|
||||
value = TRI_LookupObjectJson(json.get(), "database");
|
||||
|
||||
if (! TRI_IsStringJson(value)) {
|
||||
config->_database = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE,
|
||||
|
@ -269,7 +264,7 @@ static int LoadConfiguration (TRI_vocbase_t* vocbase,
|
|||
}
|
||||
|
||||
// read username / password
|
||||
value = TRI_LookupObjectJson(json, "username");
|
||||
value = TRI_LookupObjectJson(json.get(), "username");
|
||||
|
||||
if (TRI_IsStringJson(value)) {
|
||||
config->_username = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE,
|
||||
|
@ -277,7 +272,7 @@ static int LoadConfiguration (TRI_vocbase_t* vocbase,
|
|||
value->_value._string.length - 1);
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "password");
|
||||
value = TRI_LookupObjectJson(json.get(), "password");
|
||||
|
||||
if (TRI_IsStringJson(value)) {
|
||||
config->_password = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE,
|
||||
|
@ -285,61 +280,61 @@ static int LoadConfiguration (TRI_vocbase_t* vocbase,
|
|||
value->_value._string.length - 1);
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "requestTimeout");
|
||||
value = TRI_LookupObjectJson(json.get(), "requestTimeout");
|
||||
|
||||
if (TRI_IsNumberJson(value)) {
|
||||
config->_requestTimeout = value->_value._number;
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "connectTimeout");
|
||||
value = TRI_LookupObjectJson(json.get(), "connectTimeout");
|
||||
|
||||
if (TRI_IsNumberJson(value)) {
|
||||
config->_connectTimeout = value->_value._number;
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "maxConnectRetries");
|
||||
value = TRI_LookupObjectJson(json.get(), "maxConnectRetries");
|
||||
|
||||
if (TRI_IsNumberJson(value)) {
|
||||
config->_maxConnectRetries = (uint64_t) value->_value._number;
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "sslProtocol");
|
||||
value = TRI_LookupObjectJson(json.get(), "sslProtocol");
|
||||
|
||||
if (TRI_IsNumberJson(value)) {
|
||||
config->_sslProtocol = (uint32_t) value->_value._number;
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "chunkSize");
|
||||
value = TRI_LookupObjectJson(json.get(), "chunkSize");
|
||||
|
||||
if (TRI_IsNumberJson(value)) {
|
||||
config->_chunkSize = (uint64_t) value->_value._number;
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "autoStart");
|
||||
value = TRI_LookupObjectJson(json.get(), "autoStart");
|
||||
|
||||
if (TRI_IsBooleanJson(value)) {
|
||||
config->_autoStart = value->_value._boolean;
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "adaptivePolling");
|
||||
value = TRI_LookupObjectJson(json.get(), "adaptivePolling");
|
||||
|
||||
if (TRI_IsBooleanJson(value)) {
|
||||
config->_adaptivePolling = value->_value._boolean;
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "includeSystem");
|
||||
value = TRI_LookupObjectJson(json.get(), "includeSystem");
|
||||
|
||||
if (TRI_IsBooleanJson(value)) {
|
||||
config->_includeSystem = value->_value._boolean;
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "requireFromPresent");
|
||||
value = TRI_LookupObjectJson(json.get(), "requireFromPresent");
|
||||
|
||||
if (TRI_IsBooleanJson(value)) {
|
||||
config->_requireFromPresent = value->_value._boolean;
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "ignoreErrors");
|
||||
value = TRI_LookupObjectJson(json.get(), "ignoreErrors");
|
||||
|
||||
if (TRI_IsNumberJson(value)) {
|
||||
config->_ignoreErrors = (uint64_t) value->_value._number;
|
||||
|
@ -353,13 +348,13 @@ static int LoadConfiguration (TRI_vocbase_t* vocbase,
|
|||
}
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "restrictType");
|
||||
value = TRI_LookupObjectJson(json.get(), "restrictType");
|
||||
|
||||
if (TRI_IsStringJson(value)) {
|
||||
config->_restrictType = std::string(value->_value._string.data, value->_value._string.length - 1);
|
||||
}
|
||||
|
||||
value = TRI_LookupObjectJson(json, "restrictCollections");
|
||||
value = TRI_LookupObjectJson(json.get(), "restrictCollections");
|
||||
|
||||
if (TRI_IsArrayJson(value)) {
|
||||
config->_restrictCollections.clear();
|
||||
|
@ -368,13 +363,11 @@ static int LoadConfiguration (TRI_vocbase_t* vocbase,
|
|||
for (size_t i = 0; i < n; ++i) {
|
||||
TRI_json_t* collection = TRI_LookupArrayJson(value, i);
|
||||
if (TRI_IsStringJson(collection)) {
|
||||
config->_restrictCollections.emplace(std::make_pair(std::string(collection->_value._string.data), true));
|
||||
config->_restrictCollections.emplace(std::string(collection->_value._string.data), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -423,41 +416,6 @@ static TRI_json_t* JsonApplyState (TRI_replication_applier_state_t const* state)
|
|||
return json;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an applier error, without locking
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int SetError (TRI_replication_applier_t* applier,
|
||||
int errorCode,
|
||||
char const* msg) {
|
||||
char const* realMsg;
|
||||
|
||||
if (msg == nullptr || strlen(msg) == 0) {
|
||||
realMsg = TRI_errno_string(errorCode);
|
||||
}
|
||||
else {
|
||||
realMsg = msg;
|
||||
}
|
||||
|
||||
// log error message
|
||||
if (errorCode != TRI_ERROR_REPLICATION_APPLIER_STOPPED) {
|
||||
LOG_ERROR("replication applier error for database '%s': %s", applier->_databaseName, realMsg);
|
||||
}
|
||||
|
||||
TRI_replication_applier_state_t* state = &applier->_state;
|
||||
state->_lastError._code = errorCode;
|
||||
|
||||
TRI_GetTimeStampReplication(state->_lastError._time, sizeof(state->_lastError._time) - 1);
|
||||
|
||||
if (state->_lastError._msg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, state->_lastError._msg);
|
||||
}
|
||||
|
||||
state->_lastError._msg = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, realMsg);
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief applier thread main function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -465,11 +423,6 @@ static int SetError (TRI_replication_applier_t* applier,
|
|||
static void ApplyThread (void* data) {
|
||||
auto syncer = static_cast<triagens::arango::ContinuousSyncer*>(data);
|
||||
|
||||
// get number of running remote transactions so we can forge the transaction
|
||||
// statistics
|
||||
int const n = static_cast<int>(syncer->applier()->_runningRemoteTransactions.size());
|
||||
triagens::arango::TransactionBase::setNumbers(n, n);
|
||||
|
||||
try {
|
||||
syncer->run();
|
||||
}
|
||||
|
@ -478,128 +431,6 @@ static void ApplyThread (void* data) {
|
|||
delete syncer;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief start the replication applier
|
||||
/// note: must hold the lock when calling this
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int StartApplier (TRI_replication_applier_t* applier,
|
||||
TRI_voc_tick_t initialTick,
|
||||
bool useTick) {
|
||||
TRI_replication_applier_state_t* state = &applier->_state;
|
||||
|
||||
if (state->_active) {
|
||||
// already running
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
if (applier->_configuration._endpoint == nullptr) {
|
||||
return SetError(applier, TRI_ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION, "no endpoint configured");
|
||||
}
|
||||
|
||||
if (applier->_configuration._database == nullptr) {
|
||||
return SetError(applier, TRI_ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION, "no database configured");
|
||||
}
|
||||
|
||||
// TODO: prevent restart of the applier with a tick after a shutdown
|
||||
|
||||
std::unique_ptr<triagens::arango::ContinuousSyncer> syncer(new triagens::arango::ContinuousSyncer(applier->_server,
|
||||
applier->_vocbase,
|
||||
&applier->_configuration,
|
||||
initialTick,
|
||||
useTick));
|
||||
|
||||
// reset error
|
||||
if (state->_lastError._msg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, state->_lastError._msg);
|
||||
state->_lastError._msg = nullptr;
|
||||
}
|
||||
|
||||
state->_lastError._code = TRI_ERROR_NO_ERROR;
|
||||
|
||||
TRI_GetTimeStampReplication(state->_lastError._time, sizeof(state->_lastError._time) - 1);
|
||||
|
||||
|
||||
applier->setTermination(false);
|
||||
state->_active = true;
|
||||
|
||||
TRI_InitThread(&applier->_thread);
|
||||
|
||||
if (! TRI_StartThread(&applier->_thread, nullptr, "[applier]", ApplyThread, static_cast<void*>(syncer.get()))) {
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
syncer.release();
|
||||
|
||||
LOG_INFO("started replication applier for database '%s'",
|
||||
applier->_databaseName);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stop the replication applier
|
||||
/// note: must hold the lock when calling this
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int StopApplier (TRI_replication_applier_t* applier,
|
||||
bool resetError) {
|
||||
TRI_replication_applier_state_t* state = &applier->_state;
|
||||
|
||||
if (! state->_active) {
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
state->_active = false;
|
||||
|
||||
applier->setTermination(true);
|
||||
|
||||
TRI_SetProgressReplicationApplier(applier, "applier stopped", false);
|
||||
|
||||
if (resetError) {
|
||||
if (state->_lastError._msg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, state->_lastError._msg);
|
||||
state->_lastError._msg = nullptr;
|
||||
}
|
||||
|
||||
state->_lastError._code = TRI_ERROR_NO_ERROR;
|
||||
|
||||
TRI_GetTimeStampReplication(state->_lastError._time, sizeof(state->_lastError._time) - 1);
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shut down the replication applier
|
||||
/// note: must hold the lock when calling this
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int ShutdownApplier (TRI_replication_applier_t* applier) {
|
||||
TRI_replication_applier_state_t* state = &applier->_state;
|
||||
|
||||
if (! state->_active) {
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
state->_active = false;
|
||||
|
||||
applier->setTermination(true);
|
||||
|
||||
TRI_SetProgressReplicationApplier(applier, "applier shut down", false);
|
||||
|
||||
if (state->_lastError._msg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, state->_lastError._msg);
|
||||
state->_lastError._msg = nullptr;
|
||||
}
|
||||
|
||||
state->_lastError._code = TRI_ERROR_NO_ERROR;
|
||||
|
||||
TRI_GetTimeStampReplication(state->_lastError._time, sizeof(state->_lastError._time) - 1);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a JSON representation of an applier state
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -732,10 +563,7 @@ TRI_replication_applier_t* TRI_CreateReplicationApplier (TRI_server_t* server,
|
|||
}
|
||||
|
||||
applier->setTermination(false);
|
||||
|
||||
TRI_ASSERT(applier->_databaseName != nullptr);
|
||||
|
||||
TRI_SetProgressReplicationApplier(applier, "applier created", false);
|
||||
applier->setProgress("applier created", true);
|
||||
|
||||
return applier;
|
||||
}
|
||||
|
@ -752,138 +580,6 @@ TRI_json_t* TRI_JsonConfigurationReplicationApplier (TRI_replication_applier_con
|
|||
return JsonConfiguration(config, false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief start the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_StartReplicationApplier (TRI_replication_applier_t* applier,
|
||||
TRI_voc_tick_t initialTick,
|
||||
bool useTick) {
|
||||
LOG_TRACE("requesting replication applier start. initialTick: %llu, useTick: %d",
|
||||
(unsigned long long) initialTick,
|
||||
(int) useTick);
|
||||
|
||||
if (applier->_vocbase->_type == TRI_VOCBASE_TYPE_COORDINATOR) {
|
||||
return TRI_ERROR_CLUSTER_UNSUPPORTED;
|
||||
}
|
||||
|
||||
// wait until previous applier thread is shut down
|
||||
while (! applier->wait(10 * 1000));
|
||||
|
||||
WRITE_LOCKER(applier->_statusLock);
|
||||
|
||||
if (! applier->_state._active) {
|
||||
return StartApplier(applier, initialTick, useTick);
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stop the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_StopReplicationApplier (TRI_replication_applier_t* applier,
|
||||
bool resetError) {
|
||||
if (applier == nullptr) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
LOG_TRACE("requesting replication applier stop");
|
||||
|
||||
if (applier->_vocbase->_type == TRI_VOCBASE_TYPE_COORDINATOR) {
|
||||
return TRI_ERROR_CLUSTER_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int res;
|
||||
{
|
||||
WRITE_LOCKER(applier->_statusLock);
|
||||
|
||||
if (! applier->_state._active) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
res = ShutdownApplier(applier);
|
||||
}
|
||||
|
||||
// join the thread without the status lock (otherwise it would probably not join)
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
res = TRI_JoinThread(&applier->_thread);
|
||||
}
|
||||
else {
|
||||
// stop the thread but keep original error code
|
||||
int res2 = TRI_JoinThread(&applier->_thread);
|
||||
|
||||
if (res2 != TRI_ERROR_NO_ERROR) {
|
||||
LOG_ERROR("could not join replication applier for database '%s': %s",
|
||||
applier->_databaseName,
|
||||
TRI_errno_string(res2));
|
||||
}
|
||||
}
|
||||
|
||||
applier->setTermination(false);
|
||||
|
||||
LOG_INFO("stopped replication applier for database '%s'",
|
||||
applier->_databaseName);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shut down the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_ShutdownReplicationApplier (TRI_replication_applier_t* applier) {
|
||||
if (applier == nullptr) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
LOG_TRACE("requesting replication applier shutdown");
|
||||
|
||||
if (applier->_vocbase->_type == TRI_VOCBASE_TYPE_COORDINATOR) {
|
||||
return TRI_ERROR_CLUSTER_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int res;
|
||||
{
|
||||
WRITE_LOCKER(applier->_statusLock);
|
||||
|
||||
if (! applier->_state._active) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
res = StopApplier(applier, true);
|
||||
}
|
||||
|
||||
|
||||
// join the thread without the status lock (otherwise it would probably not join)
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
res = TRI_JoinThread(&applier->_thread);
|
||||
}
|
||||
else {
|
||||
// stop the thread but keep original error code
|
||||
int res2 = TRI_JoinThread(&applier->_thread);
|
||||
|
||||
if (res2 != TRI_ERROR_NO_ERROR) {
|
||||
LOG_ERROR("could not join replication applier for database '%s': %s",
|
||||
applier->_databaseName,
|
||||
TRI_errno_string(res2));
|
||||
}
|
||||
}
|
||||
|
||||
applier->setTermination(false);
|
||||
|
||||
{
|
||||
WRITE_LOCKER(applier->_statusLock);
|
||||
// really abort all ongoing transactions
|
||||
applier->abortRunningRemoteTransactions();
|
||||
}
|
||||
|
||||
LOG_INFO("stopped replication applier for database '%s'",
|
||||
applier->_databaseName);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief configure the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -971,7 +667,6 @@ TRI_json_t* TRI_JsonReplicationApplier (TRI_replication_applier_t* applier) {
|
|||
TRI_replication_applier_state_t state;
|
||||
TRI_replication_applier_configuration_t config;
|
||||
TRI_json_t* server;
|
||||
TRI_json_t* json;
|
||||
|
||||
int res = TRI_StateReplicationApplier(applier, &state);
|
||||
|
||||
|
@ -979,7 +674,7 @@ TRI_json_t* TRI_JsonReplicationApplier (TRI_replication_applier_t* applier) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
json = TRI_CreateObjectJson(TRI_CORE_MEM_ZONE);
|
||||
TRI_json_t* json = TRI_CreateObjectJson(TRI_CORE_MEM_ZONE);
|
||||
|
||||
if (json == nullptr) {
|
||||
TRI_DestroyStateReplicationApplier(&state);
|
||||
|
@ -1023,57 +718,6 @@ TRI_json_t* TRI_JsonReplicationApplier (TRI_replication_applier_t* applier) {
|
|||
return json;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an applier error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_SetErrorReplicationApplier (TRI_replication_applier_t* applier,
|
||||
int errorCode,
|
||||
char const* msg) {
|
||||
WRITE_LOCKER(applier->_statusLock);
|
||||
|
||||
SetError(applier, errorCode, msg);
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the progress with or without a lock
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_SetProgressReplicationApplier (TRI_replication_applier_t* applier,
|
||||
char const* msg,
|
||||
bool lock) {
|
||||
char* copy = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, msg);
|
||||
|
||||
if (copy == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
WRITE_LOCKER(applier->_statusLock);
|
||||
|
||||
if (applier->_state._progressMsg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, applier->_state._progressMsg);
|
||||
}
|
||||
|
||||
applier->_state._progressMsg = copy;
|
||||
|
||||
// write time in buffer
|
||||
TRI_GetTimeStampReplication(applier->_state._progressTime, sizeof(applier->_state._progressTime) - 1);
|
||||
}
|
||||
else {
|
||||
if (applier->_state._progressMsg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, applier->_state._progressMsg);
|
||||
}
|
||||
|
||||
applier->_state._progressMsg = copy;
|
||||
|
||||
// write time in buffer
|
||||
TRI_GetTimeStampReplication(applier->_state._progressTime, sizeof(applier->_state._progressTime) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initialise an applier state struct
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1194,21 +838,18 @@ int TRI_LoadStateReplicationApplier (TRI_vocbase_t* vocbase,
|
|||
|
||||
LOG_TRACE("replication state file '%s' found", filename);
|
||||
|
||||
TRI_json_t* json = TRI_JsonFile(TRI_CORE_MEM_ZONE, filename, nullptr);
|
||||
std::unique_ptr<TRI_json_t> json(TRI_JsonFile(TRI_UNKNOWN_MEM_ZONE, filename, nullptr));
|
||||
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, filename);
|
||||
|
||||
if (! TRI_IsObjectJson(json)) {
|
||||
if (json != nullptr) {
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
}
|
||||
|
||||
if (! TRI_IsObjectJson(json.get())) {
|
||||
return TRI_ERROR_REPLICATION_INVALID_APPLIER_STATE;
|
||||
}
|
||||
|
||||
int res = TRI_ERROR_NO_ERROR;
|
||||
|
||||
// read the server id
|
||||
TRI_json_t* serverId = TRI_LookupObjectJson(json, "serverId");
|
||||
TRI_json_t const* serverId = TRI_LookupObjectJson(json.get(), "serverId");
|
||||
|
||||
if (! TRI_IsStringJson(serverId)) {
|
||||
res = TRI_ERROR_REPLICATION_INVALID_APPLIER_STATE;
|
||||
|
@ -1220,14 +861,12 @@ int TRI_LoadStateReplicationApplier (TRI_vocbase_t* vocbase,
|
|||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
// read the ticks
|
||||
res |= ReadTick(json, "lastAppliedContinuousTick", &state->_lastAppliedContinuousTick);
|
||||
res |= ReadTick(json.get(), "lastAppliedContinuousTick", &state->_lastAppliedContinuousTick);
|
||||
|
||||
// set processed = applied
|
||||
state->_lastProcessedContinuousTick = state->_lastAppliedContinuousTick;
|
||||
}
|
||||
|
||||
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
|
||||
|
||||
LOG_TRACE("replication state file read successfully");
|
||||
|
||||
return res;
|
||||
|
@ -1392,28 +1031,6 @@ int TRI_SaveConfigurationReplicationApplier (TRI_vocbase_t* vocbase,
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stop the applier and "forget" everything
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_ForgetReplicationApplier (TRI_replication_applier_t* applier) {
|
||||
int res = TRI_StopReplicationApplier(applier, true);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
TRI_RemoveStateReplicationApplier(applier->_vocbase);
|
||||
TRI_DestroyStateReplicationApplier(&applier->_state);
|
||||
TRI_InitStateReplicationApplier(&applier->_state);
|
||||
|
||||
TRI_RemoveConfigurationReplicationApplier(applier->_vocbase);
|
||||
TRI_DestroyConfigurationReplicationApplier(&applier->_configuration);
|
||||
TRI_InitConfigurationReplicationApplier(&applier->_configuration);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- TRI_replication_applier_t
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -1424,10 +1041,10 @@ int TRI_ForgetReplicationApplier (TRI_replication_applier_t* applier) {
|
|||
|
||||
TRI_replication_applier_t::TRI_replication_applier_t (TRI_server_t* server,
|
||||
TRI_vocbase_t* vocbase)
|
||||
: _server(server),
|
||||
: _databaseName(vocbase->_name),
|
||||
_server(server),
|
||||
_vocbase(vocbase),
|
||||
_terminateThread(false),
|
||||
_databaseName(TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, vocbase->_name)) {
|
||||
_terminateThread(false) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1435,7 +1052,7 @@ TRI_replication_applier_t::TRI_replication_applier_t (TRI_server_t* server,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_replication_applier_t::~TRI_replication_applier_t () {
|
||||
TRI_StopReplicationApplier(this, true);
|
||||
stop(true);
|
||||
TRI_DestroyStateReplicationApplier(&_state);
|
||||
TRI_DestroyConfigurationReplicationApplier(&_configuration);
|
||||
|
||||
|
@ -1446,8 +1063,185 @@ TRI_replication_applier_t::~TRI_replication_applier_t () {
|
|||
trx->addHint(TRI_TRANSACTION_HINT_NO_ABORT_MARKER, true);
|
||||
delete trx;
|
||||
}
|
||||
}
|
||||
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, _databaseName);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief start the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_replication_applier_t::start (TRI_voc_tick_t initialTick,
|
||||
bool useTick) {
|
||||
LOG_TRACE("requesting replication applier start. initialTick: %llu, useTick: %d",
|
||||
(unsigned long long) initialTick,
|
||||
(int) useTick);
|
||||
|
||||
if (_vocbase->_type == TRI_VOCBASE_TYPE_COORDINATOR) {
|
||||
return TRI_ERROR_CLUSTER_UNSUPPORTED;
|
||||
}
|
||||
|
||||
// wait until previous applier thread is shut down
|
||||
while (! wait(10 * 1000));
|
||||
|
||||
WRITE_LOCKER(_statusLock);
|
||||
|
||||
if (_state._active) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
if (_configuration._endpoint == nullptr) {
|
||||
return doSetError(TRI_ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION, "no endpoint configured");
|
||||
}
|
||||
|
||||
if (_configuration._database == nullptr) {
|
||||
return doSetError(TRI_ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION, "no database configured");
|
||||
}
|
||||
|
||||
// TODO: prevent restart of the applier with a tick after a shutdown
|
||||
|
||||
std::unique_ptr<triagens::arango::ContinuousSyncer> syncer(new triagens::arango::ContinuousSyncer(_server,
|
||||
_vocbase,
|
||||
&_configuration,
|
||||
initialTick,
|
||||
useTick));
|
||||
|
||||
// reset error
|
||||
if (_state._lastError._msg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, _state._lastError._msg);
|
||||
_state._lastError._msg = nullptr;
|
||||
}
|
||||
|
||||
_state._lastError._code = TRI_ERROR_NO_ERROR;
|
||||
|
||||
TRI_GetTimeStampReplication(_state._lastError._time, sizeof(_state._lastError._time) - 1);
|
||||
|
||||
setTermination(false);
|
||||
_state._active = true;
|
||||
|
||||
TRI_InitThread(&_thread);
|
||||
|
||||
if (! TRI_StartThread(&_thread, nullptr, "[applier]", ApplyThread, static_cast<void*>(syncer.get()))) {
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
syncer.release();
|
||||
|
||||
LOG_INFO("started replication applier for database '%s'", _databaseName.c_str());
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stop the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_replication_applier_t::stop (bool resetError) {
|
||||
LOG_TRACE("requesting replication applier stop");
|
||||
|
||||
if (_vocbase->_type == TRI_VOCBASE_TYPE_COORDINATOR) {
|
||||
return TRI_ERROR_CLUSTER_UNSUPPORTED;
|
||||
}
|
||||
|
||||
{
|
||||
WRITE_LOCKER(_statusLock);
|
||||
|
||||
if (! _state._active) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
_state._active = false;
|
||||
|
||||
setTermination(true);
|
||||
setProgress("applier shut down", false);
|
||||
|
||||
if (_state._lastError._msg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, _state._lastError._msg);
|
||||
_state._lastError._msg = nullptr;
|
||||
}
|
||||
|
||||
_state._lastError._code = TRI_ERROR_NO_ERROR;
|
||||
|
||||
TRI_GetTimeStampReplication(_state._lastError._time, sizeof(_state._lastError._time) - 1);
|
||||
}
|
||||
|
||||
// join the thread without the status lock (otherwise it would probably not join)
|
||||
int res = TRI_JoinThread(&_thread);
|
||||
|
||||
setTermination(false);
|
||||
|
||||
LOG_INFO("stopped replication applier for database '%s'", _databaseName.c_str());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stop the applier and "forget" everything
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_replication_applier_t::forget () {
|
||||
int res = stop(true);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
TRI_RemoveStateReplicationApplier(_vocbase);
|
||||
TRI_DestroyStateReplicationApplier(&_state);
|
||||
TRI_InitStateReplicationApplier(&_state);
|
||||
|
||||
TRI_RemoveConfigurationReplicationApplier(_vocbase);
|
||||
TRI_DestroyConfigurationReplicationApplier(&_configuration);
|
||||
TRI_InitConfigurationReplicationApplier(&_configuration);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shut down the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_replication_applier_t::shutdown () {
|
||||
LOG_TRACE("requesting replication applier shutdown");
|
||||
|
||||
if (_vocbase->_type == TRI_VOCBASE_TYPE_COORDINATOR) {
|
||||
return TRI_ERROR_CLUSTER_UNSUPPORTED;
|
||||
}
|
||||
|
||||
{
|
||||
WRITE_LOCKER(_statusLock);
|
||||
|
||||
if (! _state._active) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
_state._active = false;
|
||||
|
||||
setTermination(true);
|
||||
setProgress("applier stopped", false);
|
||||
|
||||
if (_state._lastError._msg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, _state._lastError._msg);
|
||||
_state._lastError._msg = nullptr;
|
||||
}
|
||||
|
||||
_state._lastError._code = TRI_ERROR_NO_ERROR;
|
||||
|
||||
TRI_GetTimeStampReplication(_state._lastError._time, sizeof(_state._lastError._time) - 1);
|
||||
}
|
||||
|
||||
|
||||
// join the thread without the status lock (otherwise it would probably not join)
|
||||
int res = TRI_JoinThread(&_thread);
|
||||
|
||||
setTermination(false);
|
||||
|
||||
{
|
||||
WRITE_LOCKER(_statusLock);
|
||||
// really abort all ongoing transactions
|
||||
abortRunningRemoteTransactions();
|
||||
}
|
||||
|
||||
LOG_INFO("stopped replication applier for database '%s'", _databaseName.c_str());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1493,7 +1287,90 @@ bool TRI_replication_applier_t::wait (uint64_t sleepTime) {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the progress with or without a lock
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_replication_applier_t::setProgress (char const* msg,
|
||||
bool lock) {
|
||||
char* copy = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, msg);
|
||||
|
||||
if (copy == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
WRITE_LOCKER(_statusLock);
|
||||
|
||||
if (_state._progressMsg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, _state._progressMsg);
|
||||
}
|
||||
|
||||
_state._progressMsg = copy;
|
||||
|
||||
// write time in buffer
|
||||
TRI_GetTimeStampReplication(_state._progressTime, sizeof(_state._progressTime) - 1);
|
||||
}
|
||||
else {
|
||||
if (_state._progressMsg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, _state._progressMsg);
|
||||
}
|
||||
|
||||
_state._progressMsg = copy;
|
||||
|
||||
// write time in buffer
|
||||
TRI_GetTimeStampReplication(_state._progressTime, sizeof(_state._progressTime) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an applier error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_replication_applier_t::setError (int errorCode,
|
||||
char const* msg) {
|
||||
WRITE_LOCKER(_statusLock);
|
||||
return doSetError(errorCode, msg);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an applier error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_replication_applier_t::doSetError (int errorCode,
|
||||
char const* msg) {
|
||||
char const* realMsg;
|
||||
|
||||
if (msg == nullptr || strlen(msg) == 0) {
|
||||
realMsg = TRI_errno_string(errorCode);
|
||||
}
|
||||
else {
|
||||
realMsg = msg;
|
||||
}
|
||||
|
||||
// log error message
|
||||
if (errorCode != TRI_ERROR_REPLICATION_APPLIER_STOPPED) {
|
||||
LOG_ERROR("replication applier error for database '%s': %s", _databaseName.c_str(), realMsg);
|
||||
}
|
||||
|
||||
_state._lastError._code = errorCode;
|
||||
|
||||
TRI_GetTimeStampReplication(_state._lastError._time, sizeof(_state._lastError._time) - 1);
|
||||
|
||||
if (_state._lastError._msg != nullptr) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, _state._lastError._msg);
|
||||
}
|
||||
|
||||
_state._lastError._msg = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, realMsg);
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -112,54 +112,123 @@ struct TRI_replication_applier_state_t {
|
|||
/// @brief replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TRI_replication_applier_t {
|
||||
TRI_replication_applier_t (TRI_server_t*,
|
||||
TRI_vocbase_t*);
|
||||
class TRI_replication_applier_t {
|
||||
public:
|
||||
|
||||
~TRI_replication_applier_t ();
|
||||
TRI_replication_applier_t (TRI_server_t*,
|
||||
TRI_vocbase_t*);
|
||||
|
||||
~TRI_replication_applier_t ();
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief pauses and checks whether the apply thread should terminate
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool wait (uint64_t);
|
||||
bool wait (uint64_t);
|
||||
|
||||
bool isTerminated () {
|
||||
return _terminateThread.load();
|
||||
}
|
||||
bool isTerminated () {
|
||||
return _terminateThread.load();
|
||||
}
|
||||
|
||||
void setTermination (bool value) {
|
||||
_terminateThread.store(value);
|
||||
}
|
||||
|
||||
void addRemoteTransaction (triagens::arango::ReplicationTransaction* trx) {
|
||||
_runningRemoteTransactions.insert(std::make_pair(trx->externalId(), trx));
|
||||
}
|
||||
|
||||
void abortRunningRemoteTransactions () {
|
||||
size_t const n = _runningRemoteTransactions.size();
|
||||
triagens::arango::TransactionBase::increaseNumbers((int) n, (int) n);
|
||||
|
||||
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->removeHint(TRI_TRANSACTION_HINT_NO_ABORT_MARKER, true);
|
||||
delete trx;
|
||||
void setTermination (bool value) {
|
||||
_terminateThread.store(value);
|
||||
}
|
||||
|
||||
_runningRemoteTransactions.clear();
|
||||
}
|
||||
void addRemoteTransaction (triagens::arango::ReplicationTransaction* trx) {
|
||||
_runningRemoteTransactions.insert(std::make_pair(trx->externalId(), trx));
|
||||
}
|
||||
|
||||
TRI_server_t* _server;
|
||||
TRI_vocbase_t* _vocbase;
|
||||
triagens::basics::ReadWriteLock _statusLock;
|
||||
std::atomic<bool> _terminateThread;
|
||||
TRI_replication_applier_state_t _state;
|
||||
TRI_replication_applier_configuration_t _configuration;
|
||||
char* _databaseName;
|
||||
TRI_thread_t _thread;
|
||||
std::unordered_map<TRI_voc_tid_t, triagens::arango::ReplicationTransaction*> _runningRemoteTransactions;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the database name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char const* databaseName () const {
|
||||
return _databaseName.c_str();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief start the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int start (TRI_voc_tick_t,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stop the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int stop (bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stop the applier and "forget" everything
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int forget ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shuts down the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int shutdown ();
|
||||
|
||||
void abortRunningRemoteTransactions () {
|
||||
size_t const n = _runningRemoteTransactions.size();
|
||||
triagens::arango::TransactionBase::increaseNumbers((int) n, (int) n);
|
||||
|
||||
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->removeHint(TRI_TRANSACTION_HINT_NO_ABORT_MARKER, true);
|
||||
delete trx;
|
||||
}
|
||||
|
||||
_runningRemoteTransactions.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the progress with or without a lock
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setProgress (char const*,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an applier error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int setError (int,
|
||||
char const*);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an applier error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int doSetError (int,
|
||||
char const*);
|
||||
|
||||
private:
|
||||
|
||||
std::string _databaseName;
|
||||
|
||||
public:
|
||||
|
||||
TRI_server_t* _server;
|
||||
TRI_vocbase_t* _vocbase;
|
||||
triagens::basics::ReadWriteLock _statusLock;
|
||||
std::atomic<bool> _terminateThread;
|
||||
TRI_replication_applier_state_t _state;
|
||||
TRI_replication_applier_configuration_t _configuration;
|
||||
TRI_thread_t _thread;
|
||||
std::unordered_map<TRI_voc_tid_t, triagens::arango::ReplicationTransaction*> _runningRemoteTransactions;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -183,27 +252,6 @@ TRI_replication_applier_t* TRI_CreateReplicationApplier (TRI_server_t*,
|
|||
|
||||
struct TRI_json_t* TRI_JsonConfigurationReplicationApplier (TRI_replication_applier_configuration_t const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief start the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_StartReplicationApplier (TRI_replication_applier_t*,
|
||||
TRI_voc_tick_t,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stop the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_StopReplicationApplier (TRI_replication_applier_t*,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shuts down the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_ShutdownReplicationApplier (TRI_replication_applier_t*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief configure the replication applier
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -224,22 +272,6 @@ int TRI_StateReplicationApplier (TRI_replication_applier_t*,
|
|||
|
||||
struct TRI_json_t* TRI_JsonReplicationApplier (TRI_replication_applier_t*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an applier error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_SetErrorReplicationApplier (TRI_replication_applier_t*,
|
||||
int,
|
||||
char const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the progress with or without a lock
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_SetProgressReplicationApplier (TRI_replication_applier_t*,
|
||||
char const*,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initialise an apply state struct
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -306,12 +338,6 @@ int TRI_SaveConfigurationReplicationApplier (TRI_vocbase_t*,
|
|||
TRI_replication_applier_configuration_t const*,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stop the applier and "forget" everything
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_ForgetReplicationApplier (TRI_replication_applier_t*);
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -710,34 +710,6 @@ static int OpenDatabases (TRI_server_t* server,
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief stop the replication appliers in all databases
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void StopReplicationAppliers (TRI_server_t* server) {
|
||||
MUTEX_LOCKER(server->_databasesMutex); // Only one should do this at a time
|
||||
// No need for the thread protector here, because we have the mutex
|
||||
|
||||
for (auto& p : server->_databasesLists.load()->_databases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
TRI_ASSERT(vocbase != nullptr);
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief close all opened databases
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1981,7 +1953,7 @@ int TRI_InitDatabasesServer (TRI_server_t* server) {
|
|||
LOG_INFO("replication applier explicitly deactivated for database '%s'", vocbase->_name);
|
||||
}
|
||||
else {
|
||||
int res = TRI_StartReplicationApplier(vocbase->_replicationApplier, 0, false);
|
||||
int res = vocbase->_replicationApplier->start(0, false);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
LOG_WARNING("unable to start replication applier for database '%s': %s",
|
||||
|
@ -2018,7 +1990,17 @@ int TRI_StopServer (TRI_server_t* server) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_StopReplicationAppliersServer (TRI_server_t* server) {
|
||||
StopReplicationAppliers(server);
|
||||
MUTEX_LOCKER(server->_databasesMutex); // Only one should do this at a time
|
||||
// No need for the thread protector here, because we have the mutex
|
||||
|
||||
for (auto& p : server->_databasesLists.load()->_databases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
TRI_ASSERT(vocbase != nullptr);
|
||||
TRI_ASSERT(vocbase->_type == TRI_VOCBASE_TYPE_NORMAL);
|
||||
if (vocbase->_replicationApplier != nullptr) {
|
||||
vocbase->_replicationApplier->stop(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2221,7 +2203,7 @@ int TRI_CreateDatabaseServer (TRI_server_t* server,
|
|||
LOG_INFO("replication applier explicitly deactivated for database '%s'", name);
|
||||
}
|
||||
else {
|
||||
res = TRI_StartReplicationApplier(vocbase->_replicationApplier, 0, false);
|
||||
res = vocbase->_replicationApplier->start(0, false);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
LOG_WARNING("unable to start replication applier for database '%s': %s",
|
||||
|
|
|
@ -148,7 +148,7 @@ void ClearQueryCache (TRI_transaction_t* trx) {
|
|||
}
|
||||
}
|
||||
catch (...) {
|
||||
// in case something goes wrong, we have to disable the query cache
|
||||
// in case something goes wrong, we have to remove all queries from the cache
|
||||
triagens::aql::QueryCache::instance()->invalidate(trx->_vocbase);
|
||||
}
|
||||
}
|
||||
|
@ -1413,6 +1413,7 @@ int TRI_CommitTransaction (TRI_transaction_t* trx,
|
|||
|
||||
// if a write query, clear the query cache for the participating collections
|
||||
if (trx->_type == TRI_TRANSACTION_WRITE &&
|
||||
trx->_collections._length > 0 &&
|
||||
triagens::aql::QueryCache::instance()->mayBeActive()) {
|
||||
ClearQueryCache(trx);
|
||||
}
|
||||
|
|
|
@ -1501,12 +1501,12 @@ TRI_vocbase_t* TRI_OpenVocBase (TRI_server_t* server,
|
|||
void TRI_DestroyVocBase (TRI_vocbase_t* vocbase) {
|
||||
// stop replication
|
||||
if (vocbase->_replicationApplier != nullptr) {
|
||||
TRI_StopReplicationApplier(vocbase->_replicationApplier, false);
|
||||
vocbase->_replicationApplier->stop(false);
|
||||
}
|
||||
|
||||
// mark all cursors as deleted so underlying collections can be freed soon
|
||||
if (vocbase->_cursorRepository != nullptr) {
|
||||
static_cast<triagens::arango::CursorRepository*>(vocbase->_cursorRepository)->garbageCollect(true);
|
||||
vocbase->_cursorRepository->garbageCollect(true);
|
||||
}
|
||||
|
||||
std::vector<TRI_vocbase_col_t*> collections;
|
||||
|
@ -2446,8 +2446,8 @@ TRI_vocbase_t::~TRI_vocbase_t () {
|
|||
TRI_DestroyAssociativePointer(&_collectionsByName);
|
||||
TRI_DestroyAssociativePointer(&_collectionsById);
|
||||
|
||||
delete static_cast<triagens::arango::CursorRepository*>(_cursorRepository);
|
||||
delete static_cast<triagens::aql::QueryList*>(_queries);
|
||||
delete _cursorRepository;
|
||||
delete _queries;
|
||||
|
||||
// free name and path
|
||||
if (_path != nullptr) {
|
||||
|
|
|
@ -46,11 +46,20 @@
|
|||
struct TRI_col_info_s;
|
||||
struct TRI_document_collection_t;
|
||||
struct TRI_json_t;
|
||||
struct TRI_replication_applier_t;
|
||||
class TRI_replication_applier_t;
|
||||
struct TRI_server_t;
|
||||
struct TRI_vocbase_col_s;
|
||||
struct TRI_vocbase_defaults_s;
|
||||
|
||||
namespace triagens {
|
||||
namespace aql {
|
||||
class QueryList;
|
||||
}
|
||||
namespace arango {
|
||||
class CursorRepository;
|
||||
}
|
||||
}
|
||||
|
||||
extern bool IGNORE_DATAFILE_ERRORS;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -287,8 +296,8 @@ struct TRI_vocbase_t {
|
|||
|
||||
// structures for user-defined volatile data
|
||||
void* _userStructures;
|
||||
void* _queries;
|
||||
void* _cursorRepository;
|
||||
triagens::aql::QueryList* _queries;
|
||||
triagens::arango::CursorRepository* _cursorRepository;
|
||||
|
||||
TRI_associative_pointer_t _authInfo;
|
||||
TRI_associative_pointer_t _authCache;
|
||||
|
@ -299,7 +308,7 @@ struct TRI_vocbase_t {
|
|||
|
||||
std::set<TRI_voc_tid_t>* _oldTransactions;
|
||||
|
||||
struct TRI_replication_applier_t* _replicationApplier;
|
||||
class TRI_replication_applier_t* _replicationApplier;
|
||||
|
||||
// state of the database
|
||||
// 0 = inactive
|
||||
|
|
|
@ -880,7 +880,7 @@ void ArangoClient::shutup () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool ArangoClient::colors () const {
|
||||
return ! _noColors;
|
||||
return (! _noColors && isatty(STDIN_FILENO));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -44,16 +44,11 @@
|
|||
#include "Rest/Endpoint.h"
|
||||
#include "Rest/InitialiseRest.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
#include "Rest/SslInterface.h"
|
||||
#include "SimpleHttpClient/GeneralClientConnection.h"
|
||||
#include "SimpleHttpClient/SimpleHttpClient.h"
|
||||
#include "SimpleHttpClient/SimpleHttpResult.h"
|
||||
|
||||
#ifdef TRI_FILESYSTEM_CASE_BROKEN
|
||||
#include <openssl/md5.h>
|
||||
#else
|
||||
#define hexStr ""
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace triagens::basics;
|
||||
using namespace triagens::httpclient;
|
||||
|
@ -282,13 +277,11 @@ static string GetHttpErrorMessage (SimpleHttpResult* result) {
|
|||
StringBuffer const& body = result->getBody();
|
||||
string details;
|
||||
|
||||
TRI_json_t* json = JsonHelper::fromString(body.c_str(), body.length());
|
||||
std::unique_ptr<TRI_json_t> json(JsonHelper::fromString(body.c_str(), body.length()));
|
||||
|
||||
if (json != nullptr) {
|
||||
const string& errorMessage = JsonHelper::getStringValue(json, "errorMessage", "");
|
||||
const int errorNum = JsonHelper::getNumericValue<int>(json, "errorNum", 0);
|
||||
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
const string& errorMessage = JsonHelper::getStringValue(json.get(), "errorMessage", "");
|
||||
const int errorNum = JsonHelper::getNumericValue<int>(json.get(), "errorNum", 0);
|
||||
|
||||
if (errorMessage != "" && errorNum > 0) {
|
||||
details = ": ArangoError " + StringUtils::itoa(errorNum) + ": " + errorMessage;
|
||||
|
@ -329,20 +322,17 @@ static string GetArangoVersion () {
|
|||
version = "arango";
|
||||
|
||||
// convert response body to json
|
||||
TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE,
|
||||
response->getBody().c_str());
|
||||
std::unique_ptr<TRI_json_t> json(TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, response->getBody().c_str()));
|
||||
|
||||
if (json != nullptr) {
|
||||
// look up "server" value
|
||||
const string server = JsonHelper::getStringValue(json, "server", "");
|
||||
const string server = JsonHelper::getStringValue(json.get(), "server", "");
|
||||
|
||||
// "server" value is a string and content is "arango"
|
||||
if (server == "arango") {
|
||||
// look up "version" value
|
||||
version = JsonHelper::getStringValue(json, "version", "");
|
||||
version = JsonHelper::getStringValue(json.get(), "version", "");
|
||||
}
|
||||
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -382,14 +372,11 @@ static bool GetArangoIsCluster () {
|
|||
|
||||
if (response->getHttpReturnCode() == HttpResponse::OK) {
|
||||
// convert response body to json
|
||||
TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE,
|
||||
response->getBody().c_str());
|
||||
std::unique_ptr<TRI_json_t> json(TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, response->getBody().c_str()));
|
||||
|
||||
if (json != nullptr) {
|
||||
// look up "server" value
|
||||
role = JsonHelper::getStringValue(json, "role", "UNDEFINED");
|
||||
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
role = JsonHelper::getStringValue(json.get(), "role", "UNDEFINED");
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -448,7 +435,7 @@ static int StartBatch (string DBserver, string& errorMsg) {
|
|||
}
|
||||
|
||||
// convert response body to json
|
||||
TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, response->getBody().c_str());
|
||||
std::unique_ptr<TRI_json_t> json(TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, response->getBody().c_str()));
|
||||
delete response;
|
||||
|
||||
if (json == nullptr) {
|
||||
|
@ -458,9 +445,7 @@ static int StartBatch (string DBserver, string& errorMsg) {
|
|||
}
|
||||
|
||||
// look up "id" value
|
||||
const string id = JsonHelper::getStringValue(json, "id", "");
|
||||
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
const string id = JsonHelper::getStringValue(json.get(), "id", "");
|
||||
|
||||
BatchId = StringUtils::uint64(id);
|
||||
|
||||
|
@ -698,34 +683,28 @@ static int RunDump (string& errorMsg) {
|
|||
StringBuffer const& data = response->getBody();
|
||||
|
||||
|
||||
TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, data.c_str());
|
||||
std::unique_ptr<TRI_json_t> json(TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, data.c_str()));
|
||||
|
||||
delete response;
|
||||
|
||||
if (! JsonHelper::isObject(json)) {
|
||||
if (json != nullptr) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
}
|
||||
|
||||
if (! JsonHelper::isObject(json.get())) {
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
TRI_json_t const* collections = JsonHelper::getObjectElement(json, "collections");
|
||||
TRI_json_t const* collections = JsonHelper::getObjectElement(json.get(), "collections");
|
||||
|
||||
if (! JsonHelper::isArray(collections)) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
// read the server's max tick value
|
||||
const string tickString = JsonHelper::getStringValue(json, "tick", "");
|
||||
const string tickString = JsonHelper::getStringValue(json.get(), "tick", "");
|
||||
|
||||
if (tickString == "") {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
|
@ -744,7 +723,6 @@ static int RunDump (string& errorMsg) {
|
|||
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;
|
||||
|
@ -767,7 +745,6 @@ static int RunDump (string& errorMsg) {
|
|||
|
||||
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;
|
||||
|
@ -779,7 +756,6 @@ static int RunDump (string& errorMsg) {
|
|||
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;
|
||||
}
|
||||
|
@ -801,7 +777,6 @@ static int RunDump (string& errorMsg) {
|
|||
TRI_json_t const* collection = (TRI_json_t const*) TRI_AtVector(&collections->_value._objects, i);
|
||||
|
||||
if (! JsonHelper::isObject(collection)) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
|
@ -810,7 +785,6 @@ static int RunDump (string& errorMsg) {
|
|||
TRI_json_t const* parameters = JsonHelper::getObjectElement(collection, "parameters");
|
||||
|
||||
if (! JsonHelper::isObject(parameters)) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
|
@ -821,7 +795,6 @@ static int RunDump (string& errorMsg) {
|
|||
const bool deleted = JsonHelper::getBooleanValue(parameters, "deleted", false);
|
||||
|
||||
if (cid == "" || name == "") {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
|
@ -841,20 +814,7 @@ 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
|
||||
|
||||
std::string const hexString(triagens::rest::SslInterface::sslMD5(name));
|
||||
|
||||
// found a collection!
|
||||
if (Progress) {
|
||||
|
@ -866,7 +826,7 @@ static int RunDump (string& errorMsg) {
|
|||
|
||||
{
|
||||
// save meta data
|
||||
string fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + hexStr + ".structure.json";
|
||||
string fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + "_" + hexString + ".structure.json";
|
||||
|
||||
int fd;
|
||||
|
||||
|
@ -879,7 +839,6 @@ static int RunDump (string& errorMsg) {
|
|||
|
||||
if (fd < 0) {
|
||||
errorMsg = "cannot write to file '" + fileName + "'";
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
||||
return TRI_ERROR_CANNOT_WRITE_FILE;
|
||||
}
|
||||
|
@ -889,7 +848,6 @@ static int RunDump (string& errorMsg) {
|
|||
if (! TRI_WritePointer(fd, collectionInfo.c_str(), collectionInfo.size())) {
|
||||
TRI_CLOSE(fd);
|
||||
errorMsg = "cannot write to file '" + fileName + "'";
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
||||
return TRI_ERROR_CANNOT_WRITE_FILE;
|
||||
}
|
||||
|
@ -901,7 +859,7 @@ static int RunDump (string& errorMsg) {
|
|||
if (DumpData) {
|
||||
// save the actual data
|
||||
string fileName;
|
||||
fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + hexStr + ".data.json";
|
||||
fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + "_" + hexString + ".data.json";
|
||||
|
||||
int fd;
|
||||
|
||||
|
@ -914,7 +872,6 @@ static int RunDump (string& errorMsg) {
|
|||
|
||||
if (fd < 0) {
|
||||
errorMsg = "cannot write to file '" + fileName + "'";
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
||||
return TRI_ERROR_CANNOT_WRITE_FILE;
|
||||
}
|
||||
|
@ -928,19 +885,12 @@ static int RunDump (string& errorMsg) {
|
|||
if (errorMsg.empty()) {
|
||||
errorMsg = "cannot write to file '" + fileName + "'";
|
||||
}
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
#ifdef TRI_FILESYSTEM_CASE_BROKEN
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, hexStr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
@ -1099,24 +1049,19 @@ static int RunClusterDump (string& errorMsg) {
|
|||
StringBuffer const& data = response->getBody();
|
||||
|
||||
|
||||
TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, data.c_str());
|
||||
std::unique_ptr<TRI_json_t> json(TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, data.c_str()));
|
||||
|
||||
delete response;
|
||||
|
||||
if (! JsonHelper::isObject(json)) {
|
||||
if (json != nullptr) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
}
|
||||
|
||||
if (! JsonHelper::isObject(json.get())) {
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
TRI_json_t const* collections = JsonHelper::getObjectElement(json, "collections");
|
||||
TRI_json_t const* collections = JsonHelper::getObjectElement(json.get(), "collections");
|
||||
|
||||
if (! JsonHelper::isArray(collections)) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
|
@ -1135,7 +1080,6 @@ static int RunClusterDump (string& errorMsg) {
|
|||
TRI_json_t const* collection = (TRI_json_t const*) TRI_AtVector(&collections->_value._objects, i);
|
||||
|
||||
if (! JsonHelper::isObject(collection)) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
|
@ -1144,7 +1088,6 @@ static int RunClusterDump (string& errorMsg) {
|
|||
TRI_json_t const* parameters = JsonHelper::getObjectElement(collection, "parameters");
|
||||
|
||||
if (! JsonHelper::isObject(parameters)) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
|
@ -1155,7 +1098,6 @@ static int RunClusterDump (string& errorMsg) {
|
|||
const bool deleted = JsonHelper::getBooleanValue(parameters, "deleted", false);
|
||||
|
||||
if (id == "" || name == "") {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
errorMsg = "got malformed JSON response from server";
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
|
@ -1199,7 +1141,6 @@ static int RunClusterDump (string& errorMsg) {
|
|||
|
||||
if (fd < 0) {
|
||||
errorMsg = "cannot write to file '" + fileName + "'";
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
||||
return TRI_ERROR_CANNOT_WRITE_FILE;
|
||||
}
|
||||
|
@ -1209,7 +1150,6 @@ static int RunClusterDump (string& errorMsg) {
|
|||
if (! TRI_WritePointer(fd, collectionInfo.c_str(), collectionInfo.size())) {
|
||||
TRI_CLOSE(fd);
|
||||
errorMsg = "cannot write to file '" + fileName + "'";
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
||||
return TRI_ERROR_CANNOT_WRITE_FILE;
|
||||
}
|
||||
|
@ -1228,38 +1168,18 @@ static int RunClusterDump (string& errorMsg) {
|
|||
// This is now a map from shardIDs to DBservers
|
||||
|
||||
// Now set up the output file:
|
||||
string fileName;
|
||||
#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;
|
||||
std::string const hexString(triagens::rest::SslInterface::sslMD5(name));
|
||||
string fileName = OutputDirectory + TRI_DIR_SEPARATOR_STR + name + "_" + hexString + ".data.json";
|
||||
|
||||
// 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);
|
||||
int fd = TRI_CREATE(fileName.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
|
||||
if (fd < 0) {
|
||||
errorMsg = "cannot write to file '" + fileName + "'";
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
||||
return TRI_ERROR_CANNOT_WRITE_FILE;
|
||||
}
|
||||
|
@ -1274,13 +1194,11 @@ static int RunClusterDump (string& errorMsg) {
|
|||
}
|
||||
res = StartBatch(DBserver, errorMsg);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
TRI_CLOSE(fd);
|
||||
return res;
|
||||
}
|
||||
res = DumpShard(fd, DBserver, shardName, errorMsg);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
TRI_CLOSE(fd);
|
||||
return res;
|
||||
}
|
||||
|
@ -1289,20 +1207,16 @@ static int RunClusterDump (string& errorMsg) {
|
|||
|
||||
res = TRI_CLOSE(fd);
|
||||
|
||||
if (res != 0) {
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
if (errorMsg.empty()) {
|
||||
errorMsg = "cannot write to file '" + fileName + "'";
|
||||
}
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,29 +31,24 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "ArangoShell/ArangoClient.h"
|
||||
#include "Basics/files.h"
|
||||
#include "Basics/FileUtils.h"
|
||||
#include "Basics/init.h"
|
||||
#include "Basics/JsonHelper.h"
|
||||
#include "Basics/logging.h"
|
||||
#include "Basics/ProgramOptions.h"
|
||||
#include "Basics/ProgramOptionsDescription.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/files.h"
|
||||
#include "Basics/init.h"
|
||||
#include "Basics/logging.h"
|
||||
#include "Basics/tri-strings.h"
|
||||
#include "Basics/terminal-utils.h"
|
||||
#include "Basics/tri-strings.h"
|
||||
#include "Rest/Endpoint.h"
|
||||
#include "Rest/InitialiseRest.h"
|
||||
#include "Rest/HttpResponse.h"
|
||||
#include "Rest/SslInterface.h"
|
||||
#include "SimpleHttpClient/GeneralClientConnection.h"
|
||||
#include "SimpleHttpClient/SimpleHttpClient.h"
|
||||
#include "SimpleHttpClient/SimpleHttpResult.h"
|
||||
|
||||
#ifdef TRI_FILESYSTEM_CASE_BROKEN
|
||||
#include <openssl/md5.h>
|
||||
#else
|
||||
#define hexStr ""
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace triagens::basics;
|
||||
using namespace triagens::httpclient;
|
||||
|
@ -625,7 +620,6 @@ static int SortCollections (const void* l,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int ProcessInputDirectory (string& errorMsg) {
|
||||
|
||||
// create a lookup table for collections
|
||||
map<string, bool> restrictList;
|
||||
for (size_t i = 0; i < Collections.size(); ++i) {
|
||||
|
@ -644,8 +638,7 @@ static int ProcessInputDirectory (string& errorMsg) {
|
|||
const vector<string> files = FileUtils::listFiles(InputDirectory);
|
||||
const size_t n = files.size();
|
||||
|
||||
// TODO: externalise file extension
|
||||
const string suffix = string(".structure.json");
|
||||
const string suffix = std::string(".structure.json");
|
||||
|
||||
// loop over all files in InputDirectory, and look for all structure.json files
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
|
@ -665,21 +658,6 @@ static int ProcessInputDirectory (string& errorMsg) {
|
|||
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
|
||||
continue;
|
||||
}
|
||||
|
||||
const string fqn = InputDirectory + TRI_DIR_SEPARATOR_STR + files[i];
|
||||
|
||||
TRI_json_t* json = TRI_JsonFile(TRI_UNKNOWN_MEM_ZONE, fqn.c_str(), 0);
|
||||
|
@ -689,7 +667,7 @@ static int ProcessInputDirectory (string& errorMsg) {
|
|||
if (! JsonHelper::isObject(json) ||
|
||||
! JsonHelper::isObject(parameters) ||
|
||||
! JsonHelper::isArray(indexes)) {
|
||||
errorMsg = "could not read collection structure file '" + name + "'";
|
||||
errorMsg = "could not read collection structure file '" + fqn + "'";
|
||||
|
||||
if (json != nullptr) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
|
@ -702,12 +680,12 @@ static int ProcessInputDirectory (string& errorMsg) {
|
|||
|
||||
const string cname = JsonHelper::getStringValue(parameters, "name", "");
|
||||
|
||||
if (cname != name) {
|
||||
if (cname != name && name != (cname + "_" + triagens::rest::SslInterface::sslMD5(cname))) {
|
||||
// file has a different name than found in structure file
|
||||
|
||||
if (ImportStructure) {
|
||||
// we cannot go on if there is a mismatch
|
||||
errorMsg = "collection name mismatch in collection structure file '" + name + "' (offending value: '" + cname + "')";
|
||||
errorMsg = "collection name mismatch in collection structure file '" + fqn + "' (offending value: '" + cname + "')";
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, collections);
|
||||
|
||||
|
@ -715,7 +693,7 @@ static int ProcessInputDirectory (string& errorMsg) {
|
|||
}
|
||||
else {
|
||||
// we can patch the name in our array and go on
|
||||
cout << "ignoring collection name mismatch in collection structure file '" + name + "' (offending value: '" + cname + "')" << endl;
|
||||
cout << "ignoring collection name mismatch in collection structure file '" + fqn + "' (offending value: '" + cname + "')" << endl;
|
||||
|
||||
TRI_json_t* nameAttribute = TRI_LookupObjectJson(parameters, "name");
|
||||
|
||||
|
@ -731,6 +709,13 @@ static int ProcessInputDirectory (string& errorMsg) {
|
|||
}
|
||||
}
|
||||
|
||||
if (! restrictList.empty() > 0 &&
|
||||
restrictList.find(cname) == restrictList.end()) {
|
||||
// collection name not in list
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
continue;
|
||||
}
|
||||
|
||||
TRI_PushBack3ArrayJson(TRI_UNKNOWN_MEM_ZONE, collections, json);
|
||||
}
|
||||
}
|
||||
|
@ -780,24 +765,10 @@ static int ProcessInputDirectory (string& errorMsg) {
|
|||
|
||||
if (ImportData) {
|
||||
// import data. check if we have a datafile
|
||||
// TODO: externalise file extension
|
||||
#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
|
||||
std::string datafile = InputDirectory + TRI_DIR_SEPARATOR_STR + cname + "_" + triagens::rest::SslInterface::sslMD5(cname) + ".data.json";
|
||||
if (! TRI_ExistsFile(datafile.c_str())) {
|
||||
datafile = InputDirectory + TRI_DIR_SEPARATOR_STR + cname + ".data.json";
|
||||
}
|
||||
|
||||
if (TRI_ExistsFile(datafile.c_str())) {
|
||||
// found a datafile
|
||||
|
|
|
@ -530,7 +530,7 @@ function processQuery (query, explain) {
|
|||
return keyword("REPLACE") + " " + variableName(node.inDocVariable) + " " + keyword("IN") + " " + collection(node.collection);
|
||||
case "UpsertNode":
|
||||
modificationFlags = node.modificationFlags;
|
||||
return keyword("UPSERT") + " " + variableName(node.inDocVariable) + " " + keyword("INSERT") + " " + variableName(node.insertVariable) + " " + keyword(node.isReplace ? "REPLACE" : "UPDATE") + variableName(node.updateVariable) + " " + keyword("IN") + " " + collection(node.collection);
|
||||
return keyword("UPSERT") + " " + variableName(node.inDocVariable) + " " + keyword("INSERT") + " " + variableName(node.insertVariable) + " " + keyword(node.isReplace ? "REPLACE" : "UPDATE") + " " + variableName(node.updateVariable) + " " + keyword("IN") + " " + collection(node.collection);
|
||||
case "RemoveNode":
|
||||
modificationFlags = node.modificationFlags;
|
||||
return keyword("REMOVE") + " " + variableName(node.inVariable) + " " + keyword("IN") + " " + collection(node.collection);
|
||||
|
|
|
@ -363,7 +363,7 @@
|
|||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// /// @EXAMPLE_ARANGOSH_RUN{HttpGharialGetGraph}
|
||||
/// @EXAMPLE_ARANGOSH_RUN{HttpGharialGetGraph}
|
||||
/// var graph = require("org/arangodb/general-graph");
|
||||
/// | if (graph._exists("myGraph")) {
|
||||
/// | graph._drop("myGraph", true);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue