1
0
Fork 0

Merge remote-tracking branch 'origin/devel' into array_indexing

This commit is contained in:
Michael Hackstein 2015-08-21 15:34:49 +02:00
commit b708a7ae68
110 changed files with 1871 additions and 2252 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.sh eol=lf

4
.gitignore vendored
View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"
]
]
```

View File

@ -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.

View File

@ -1,4 +1,4 @@
!BOOK ArangoDB Documentation
!BOOK ArangoDB VERSION_NUMBER Documentation
Welcome to the ArangoDB documentation!

View File

@ -1,6 +1,6 @@
{
"gitbook": ">=2.0.0",
"title": "ArangoDB Documentation",
"title": "ArangoDB VERSION_NUMBER Documentation",
"language": "en",
"plugins":["expandable-chapters", "addcssjs"],
"pdf": {

View File

@ -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 \

View File

@ -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" ]
}

View File

@ -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

View File

View File

@ -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;
}
// -----------------------------------------------------------------------------

View File

@ -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;
};
}

View File

@ -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;

View File

@ -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*);
////////////////////////////////////////////////////////////////////////////////

View File

@ -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;
}

View File

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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

View File

@ -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(')');
}

View File

@ -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

View File

@ -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);
}

View File

@ -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) {

View File

@ -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());

View File

@ -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);
}

View File

@ -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*);
////////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -79,6 +79,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
Variable* createVariable (char const*,
size_t,
bool);
////////////////////////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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 {

View File

@ -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 {
}
// -----------------------------------------------------------------------------

View File

@ -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
////////////////////////////////////////////////////////////////////////////////

View File

@ -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
////////////////////////////////////////////////////////////////////////////////

View File

@ -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);
};
};

View File

@ -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;
}

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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 \

View File

@ -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 = "";
}

View File

@ -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:

View File

@ -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:

View File

@ -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);
};
}
}

View File

@ -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 {

View File

@ -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);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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 {

View File

@ -81,7 +81,7 @@ namespace triagens {
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////
void handleError (const basics::Exception&);
void handleError (const basics::Exception&) override;
};
}
}

View File

@ -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);

View File

@ -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

View File

@ -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 {

View File

@ -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:

View File

@ -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:

View File

@ -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);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -137,7 +137,7 @@ namespace triagens {
/// @brief whether or not the thread is chatty on shutdown
////////////////////////////////////////////////////////////////////////////////
bool isSilent () {
bool isSilent () override {
return true;
}

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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
// .............................................................................

View File

@ -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
// -----------------------------------------------------------------------------

View 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
// -----------------------------------------------------------------------------

View File

@ -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",

View File

@ -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);
}

View File

@ -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) {

View File

@ -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

View File

@ -880,7 +880,7 @@ void ArangoClient::shutup () {
////////////////////////////////////////////////////////////////////////////////
bool ArangoClient::colors () const {
return ! _noColors;
return (! _noColors && isatty(STDIN_FILENO));
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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