mirror of https://gitee.com/bigwinds/arangodb
refactored cursor API, added export API
This commit is contained in:
parent
80a99ab23e
commit
e672d791b5
|
@ -5,7 +5,7 @@
|
||||||
This is an introduction to ArangoDB's HTTP Interface for Queries. Results of AQL
|
This is an introduction to ArangoDB's HTTP Interface for Queries. Results of AQL
|
||||||
and simple queries are returned as cursors in order to batch the communication
|
and simple queries are returned as cursors in order to batch the communication
|
||||||
between server and client. Each call returns a number of documents in a batch
|
between server and client. Each call returns a number of documents in a batch
|
||||||
and an indication, if the current batch has been the final batch. Depending on
|
and an indication if the current batch has been the final batch. Depending on
|
||||||
the query, the total number of documents in the result set might or might not be
|
the query, the total number of documents in the result set might or might not be
|
||||||
known in advance. In order to free server resources the client should delete the
|
known in advance. In order to free server resources the client should delete the
|
||||||
cursor as soon as it is no longer needed.
|
cursor as soon as it is no longer needed.
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
!CHAPTER HTTP Interface for Exporting Documents
|
||||||
|
|
||||||
|
@startDocuBlock JSF_post_api_export
|
|
@ -164,6 +164,7 @@
|
||||||
* [Edges](HttpEdge/README.md)
|
* [Edges](HttpEdge/README.md)
|
||||||
* [Address and ETag](HttpEdge/AddressAndEtag.md)
|
* [Address and ETag](HttpEdge/AddressAndEtag.md)
|
||||||
* [Working with Edges](HttpEdge/WorkingWithEdges.md)
|
* [Working with Edges](HttpEdge/WorkingWithEdges.md)
|
||||||
|
* [Exporting data](HttpExport/README.md)
|
||||||
* [AQL Query Cursors](HttpAqlQueryCursor/README.md)
|
* [AQL Query Cursors](HttpAqlQueryCursor/README.md)
|
||||||
* [Query Results](HttpAqlQueryCursor/QueryResults.md)
|
* [Query Results](HttpAqlQueryCursor/QueryResults.md)
|
||||||
* [Accessing Cursors](HttpAqlQueryCursor/AccessingCursors.md)
|
* [Accessing Cursors](HttpAqlQueryCursor/AccessingCursors.md)
|
||||||
|
|
|
@ -44,11 +44,12 @@ import sys, os, json, string
|
||||||
files = {
|
files = {
|
||||||
"js/actions/api-aqlfunction.js" : "aqlfunction",
|
"js/actions/api-aqlfunction.js" : "aqlfunction",
|
||||||
"arangod/RestHandler/RestBatchHandler.cpp" : "batch",
|
"arangod/RestHandler/RestBatchHandler.cpp" : "batch",
|
||||||
"js/actions/api-collection.js" : "collection",
|
"js/actions/_api/collection/app.js" : "collection",
|
||||||
"js/actions/api-cursor.js" : "cursor",
|
"js/actions/_admin/database/app.js" : "database",
|
||||||
"js/actions/api-database.js" : "database",
|
"arangod/RestHandler/RestCursorHandler.cpp" : "cursor",
|
||||||
"arangod/RestHandler/RestDocumentHandler.cpp" : "document",
|
"arangod/RestHandler/RestDocumentHandler.cpp" : "document",
|
||||||
"arangod/RestHandler/RestEdgeHandler.cpp" : "edge",
|
"arangod/RestHandler/RestEdgeHandler.cpp" : "edge",
|
||||||
|
"arangod/RestHandler/RestExportHandler.cpp" : "export",
|
||||||
"js/actions/api-edges.js" : "edges",
|
"js/actions/api-edges.js" : "edges",
|
||||||
"js/actions/api-endpoint.js" : "endpoint",
|
"js/actions/api-endpoint.js" : "endpoint",
|
||||||
"js/actions/api-explain.js" : "explain",
|
"js/actions/api-explain.js" : "explain",
|
||||||
|
@ -57,7 +58,7 @@ files = {
|
||||||
"js/actions/api-index.js" : "index",
|
"js/actions/api-index.js" : "index",
|
||||||
"lib/HttpServer/AsyncJobManager.h" : "job",
|
"lib/HttpServer/AsyncJobManager.h" : "job",
|
||||||
"lib/Admin/RestAdminLogHandler.cpp" : "log",
|
"lib/Admin/RestAdminLogHandler.cpp" : "log",
|
||||||
"js/actions/api-query.js" : "query",
|
"arangod/RestHandler/RestQueryHandler.cpp" : "query",
|
||||||
"arangod/RestHandler/RestReplicationHandler.cpp" : "replication",
|
"arangod/RestHandler/RestReplicationHandler.cpp" : "replication",
|
||||||
"js/actions/api-simple.js" : "simple",
|
"js/actions/api-simple.js" : "simple",
|
||||||
"js/actions/api-structure.js" : "structure",
|
"js/actions/api-structure.js" : "structure",
|
||||||
|
@ -65,8 +66,9 @@ files = {
|
||||||
"js/actions/api-tasks.js" : "tasks",
|
"js/actions/api-tasks.js" : "tasks",
|
||||||
"js/actions/api-transaction.js" : "transaction",
|
"js/actions/api-transaction.js" : "transaction",
|
||||||
"js/actions/api-traversal.js" : "traversal",
|
"js/actions/api-traversal.js" : "traversal",
|
||||||
"js/actions/api-user.js" : "user",
|
"js/actions/_api/user/app.js" : "user",
|
||||||
"lib/Admin/RestVersionHandler.cpp" : "version"
|
"lib/Admin/RestVersionHandler.cpp" : "version",
|
||||||
|
"js/actions/_admin/wal/app.js" : "wal"
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sys.argv) < 3:
|
if len(sys.argv) < 3:
|
||||||
|
|
|
@ -480,7 +480,6 @@ void Query::registerErrorCustom (int code,
|
||||||
errorMessage.append(": ");
|
errorMessage.append(": ");
|
||||||
errorMessage.append(details);
|
errorMessage.append(details);
|
||||||
|
|
||||||
std::cout << "REGISTER ERROR CUSTOM: " << errorMessage << "\n";
|
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(code, errorMessage);
|
THROW_ARANGO_EXCEPTION_MESSAGE(code, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,7 @@ add_executable(
|
||||||
RestHandler/RestCursorHandler.cpp
|
RestHandler/RestCursorHandler.cpp
|
||||||
RestHandler/RestDocumentHandler.cpp
|
RestHandler/RestDocumentHandler.cpp
|
||||||
RestHandler/RestEdgeHandler.cpp
|
RestHandler/RestEdgeHandler.cpp
|
||||||
|
RestHandler/RestExportHandler.cpp
|
||||||
RestHandler/RestImportHandler.cpp
|
RestHandler/RestImportHandler.cpp
|
||||||
RestHandler/RestPleaseUpgradeHandler.cpp
|
RestHandler/RestPleaseUpgradeHandler.cpp
|
||||||
RestHandler/RestQueryHandler.cpp
|
RestHandler/RestQueryHandler.cpp
|
||||||
|
@ -116,6 +117,7 @@ add_executable(
|
||||||
RestServer/VocbaseContext.cpp
|
RestServer/VocbaseContext.cpp
|
||||||
RestServer/arangod.cpp
|
RestServer/arangod.cpp
|
||||||
SkipLists/skiplistIndex.cpp
|
SkipLists/skiplistIndex.cpp
|
||||||
|
Utils/CollectionExport.cpp
|
||||||
Utils/Cursor.cpp
|
Utils/Cursor.cpp
|
||||||
Utils/CursorRepository.cpp
|
Utils/CursorRepository.cpp
|
||||||
Utils/DocumentHelper.cpp
|
Utils/DocumentHelper.cpp
|
||||||
|
|
|
@ -78,6 +78,7 @@ arangod_libarangod_a_SOURCES = \
|
||||||
arangod/RestHandler/RestCursorHandler.cpp \
|
arangod/RestHandler/RestCursorHandler.cpp \
|
||||||
arangod/RestHandler/RestDocumentHandler.cpp \
|
arangod/RestHandler/RestDocumentHandler.cpp \
|
||||||
arangod/RestHandler/RestEdgeHandler.cpp \
|
arangod/RestHandler/RestEdgeHandler.cpp \
|
||||||
|
arangod/RestHandler/RestExportHandler.cpp \
|
||||||
arangod/RestHandler/RestImportHandler.cpp \
|
arangod/RestHandler/RestImportHandler.cpp \
|
||||||
arangod/RestHandler/RestPleaseUpgradeHandler.cpp \
|
arangod/RestHandler/RestPleaseUpgradeHandler.cpp \
|
||||||
arangod/RestHandler/RestQueryHandler.cpp \
|
arangod/RestHandler/RestQueryHandler.cpp \
|
||||||
|
@ -89,6 +90,7 @@ arangod_libarangod_a_SOURCES = \
|
||||||
arangod/RestServer/VocbaseContext.cpp \
|
arangod/RestServer/VocbaseContext.cpp \
|
||||||
arangod/RestServer/arangod.cpp \
|
arangod/RestServer/arangod.cpp \
|
||||||
arangod/SkipLists/skiplistIndex.cpp \
|
arangod/SkipLists/skiplistIndex.cpp \
|
||||||
|
arangod/Utils/CollectionExport.cpp \
|
||||||
arangod/Utils/Cursor.cpp \
|
arangod/Utils/Cursor.cpp \
|
||||||
arangod/Utils/CursorRepository.cpp \
|
arangod/Utils/CursorRepository.cpp \
|
||||||
arangod/Utils/DocumentHelper.cpp \
|
arangod/Utils/DocumentHelper.cpp \
|
||||||
|
|
|
@ -236,67 +236,6 @@ triagens::basics::Json RestCursorHandler::buildExtra (triagens::aql::QueryResult
|
||||||
return extra;
|
return extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief append the contents of the cursor into the response body
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void RestCursorHandler::dumpCursor (Cursor* cursor) {
|
|
||||||
_response->body().appendText("{\"result\":[");
|
|
||||||
|
|
||||||
size_t const n = cursor->batchSize();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
if (! cursor->hasNext()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i > 0) {
|
|
||||||
_response->body().appendChar(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
auto row = cursor->next();
|
|
||||||
if (row == nullptr) {
|
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
int res = TRI_StringifyJson(_response->body().stringBuffer(), row);
|
|
||||||
|
|
||||||
if (res != TRI_ERROR_NO_ERROR) {
|
|
||||||
THROW_ARANGO_EXCEPTION(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasCount = cursor->hasCount();
|
|
||||||
size_t count = cursor->count();
|
|
||||||
bool hasNext = cursor->hasNext();
|
|
||||||
TRI_json_t* extra = cursor->extra();
|
|
||||||
|
|
||||||
_response->body().appendText("],\"hasMore\":");
|
|
||||||
_response->body().appendText(hasNext ? "true" : "false");
|
|
||||||
|
|
||||||
if (hasNext) {
|
|
||||||
// only return cursor id if there are more documents
|
|
||||||
_response->body().appendText(",\"id\":\"");
|
|
||||||
_response->body().appendInteger(cursor->id());
|
|
||||||
_response->body().appendText("\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasCount) {
|
|
||||||
_response->body().appendText(",\"count\":");
|
|
||||||
_response->body().appendInteger(static_cast<uint64_t>(count));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TRI_IsObjectJson(extra)) {
|
|
||||||
_response->body().appendText(",\"extra\":");
|
|
||||||
TRI_StringifyJson(_response->body().stringBuffer(), extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
_response->body().appendText(",\"error\":false,\"code\":");
|
|
||||||
_response->body().appendInteger(static_cast<uint32_t>(_response->responseCode()));
|
|
||||||
|
|
||||||
_response->body().appendChar('}');
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @startDocuBlock JSF_post_api_cursor
|
/// @startDocuBlock JSF_post_api_cursor
|
||||||
/// @brief create a cursor and return the first results
|
/// @brief create a cursor and return the first results
|
||||||
|
@ -735,13 +674,18 @@ void RestCursorHandler::createCursor () {
|
||||||
double ttl = triagens::basics::JsonHelper::getNumericValue<double>(options.json(), "ttl", 30);
|
double ttl = triagens::basics::JsonHelper::getNumericValue<double>(options.json(), "ttl", 30);
|
||||||
bool count = triagens::basics::JsonHelper::getBooleanValue(options.json(), "count", false);
|
bool count = triagens::basics::JsonHelper::getBooleanValue(options.json(), "count", false);
|
||||||
|
|
||||||
// steal the query JSON, cursor will take owner the ownership
|
// steal the query JSON, cursor will take over the ownership
|
||||||
auto j = queryResult.json;
|
auto j = queryResult.json;
|
||||||
|
triagens::arango::JsonCursor* cursor = cursors->createFromJson(j, batchSize, extra.steal(), ttl, count);
|
||||||
queryResult.json = nullptr;
|
queryResult.json = nullptr;
|
||||||
triagens::arango::Cursor* cursor = cursors->createFromJson(j, batchSize, extra.steal(), ttl, count);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dumpCursor(cursor);
|
_response->body().appendChar('{');
|
||||||
|
cursor->dump(_response->body());
|
||||||
|
_response->body().appendText(",\"error\":false,\"code\":");
|
||||||
|
_response->body().appendInteger(static_cast<uint32_t>(_response->responseCode()));
|
||||||
|
_response->body().appendChar('}');
|
||||||
|
|
||||||
cursors->release(cursor);
|
cursors->release(cursor);
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
@ -889,7 +833,12 @@ void RestCursorHandler::modifyCursor () {
|
||||||
_response = createResponse(HttpResponse::OK);
|
_response = createResponse(HttpResponse::OK);
|
||||||
_response->setContentType("application/json; charset=utf-8");
|
_response->setContentType("application/json; charset=utf-8");
|
||||||
|
|
||||||
dumpCursor(cursor);
|
_response->body().appendChar('{');
|
||||||
|
cursor->dump(_response->body());
|
||||||
|
_response->body().appendText(",\"error\":false,\"code\":");
|
||||||
|
_response->body().appendInteger(static_cast<uint32_t>(_response->responseCode()));
|
||||||
|
_response->body().appendChar('}');
|
||||||
|
|
||||||
cursors->release(cursor);
|
cursors->release(cursor);
|
||||||
}
|
}
|
||||||
catch (triagens::basics::Exception const& ex) {
|
catch (triagens::basics::Exception const& ex) {
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace triagens {
|
||||||
class Cursor;
|
class Cursor;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief document request handler
|
/// @brief cursor request handler
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class RestCursorHandler : public RestVocbaseBaseHandler {
|
class RestCursorHandler : public RestVocbaseBaseHandler {
|
||||||
|
|
|
@ -0,0 +1,294 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief export request 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 Jan Steemann
|
||||||
|
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||||
|
/// @author Copyright 2010-2014, triAGENS GmbH, Cologne, Germany
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "RestExportHandler.h"
|
||||||
|
#include "Basics/Exceptions.h"
|
||||||
|
#include "Basics/json.h"
|
||||||
|
#include "Basics/MutexLocker.h"
|
||||||
|
#include "Utils/CollectionExport.h"
|
||||||
|
#include "Utils/Cursor.h"
|
||||||
|
#include "Utils/CursorRepository.h"
|
||||||
|
#include "Wal/LogfileManager.h"
|
||||||
|
|
||||||
|
using namespace triagens::arango;
|
||||||
|
using namespace triagens::rest;
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- constructors and destructors
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
RestExportHandler::RestExportHandler (HttpRequest* request)
|
||||||
|
: RestVocbaseBaseHandler(request) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- Handler methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// {@inheritDoc}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
HttpHandler::status_t RestExportHandler::execute () {
|
||||||
|
// extract the sub-request type
|
||||||
|
HttpRequest::HttpRequestType type = _request->requestType();
|
||||||
|
|
||||||
|
if (type == HttpRequest::HTTP_REQUEST_POST) {
|
||||||
|
createCursor();
|
||||||
|
return status_t(HANDLER_DONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
|
||||||
|
return status_t(HANDLER_DONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- private methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief build options for the query as JSON
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
triagens::basics::Json RestExportHandler::buildOptions (TRI_json_t const* json) {
|
||||||
|
auto getAttribute = [&json] (char const* name) {
|
||||||
|
return TRI_LookupObjectJson(json, name);
|
||||||
|
};
|
||||||
|
|
||||||
|
triagens::basics::Json options(triagens::basics::Json::Object);
|
||||||
|
|
||||||
|
auto attribute = getAttribute("count");
|
||||||
|
options.set("count", triagens::basics::Json(TRI_IsBooleanJson(attribute) ? attribute->_value._boolean : false));
|
||||||
|
|
||||||
|
attribute = getAttribute("batchSize");
|
||||||
|
options.set("batchSize", triagens::basics::Json(TRI_IsNumberJson(attribute) ? attribute->_value._number : 1000.0));
|
||||||
|
|
||||||
|
if (TRI_IsNumberJson(attribute) && static_cast<size_t>(attribute->_value._number) == 0) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_TYPE_ERROR, "expecting non-zero value for <batchSize>");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! options.has("ttl")) {
|
||||||
|
attribute = getAttribute("ttl");
|
||||||
|
options.set("ttl", triagens::basics::Json(TRI_IsNumberJson(attribute) ? attribute->_value._number : 30.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @startDocuBlock JSF_post_api_export
|
||||||
|
/// @brief export all documents from a collection, using a cursor
|
||||||
|
///
|
||||||
|
/// @RESTHEADER{POST /_api/export, Create export cursor}
|
||||||
|
///
|
||||||
|
/// @RESTBODYPARAM{options,json,optional}
|
||||||
|
/// A JSON object with export options.
|
||||||
|
///
|
||||||
|
/// @RESTQUERYPARAMETERS
|
||||||
|
///
|
||||||
|
/// @RESTQUERYPARAM{collection,string,required}
|
||||||
|
/// The name of the collection to export.
|
||||||
|
///
|
||||||
|
/// @RESTDESCRIPTION
|
||||||
|
/// A call to this method creates a cursor containing all documents in the
|
||||||
|
/// specified collection. In contrast to other data-producing APIs, the internal
|
||||||
|
/// data structures produced by the export API are more lightweight, so it is
|
||||||
|
/// the preferred way to retrieve all documents from a collection.
|
||||||
|
///
|
||||||
|
/// The following attributes can be used inside the JSON object:
|
||||||
|
///
|
||||||
|
/// - *count*: boolean flag that indicates whether the number of documents
|
||||||
|
/// in the result set should be returned in the "count" attribute of the result (optional).
|
||||||
|
/// Calculating the "count" attribute might in the future have a performance
|
||||||
|
/// impact so this option is turned off by default, and "count" is only returned
|
||||||
|
/// when requested.
|
||||||
|
///
|
||||||
|
/// - *batchSize*: maximum number of result documents to be transferred from
|
||||||
|
/// the server to the client in one roundtrip (optional). If this attribute is
|
||||||
|
/// not set, a server-controlled default value will be used.
|
||||||
|
///
|
||||||
|
/// - *ttl*: an optional time-to-live for the cursor (in seconds). The cursor will be
|
||||||
|
/// removed on the server automatically after the specified amount of time. This
|
||||||
|
/// is useful to ensure garbage collection of cursors that are not fully fetched
|
||||||
|
/// by clients. If not set, a server-defined value will be used.
|
||||||
|
///
|
||||||
|
/// If the result set can be created by the server, the server will respond with
|
||||||
|
/// *HTTP 201*. The body of the response will contain a JSON object with the
|
||||||
|
/// result set.
|
||||||
|
///
|
||||||
|
/// The returned JSON object has the following properties:
|
||||||
|
///
|
||||||
|
/// - *error*: boolean flag to indicate that an error occurred (*false*
|
||||||
|
/// in this case)
|
||||||
|
///
|
||||||
|
/// - *code*: the HTTP status code
|
||||||
|
///
|
||||||
|
/// - *result*: an array of result documents (might be empty if the collection was empty)
|
||||||
|
///
|
||||||
|
/// - *hasMore*: a boolean indicator whether there are more results
|
||||||
|
/// available for the cursor on the server
|
||||||
|
///
|
||||||
|
/// - *count*: the total number of result documents available (only
|
||||||
|
/// available if the query was executed with the *count* attribute set)
|
||||||
|
///
|
||||||
|
/// - *id*: id of temporary cursor created on the server (optional, see above)
|
||||||
|
///
|
||||||
|
/// If the JSON representation is malformed or the query specification is
|
||||||
|
/// missing from the request, the server will respond with *HTTP 400*.
|
||||||
|
///
|
||||||
|
/// The body of the response will contain a JSON object with additional error
|
||||||
|
/// details. The object has the following attributes:
|
||||||
|
///
|
||||||
|
/// - *error*: boolean flag to indicate that an error occurred (*true* in this case)
|
||||||
|
///
|
||||||
|
/// - *code*: the HTTP status code
|
||||||
|
///
|
||||||
|
/// - *errorNum*: the server error number
|
||||||
|
///
|
||||||
|
/// - *errorMessage*: a descriptive error message
|
||||||
|
///
|
||||||
|
/// @RESTRETURNCODES
|
||||||
|
///
|
||||||
|
/// @RESTRETURNCODE{201}
|
||||||
|
/// is returned if the result set can be created by the server.
|
||||||
|
///
|
||||||
|
/// @RESTRETURNCODE{400}
|
||||||
|
/// is returned if the JSON representation is malformed or the query specification is
|
||||||
|
/// missing from the request.
|
||||||
|
///
|
||||||
|
/// @RESTRETURNCODE{404}
|
||||||
|
/// The server will respond with *HTTP 404* in case a non-existing collection is
|
||||||
|
/// accessed in the query.
|
||||||
|
///
|
||||||
|
/// @RESTRETURNCODE{405}
|
||||||
|
/// The server will respond with *HTTP 405* if an unsupported HTTP method is used.
|
||||||
|
///
|
||||||
|
/// @endDocuBlock
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void RestExportHandler::createCursor () {
|
||||||
|
std::vector<std::string> const& suffix = _request->suffix();
|
||||||
|
|
||||||
|
if (suffix.size() != 0) {
|
||||||
|
generateError(HttpResponse::BAD,
|
||||||
|
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||||
|
"expecting POST /_api/export");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract the cid
|
||||||
|
bool found;
|
||||||
|
char const* name = _request->value("collection", found);
|
||||||
|
|
||||||
|
if (! found || *name == '\0') {
|
||||||
|
generateError(HttpResponse::BAD,
|
||||||
|
TRI_ERROR_ARANGO_COLLECTION_PARAMETER_MISSING,
|
||||||
|
"'collection' is missing, expecting " + EXPORT_PATH + "?collection=<identifier>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::unique_ptr<TRI_json_t> json(parseJsonBody());
|
||||||
|
|
||||||
|
triagens::basics::Json options;
|
||||||
|
|
||||||
|
if (json.get() != nullptr) {
|
||||||
|
if (! TRI_IsObjectJson(json.get())) {
|
||||||
|
generateError(HttpResponse::BAD, TRI_ERROR_QUERY_EMPTY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
options = buildOptions(json.get());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// create an empty options object
|
||||||
|
options = triagens::basics::Json(triagens::basics::Json::Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool flush = triagens::basics::JsonHelper::getBooleanValue(options.json(), "flush", true);
|
||||||
|
|
||||||
|
if (flush) {
|
||||||
|
// flush the logfiles so the export can fetch all documents
|
||||||
|
int res = triagens::wal::LogfileManager::instance()->flush(true, true, false);
|
||||||
|
|
||||||
|
if (res != TRI_ERROR_NO_ERROR) {
|
||||||
|
THROW_ARANGO_EXCEPTION(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this may throw!
|
||||||
|
std::unique_ptr<CollectionExport> collectionExport(new CollectionExport(_vocbase, name));
|
||||||
|
collectionExport->run();
|
||||||
|
|
||||||
|
{
|
||||||
|
_response = createResponse(HttpResponse::CREATED);
|
||||||
|
_response->setContentType("application/json; charset=utf-8");
|
||||||
|
|
||||||
|
size_t batchSize = triagens::basics::JsonHelper::getNumericValue<size_t>(options.json(), "batchSize", 1000);
|
||||||
|
double ttl = triagens::basics::JsonHelper::getNumericValue<double>(options.json(), "ttl", 30);
|
||||||
|
bool count = triagens::basics::JsonHelper::getBooleanValue(options.json(), "count", false);
|
||||||
|
|
||||||
|
auto cursors = static_cast<triagens::arango::CursorRepository*>(_vocbase->_cursorRepository);
|
||||||
|
TRI_ASSERT(cursors != nullptr);
|
||||||
|
|
||||||
|
// create a cursor from the result
|
||||||
|
triagens::arango::Cursor* cursor = cursors->createFromExport(collectionExport.get(), batchSize, ttl, count);
|
||||||
|
collectionExport.release();
|
||||||
|
|
||||||
|
try {
|
||||||
|
cursor->dump(_response->body());
|
||||||
|
cursors->release(cursor);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
cursors->release(cursor);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (triagens::basics::Exception const& ex) {
|
||||||
|
generateError(HttpResponse::responseCode(ex.code()), ex.code(), ex.what());
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- END-OF-FILE
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// mode: outline-minor
|
||||||
|
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||||
|
// End:
|
|
@ -0,0 +1,113 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief export request 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 Jan Steemann
|
||||||
|
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||||
|
/// @author Copyright 2010-2014, triAGENS GmbH, Cologne, Germany
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef ARANGODB_REST_HANDLER_REST_EXPORT_HANDLER_H
|
||||||
|
#define ARANGODB_REST_HANDLER_REST_EXPORT_HANDLER_H 1
|
||||||
|
|
||||||
|
#include "Basics/Common.h"
|
||||||
|
#include "Basics/Mutex.h"
|
||||||
|
#include "RestHandler/RestVocbaseBaseHandler.h"
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- class RestExportHandler
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace triagens {
|
||||||
|
|
||||||
|
namespace arango {
|
||||||
|
class Cursor;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief document request handler
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class RestExportHandler : public RestVocbaseBaseHandler {
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- constructors and destructors
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
RestExportHandler (rest::HttpRequest*);
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- Handler methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// {@inheritDoc}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
status_t execute () override;
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- private methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief build options for the query as JSON
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
triagens::basics::Json buildOptions (TRI_json_t const*);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create an export cursor and return the first results
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void createCursor ();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- private variables
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- END-OF-FILE
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// mode: outline-minor
|
||||||
|
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||||
|
// End:
|
|
@ -94,7 +94,7 @@ HttpHandler::status_t RestImportHandler::execute () {
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
generateNotImplemented("ILLEGAL " + DOCUMENT_IMPORT_PATH);
|
generateNotImplemented("ILLEGAL " + IMPORT_PATH);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +593,7 @@ bool RestImportHandler::createFromJson (string const& type) {
|
||||||
if (suffix.size() != 0) {
|
if (suffix.size() != 0) {
|
||||||
generateError(HttpResponse::BAD,
|
generateError(HttpResponse::BAD,
|
||||||
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
|
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
|
||||||
"superfluous suffix, expecting " + DOCUMENT_IMPORT_PATH + "?collection=<identifier>");
|
"superfluous suffix, expecting " + IMPORT_PATH + "?collection=<identifier>");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,7 +608,7 @@ bool RestImportHandler::createFromJson (string const& type) {
|
||||||
if (! found || collection.empty()) {
|
if (! found || collection.empty()) {
|
||||||
generateError(HttpResponse::BAD,
|
generateError(HttpResponse::BAD,
|
||||||
TRI_ERROR_ARANGO_COLLECTION_PARAMETER_MISSING,
|
TRI_ERROR_ARANGO_COLLECTION_PARAMETER_MISSING,
|
||||||
"'collection' is missing, expecting " + DOCUMENT_IMPORT_PATH + "?collection=<identifier>");
|
"'collection' is missing, expecting " + IMPORT_PATH + "?collection=<identifier>");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1061,7 +1061,7 @@ bool RestImportHandler::createFromKeyValueList () {
|
||||||
if (suffix.size() != 0) {
|
if (suffix.size() != 0) {
|
||||||
generateError(HttpResponse::BAD,
|
generateError(HttpResponse::BAD,
|
||||||
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
|
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
|
||||||
"superfluous suffix, expecting " + DOCUMENT_IMPORT_PATH + "?collection=<identifier>");
|
"superfluous suffix, expecting " + IMPORT_PATH + "?collection=<identifier>");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,7 +1076,7 @@ bool RestImportHandler::createFromKeyValueList () {
|
||||||
if (! found || collection.empty()) {
|
if (! found || collection.empty()) {
|
||||||
generateError(HttpResponse::BAD,
|
generateError(HttpResponse::BAD,
|
||||||
TRI_ERROR_ARANGO_COLLECTION_PARAMETER_MISSING,
|
TRI_ERROR_ARANGO_COLLECTION_PARAMETER_MISSING,
|
||||||
"'collection' is missing, expecting " + DOCUMENT_IMPORT_PATH + "?collection=<identifier>");
|
"'collection' is missing, expecting " + IMPORT_PATH + "?collection=<identifier>");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,18 +70,24 @@ const string RestVocbaseBaseHandler::CURSOR_PATH = "/_api/cursor";
|
||||||
|
|
||||||
const string RestVocbaseBaseHandler::DOCUMENT_PATH = "/_api/document";
|
const string RestVocbaseBaseHandler::DOCUMENT_PATH = "/_api/document";
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief documents import path
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
const string RestVocbaseBaseHandler::DOCUMENT_IMPORT_PATH = "/_api/import";
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief document path
|
/// @brief document path
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const string RestVocbaseBaseHandler::EDGE_PATH = "/_api/edge";
|
const string RestVocbaseBaseHandler::EDGE_PATH = "/_api/edge";
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief export path
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const string RestVocbaseBaseHandler::EXPORT_PATH = "/_api/export";
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief documents import path
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const string RestVocbaseBaseHandler::IMPORT_PATH = "/_api/import";
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief replication path
|
/// @brief replication path
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -33,14 +33,12 @@
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
|
||||||
#include "Admin/RestBaseHandler.h"
|
#include "Admin/RestBaseHandler.h"
|
||||||
|
|
||||||
#include "Basics/json.h"
|
#include "Basics/json.h"
|
||||||
#include "Basics/logging.h"
|
#include "Basics/logging.h"
|
||||||
#include "Basics/json-utilities.h"
|
#include "Basics/json-utilities.h"
|
||||||
|
|
||||||
#include "Rest/HttpResponse.h"
|
#include "Rest/HttpResponse.h"
|
||||||
#include "Utils/transactions.h"
|
|
||||||
#include "RestServer/VocbaseContext.h"
|
#include "RestServer/VocbaseContext.h"
|
||||||
|
#include "Utils/transactions.h"
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- forward declarations
|
// --SECTION-- forward declarations
|
||||||
|
@ -64,9 +62,10 @@ namespace triagens {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class RestVocbaseBaseHandler : public admin::RestBaseHandler {
|
class RestVocbaseBaseHandler : public admin::RestBaseHandler {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RestVocbaseBaseHandler (RestVocbaseBaseHandler const&);
|
RestVocbaseBaseHandler (RestVocbaseBaseHandler const&) = delete;
|
||||||
RestVocbaseBaseHandler& operator= (RestVocbaseBaseHandler const&);
|
RestVocbaseBaseHandler& operator= (RestVocbaseBaseHandler const&) = delete;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- public constants
|
// --SECTION-- public constants
|
||||||
|
@ -92,18 +91,24 @@ namespace triagens {
|
||||||
|
|
||||||
static const std::string DOCUMENT_PATH;
|
static const std::string DOCUMENT_PATH;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief document import path
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static const std::string DOCUMENT_IMPORT_PATH;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief edge path
|
/// @brief edge path
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static const std::string EDGE_PATH;
|
static const std::string EDGE_PATH;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief document export path
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static const std::string EXPORT_PATH;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief document import path
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static const std::string IMPORT_PATH;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief replication path
|
/// @brief replication path
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "Admin/RestHandlerCreator.h"
|
#include "Admin/RestHandlerCreator.h"
|
||||||
#include "Admin/RestShutdownHandler.h"
|
#include "Admin/RestShutdownHandler.h"
|
||||||
#include "Aql/Query.h"
|
#include "Aql/Query.h"
|
||||||
|
#include "Aql/RestAqlHandler.h"
|
||||||
#include "Basics/FileUtils.h"
|
#include "Basics/FileUtils.h"
|
||||||
#include "Basics/Nonce.h"
|
#include "Basics/Nonce.h"
|
||||||
#include "Basics/ProgramOptions.h"
|
#include "Basics/ProgramOptions.h"
|
||||||
|
@ -49,7 +50,10 @@
|
||||||
#include "Basics/messages.h"
|
#include "Basics/messages.h"
|
||||||
#include "Basics/ThreadPool.h"
|
#include "Basics/ThreadPool.h"
|
||||||
#include "Basics/tri-strings.h"
|
#include "Basics/tri-strings.h"
|
||||||
|
#include "Cluster/ApplicationCluster.h"
|
||||||
|
#include "Cluster/ClusterComm.h"
|
||||||
#include "Cluster/HeartbeatThread.h"
|
#include "Cluster/HeartbeatThread.h"
|
||||||
|
#include "Cluster/RestShardHandler.h"
|
||||||
#include "Dispatcher/ApplicationDispatcher.h"
|
#include "Dispatcher/ApplicationDispatcher.h"
|
||||||
#include "Dispatcher/Dispatcher.h"
|
#include "Dispatcher/Dispatcher.h"
|
||||||
#include "HttpServer/ApplicationEndpointServer.h"
|
#include "HttpServer/ApplicationEndpointServer.h"
|
||||||
|
@ -61,6 +65,7 @@
|
||||||
#include "RestHandler/RestCursorHandler.h"
|
#include "RestHandler/RestCursorHandler.h"
|
||||||
#include "RestHandler/RestDocumentHandler.h"
|
#include "RestHandler/RestDocumentHandler.h"
|
||||||
#include "RestHandler/RestEdgeHandler.h"
|
#include "RestHandler/RestEdgeHandler.h"
|
||||||
|
#include "RestHandler/RestExportHandler.h"
|
||||||
#include "RestHandler/RestImportHandler.h"
|
#include "RestHandler/RestImportHandler.h"
|
||||||
#include "RestHandler/RestPleaseUpgradeHandler.h"
|
#include "RestHandler/RestPleaseUpgradeHandler.h"
|
||||||
#include "RestHandler/RestQueryHandler.h"
|
#include "RestHandler/RestQueryHandler.h"
|
||||||
|
@ -77,10 +82,6 @@
|
||||||
#include "VocBase/auth.h"
|
#include "VocBase/auth.h"
|
||||||
#include "VocBase/server.h"
|
#include "VocBase/server.h"
|
||||||
#include "Wal/LogfileManager.h"
|
#include "Wal/LogfileManager.h"
|
||||||
#include "Cluster/ApplicationCluster.h"
|
|
||||||
#include "Cluster/RestShardHandler.h"
|
|
||||||
#include "Cluster/ClusterComm.h"
|
|
||||||
#include "Aql/RestAqlHandler.h"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace triagens::basics;
|
using namespace triagens::basics;
|
||||||
|
@ -131,8 +132,12 @@ void ArangoServer::defineHandlers (HttpHandlerFactory* factory) {
|
||||||
factory->addPrefixHandler(RestVocbaseBaseHandler::EDGE_PATH,
|
factory->addPrefixHandler(RestVocbaseBaseHandler::EDGE_PATH,
|
||||||
RestHandlerCreator<RestEdgeHandler>::createNoData);
|
RestHandlerCreator<RestEdgeHandler>::createNoData);
|
||||||
|
|
||||||
|
// add "/export" handler
|
||||||
|
factory->addPrefixHandler(RestVocbaseBaseHandler::EXPORT_PATH,
|
||||||
|
RestHandlerCreator<RestExportHandler>::createNoData);
|
||||||
|
|
||||||
// add "/import" handler
|
// add "/import" handler
|
||||||
factory->addPrefixHandler(RestVocbaseBaseHandler::DOCUMENT_IMPORT_PATH,
|
factory->addPrefixHandler(RestVocbaseBaseHandler::IMPORT_PATH,
|
||||||
RestHandlerCreator<RestImportHandler>::createNoData);
|
RestHandlerCreator<RestImportHandler>::createNoData);
|
||||||
|
|
||||||
// add "/replication" handler
|
// add "/replication" handler
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief collection export result container
|
||||||
|
///
|
||||||
|
/// @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 Jan Steemann
|
||||||
|
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||||
|
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "Utils/CollectionExport.h"
|
||||||
|
#include "Basics/JsonHelper.h"
|
||||||
|
#include "Utils/CollectionGuard.h"
|
||||||
|
#include "Utils/CollectionReadLocker.h"
|
||||||
|
#include "VocBase/barrier.h"
|
||||||
|
#include "VocBase/vocbase.h"
|
||||||
|
|
||||||
|
using namespace triagens::arango;
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- class CollectionExport
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- constructors / destructors
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CollectionExport::CollectionExport (TRI_vocbase_t* vocbase,
|
||||||
|
std::string const& name)
|
||||||
|
: _guard(nullptr),
|
||||||
|
_document(nullptr),
|
||||||
|
_barrier(nullptr),
|
||||||
|
_resolver(vocbase),
|
||||||
|
_documents(nullptr) {
|
||||||
|
|
||||||
|
// this may throw
|
||||||
|
_guard = new triagens::arango::CollectionGuard(vocbase, name.c_str(), false);
|
||||||
|
|
||||||
|
_document = _guard->collection()->_collection;
|
||||||
|
TRI_ASSERT(_document != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionExport::~CollectionExport () {
|
||||||
|
delete _documents;
|
||||||
|
|
||||||
|
if (_barrier != nullptr) {
|
||||||
|
TRI_FreeBarrier(_barrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete _guard;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void CollectionExport::run () {
|
||||||
|
// create a fake transaction for iterating over the collection
|
||||||
|
TransactionBase trx(true);
|
||||||
|
|
||||||
|
_barrier = TRI_CreateBarrierElement(&_document->_barrierList);
|
||||||
|
|
||||||
|
if (_barrier == nullptr) {
|
||||||
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TRI_ASSERT(_documents == nullptr);
|
||||||
|
_documents = new std::vector<void const*>();
|
||||||
|
|
||||||
|
// RAII read-lock
|
||||||
|
{
|
||||||
|
triagens::arango::CollectionReadLocker lock(_document, true);
|
||||||
|
|
||||||
|
size_t const n = _document->_primaryIndex._nrUsed;
|
||||||
|
|
||||||
|
_documents->reserve(n);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
auto ptr = _document->_primaryIndex._table[i];
|
||||||
|
|
||||||
|
if (ptr != nullptr) {
|
||||||
|
void const* marker = static_cast<TRI_doc_mptr_t const*>(ptr)->getDataPtr();
|
||||||
|
|
||||||
|
// it is only safe to use the markers from the datafiles, not the WAL
|
||||||
|
if (! TRI_IsWalDataMarkerDatafile(marker)) {
|
||||||
|
_documents->emplace_back(marker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- END-OF-FILE
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// mode: outline-minor
|
||||||
|
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||||
|
// End:
|
|
@ -0,0 +1,97 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief collection export result container
|
||||||
|
///
|
||||||
|
/// @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 Jan Steemann
|
||||||
|
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||||
|
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef ARANGODB_ARANGO_COLLECTION_EXPORT_H
|
||||||
|
#define ARANGODB_ARANGO_COLLECTION_EXPORT_H 1
|
||||||
|
|
||||||
|
#include "Basics/Common.h"
|
||||||
|
#include "Utils/CollectionNameResolver.h"
|
||||||
|
#include "VocBase/voc-types.h"
|
||||||
|
|
||||||
|
struct TRI_barrier_s;
|
||||||
|
struct TRI_document_collection_t;
|
||||||
|
struct TRI_vocbase_s;
|
||||||
|
|
||||||
|
namespace triagens {
|
||||||
|
namespace arango {
|
||||||
|
|
||||||
|
class CollectionGuard;
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- class CollectionExport
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CollectionExport {
|
||||||
|
|
||||||
|
friend class ExportCursor;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CollectionExport (CollectionExport const&) = delete;
|
||||||
|
CollectionExport& operator= (CollectionExport const&) = delete;
|
||||||
|
|
||||||
|
CollectionExport (TRI_vocbase_s*,
|
||||||
|
std::string const&);
|
||||||
|
|
||||||
|
~CollectionExport ();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void run ();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- private variables
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
triagens::arango::CollectionGuard* _guard;
|
||||||
|
struct TRI_document_collection_t* _document;
|
||||||
|
struct TRI_barrier_s* _barrier;
|
||||||
|
triagens::arango::CollectionNameResolver _resolver;
|
||||||
|
std::vector<void const*>* _documents;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- END-OF-FILE
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// mode: outline-minor
|
||||||
|
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||||
|
// End:
|
|
@ -28,8 +28,12 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "Utils/Cursor.h"
|
#include "Utils/Cursor.h"
|
||||||
#include "Basics/json.h"
|
#include "Basics/JsonHelper.h"
|
||||||
|
#include "ShapedJson/shaped-json.h"
|
||||||
|
#include "Utils/CollectionExport.h"
|
||||||
|
#include "VocBase/document-collection.h"
|
||||||
#include "VocBase/vocbase.h"
|
#include "VocBase/vocbase.h"
|
||||||
|
#include "VocBase/voc-shaper.h"
|
||||||
|
|
||||||
using namespace triagens::arango;
|
using namespace triagens::arango;
|
||||||
|
|
||||||
|
@ -88,9 +92,15 @@ JsonCursor::JsonCursor (TRI_vocbase_t* vocbase,
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonCursor::~JsonCursor () {
|
JsonCursor::~JsonCursor () {
|
||||||
|
freeJson();
|
||||||
|
|
||||||
TRI_ReleaseVocBase(_vocbase);
|
TRI_ReleaseVocBase(_vocbase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief check whether the cursor contains more data
|
/// @brief check whether the cursor contains more data
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -123,6 +133,59 @@ size_t JsonCursor::count () const {
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief dump the cursor contents into a string buffer
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void JsonCursor::dump (triagens::basics::StringBuffer& buffer) {
|
||||||
|
buffer.appendText("\"result\":[");
|
||||||
|
|
||||||
|
size_t const n = batchSize();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
if (! hasNext()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
buffer.appendChar(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
auto row = next();
|
||||||
|
if (row == nullptr) {
|
||||||
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = TRI_StringifyJson(buffer.stringBuffer(), row);
|
||||||
|
|
||||||
|
if (res != TRI_ERROR_NO_ERROR) {
|
||||||
|
THROW_ARANGO_EXCEPTION(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.appendText("],\"hasMore\":");
|
||||||
|
buffer.appendText(hasNext() ? "true" : "false");
|
||||||
|
|
||||||
|
if (hasNext()) {
|
||||||
|
// only return cursor id if there are more documents
|
||||||
|
buffer.appendText(",\"id\":\"");
|
||||||
|
buffer.appendInteger(id());
|
||||||
|
buffer.appendText("\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCount()) {
|
||||||
|
buffer.appendText(",\"count\":");
|
||||||
|
buffer.appendInteger(static_cast<uint64_t>(count()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_json_t const* extraJson = extra();
|
||||||
|
|
||||||
|
if (TRI_IsObjectJson(extraJson)) {
|
||||||
|
buffer.appendText(",\"extra\":");
|
||||||
|
TRI_StringifyJson(buffer.stringBuffer(), extraJson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private functions
|
// --SECTION-- private functions
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -140,6 +203,133 @@ void JsonCursor::freeJson () {
|
||||||
_isDeleted = true;
|
_isDeleted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- class ExportCursor
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- constructors / destructors
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ExportCursor::ExportCursor (TRI_vocbase_t* vocbase,
|
||||||
|
CursorId id,
|
||||||
|
triagens::arango::CollectionExport* ex,
|
||||||
|
size_t batchSize,
|
||||||
|
double ttl,
|
||||||
|
bool hasCount)
|
||||||
|
: Cursor(id, batchSize, nullptr, ttl, hasCount),
|
||||||
|
_vocbase(vocbase),
|
||||||
|
_ex(ex) {
|
||||||
|
|
||||||
|
TRI_UseVocBase(vocbase);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportCursor::~ExportCursor () {
|
||||||
|
TRI_ReleaseVocBase(_vocbase);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief check whether the cursor contains more data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool ExportCursor::hasNext () {
|
||||||
|
return (_position < _ex->_documents->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief return the next element (not implemented)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
TRI_json_t* ExportCursor::next () {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief return the cursor size
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
size_t ExportCursor::count () const {
|
||||||
|
return _ex->_documents->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief dump the cursor contents into a string buffer
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void ExportCursor::dump (triagens::basics::StringBuffer& buffer) {
|
||||||
|
TRI_shaper_t* shaper = _ex->_document->getShaper();
|
||||||
|
|
||||||
|
buffer.appendText("\"result\":[");
|
||||||
|
|
||||||
|
size_t const n = batchSize();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
if (! hasNext()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
buffer.appendChar(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
auto marker = static_cast<TRI_df_marker_t const*>(_ex->_documents->at(_position++));
|
||||||
|
|
||||||
|
TRI_shaped_json_t shaped;
|
||||||
|
TRI_EXTRACT_SHAPED_JSON_MARKER(shaped, marker);
|
||||||
|
triagens::basics::Json json(shaper->_memoryZone, TRI_JsonShapedJson(shaper, &shaped));
|
||||||
|
|
||||||
|
// append the internal attributes
|
||||||
|
|
||||||
|
// _id, _key, _rev
|
||||||
|
char const* key = TRI_EXTRACT_MARKER_KEY(marker);
|
||||||
|
std::string id(_ex->_resolver.getCollectionName(_ex->_document->_info._cid));
|
||||||
|
id.push_back('/');
|
||||||
|
id.append(key);
|
||||||
|
json(TRI_VOC_ATTRIBUTE_ID, triagens::basics::Json(id));
|
||||||
|
json(TRI_VOC_ATTRIBUTE_REV, triagens::basics::Json(std::to_string(TRI_EXTRACT_MARKER_RID(marker))));
|
||||||
|
json(TRI_VOC_ATTRIBUTE_KEY, triagens::basics::Json(key));
|
||||||
|
|
||||||
|
if (TRI_IS_EDGE_MARKER(marker)) {
|
||||||
|
// _from
|
||||||
|
std::string from(_ex->_resolver.getCollectionNameCluster(TRI_EXTRACT_MARKER_FROM_CID(marker)));
|
||||||
|
from.push_back('/');
|
||||||
|
from.append(TRI_EXTRACT_MARKER_FROM_KEY(marker));
|
||||||
|
json(TRI_VOC_ATTRIBUTE_FROM, triagens::basics::Json(from));
|
||||||
|
|
||||||
|
// _to
|
||||||
|
std::string to(_ex->_resolver.getCollectionNameCluster(TRI_EXTRACT_MARKER_TO_CID(marker)));
|
||||||
|
to.push_back('/');
|
||||||
|
to.append(TRI_EXTRACT_MARKER_TO_KEY(marker));
|
||||||
|
json(TRI_VOC_ATTRIBUTE_TO, triagens::basics::Json(to));
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = TRI_StringifyJson(buffer.stringBuffer(), json.json());
|
||||||
|
|
||||||
|
if (res != TRI_ERROR_NO_ERROR) {
|
||||||
|
THROW_ARANGO_EXCEPTION(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.appendText("],\"hasMore\":");
|
||||||
|
buffer.appendText(hasNext() ? "true" : "false");
|
||||||
|
|
||||||
|
if (hasNext()) {
|
||||||
|
// only return cursor id if there are more documents
|
||||||
|
buffer.appendText(",\"id\":\"");
|
||||||
|
buffer.appendInteger(id());
|
||||||
|
buffer.appendText("\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCount()) {
|
||||||
|
buffer.appendText(",\"count\":");
|
||||||
|
buffer.appendInteger(static_cast<uint64_t>(count()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- END-OF-FILE
|
// --SECTION-- END-OF-FILE
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#define ARANGODB_ARANGO_CURSOR_H 1
|
#define ARANGODB_ARANGO_CURSOR_H 1
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
#include "Basics/StringBuffer.h"
|
||||||
#include "VocBase/voc-types.h"
|
#include "VocBase/voc-types.h"
|
||||||
|
|
||||||
struct TRI_json_t;
|
struct TRI_json_t;
|
||||||
|
@ -39,6 +40,8 @@ struct TRI_vocbase_s;
|
||||||
namespace triagens {
|
namespace triagens {
|
||||||
namespace arango {
|
namespace arango {
|
||||||
|
|
||||||
|
class CollectionExport;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- class Cursor
|
// --SECTION-- class Cursor
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -120,16 +123,10 @@ namespace triagens {
|
||||||
|
|
||||||
virtual size_t count () const = 0;
|
virtual size_t count () const = 0;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
virtual void dump (triagens::basics::StringBuffer&) = 0;
|
||||||
// --SECTION-- private functions
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void freeJson ();
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private variables
|
// --SECTION-- protected variables
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -174,6 +171,8 @@ namespace triagens {
|
||||||
|
|
||||||
size_t count () const override final;
|
size_t count () const override final;
|
||||||
|
|
||||||
|
void dump (triagens::basics::StringBuffer&) override final;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private functions
|
// --SECTION-- private functions
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -192,6 +191,47 @@ namespace triagens {
|
||||||
struct TRI_json_t* _json;
|
struct TRI_json_t* _json;
|
||||||
size_t const _size;
|
size_t const _size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- class ExportCursor
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ExportCursor : public Cursor {
|
||||||
|
public:
|
||||||
|
|
||||||
|
ExportCursor (struct TRI_vocbase_s*,
|
||||||
|
CursorId,
|
||||||
|
triagens::arango::CollectionExport*,
|
||||||
|
size_t,
|
||||||
|
double,
|
||||||
|
bool);
|
||||||
|
|
||||||
|
~ExportCursor ();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool hasNext () override final;
|
||||||
|
|
||||||
|
struct TRI_json_t* next () override final;
|
||||||
|
|
||||||
|
size_t count () const override final;
|
||||||
|
|
||||||
|
void dump (triagens::basics::StringBuffer&) override final;
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- private variables
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct TRI_vocbase_s* _vocbase;
|
||||||
|
triagens::arango::CollectionExport* _ex;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "Utils/CursorRepository.h"
|
#include "Utils/CursorRepository.h"
|
||||||
#include "Basics/json.h"
|
#include "Basics/json.h"
|
||||||
#include "Basics/MutexLocker.h"
|
#include "Basics/MutexLocker.h"
|
||||||
|
#include "Utils/CollectionExport.h"
|
||||||
#include "VocBase/server.h"
|
#include "VocBase/server.h"
|
||||||
#include "VocBase/vocbase.h"
|
#include "VocBase/vocbase.h"
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ CursorRepository::~CursorRepository () {
|
||||||
/// the cursor will take ownership of both json and extra
|
/// the cursor will take ownership of both json and extra
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Cursor* CursorRepository::createFromJson (TRI_json_t* json,
|
JsonCursor* CursorRepository::createFromJson (TRI_json_t* json,
|
||||||
size_t batchSize,
|
size_t batchSize,
|
||||||
TRI_json_t* extra,
|
TRI_json_t* extra,
|
||||||
double ttl,
|
double ttl,
|
||||||
|
@ -89,7 +90,7 @@ Cursor* CursorRepository::createFromJson (TRI_json_t* json,
|
||||||
TRI_ASSERT(json != nullptr);
|
TRI_ASSERT(json != nullptr);
|
||||||
|
|
||||||
CursorId const id = TRI_NewTickServer();
|
CursorId const id = TRI_NewTickServer();
|
||||||
triagens::arango::Cursor* cursor = nullptr;
|
triagens::arango::JsonCursor* cursor = nullptr;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = new triagens::arango::JsonCursor(_vocbase, id, json, batchSize, extra, ttl, count);
|
cursor = new triagens::arango::JsonCursor(_vocbase, id, json, batchSize, extra, ttl, count);
|
||||||
|
@ -115,6 +116,32 @@ Cursor* CursorRepository::createFromJson (TRI_json_t* json,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief creates a cursor and stores it in the registry
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ExportCursor* CursorRepository::createFromExport (triagens::arango::CollectionExport* ex,
|
||||||
|
size_t batchSize,
|
||||||
|
double ttl,
|
||||||
|
bool count) {
|
||||||
|
TRI_ASSERT(ex != nullptr);
|
||||||
|
|
||||||
|
CursorId const id = TRI_NewTickServer();
|
||||||
|
triagens::arango::ExportCursor* cursor = new triagens::arango::ExportCursor(_vocbase, id, ex, batchSize, ttl, count);
|
||||||
|
|
||||||
|
cursor->use();
|
||||||
|
|
||||||
|
try {
|
||||||
|
MUTEX_LOCKER(_lock);
|
||||||
|
_cursors.emplace(std::make_pair(id, cursor));
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
delete cursor;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief remove a cursor by id
|
/// @brief remove a cursor by id
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -227,7 +254,6 @@ bool CursorRepository::garbageCollect (bool force) {
|
||||||
|
|
||||||
{
|
{
|
||||||
MUTEX_LOCKER(_lock);
|
MUTEX_LOCKER(_lock);
|
||||||
std::cout << "CLEANUP COUNT: " << _cursors.size() << "\n";
|
|
||||||
|
|
||||||
for (auto it = _cursors.begin(); it != _cursors.end(); /* no hoisting */) {
|
for (auto it = _cursors.begin(); it != _cursors.end(); /* no hoisting */) {
|
||||||
auto cursor = (*it).second;
|
auto cursor = (*it).second;
|
||||||
|
|
|
@ -41,6 +41,8 @@ struct TRI_vocbase_s;
|
||||||
namespace triagens {
|
namespace triagens {
|
||||||
namespace arango {
|
namespace arango {
|
||||||
|
|
||||||
|
class CollectionExport;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- class CursorRepository
|
// --SECTION-- class CursorRepository
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -78,12 +80,21 @@ namespace triagens {
|
||||||
/// the cursor will take ownership of both json and extra
|
/// the cursor will take ownership of both json and extra
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Cursor* createFromJson (struct TRI_json_t*,
|
JsonCursor* createFromJson (struct TRI_json_t*,
|
||||||
size_t,
|
size_t,
|
||||||
struct TRI_json_t*,
|
struct TRI_json_t*,
|
||||||
double,
|
double,
|
||||||
bool);
|
bool);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief creates a cursor and stores it in the registry
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ExportCursor* createFromExport (triagens::arango::CollectionExport*,
|
||||||
|
size_t,
|
||||||
|
double,
|
||||||
|
bool);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief remove a cursor by id
|
/// @brief remove a cursor by id
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1472,6 +1472,10 @@ void TRI_DestroyInitialVocBase (TRI_vocbase_t* vocbase) {
|
||||||
|
|
||||||
TRI_DestroySpin(&vocbase->_usage._lock);
|
TRI_DestroySpin(&vocbase->_usage._lock);
|
||||||
|
|
||||||
|
if (vocbase->_cursorRepository != nullptr) {
|
||||||
|
delete static_cast<triagens::arango::CursorRepository*>(vocbase->_cursorRepository);
|
||||||
|
}
|
||||||
|
|
||||||
if (vocbase->_queries != nullptr) {
|
if (vocbase->_queries != nullptr) {
|
||||||
delete static_cast<triagens::aql::QueryList*>(vocbase->_queries);
|
delete static_cast<triagens::aql::QueryList*>(vocbase->_queries);
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,20 +249,20 @@ function ahuacatlModifySuite () {
|
||||||
assertQueryError(errors.ERROR_QUERY_PARSE.code, "FOR d IN @@cn REMOVE d IN @@cn OPTIONS 'foo'", { "@cn": cn1 });
|
assertQueryError(errors.ERROR_QUERY_PARSE.code, "FOR d IN @@cn REMOVE d IN @@cn OPTIONS 'foo'", { "@cn": cn1 });
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief test usage of OLD
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
testInvalidUsageOfNew : function () {
|
|
||||||
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, "REMOVE 'abc' IN @@cn LET removed = NEW RETURN removed", { "@cn": cn1 });
|
|
||||||
},
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief test usage of NEW
|
/// @brief test usage of NEW
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testInvalidUsageOfNew : function () {
|
||||||
|
assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "REMOVE 'abc' IN @@cn LET removed = NEW RETURN removed", { "@cn": cn1 });
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test usage of OLD
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testInvalidUsageOfOld : function () {
|
testInvalidUsageOfOld : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, "INSERT { } IN @@cn LET inserted = OLD RETURN inserted", { "@cn": cn1 });
|
assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "INSERT { } IN @@cn LET inserted = OLD RETURN inserted", { "@cn": cn1 });
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -270,7 +270,7 @@ function ahuacatlModifySuite () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testInvalidVariableNames1 : function () {
|
testInvalidVariableNames1 : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, "REMOVE 'abc' IN @@cn LET removed1 = OLD RETURN removed2", { "@cn": cn1 });
|
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, "REMOVE 'abc' IN @@cn LET removed1 = OLD RETURN @@cn", { "@cn": cn1 });
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -278,7 +278,23 @@ function ahuacatlModifySuite () {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
testInvalidVariableNames2 : function () {
|
testInvalidVariableNames2 : function () {
|
||||||
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, "UPDATE 'abc' WITH { } IN @@cn LET updated = NEW RETURN foo", { "@cn": cn1 });
|
assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "REMOVE 'abc' IN @@cn LET removed1 = OLD RETURN removed2", { "@cn": cn1 });
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test variable names
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testInvalidVariableNames3 : function () {
|
||||||
|
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, "UPDATE 'abc' WITH { } IN @@cn LET updated = NEW RETURN @@cn", { "@cn": cn1 });
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test variable names
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testInvalidVariableNames4 : function () {
|
||||||
|
assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "UPDATE 'abc' WITH { } IN @@cn LET updated = NEW RETURN foo", { "@cn": cn1 });
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in New Issue