1
0
Fork 0

Merge branch 'engine-vs-velocystream' of https://github.com/arangodb/arangodb into generic-col-types

This commit is contained in:
jsteemann 2016-09-05 11:51:09 +02:00
commit df808cd665
21 changed files with 465 additions and 315 deletions

1
.gitignore vendored
View File

@ -26,6 +26,7 @@ core.*
Thumbs.db
compile_commands.json
instanceinfo.json
testresult.json
botschaft.txt
testsStarted

View File

@ -21,9 +21,9 @@
/// @author Kaveh Vahedipour
////////////////////////////////////////////////////////////////////////////////
#include "RestAgencyPrivHandler.h"
#include "Rest/HttpRequest.h"
#include "Rest/Version.h"
#include "RestAgencyPrivHandler.h"
#include "Agency/Agent.h"
@ -58,13 +58,14 @@ inline RestHandler::status RestAgencyPrivHandler::reportErrorEmptyRequest() {
}
inline RestHandler::status RestAgencyPrivHandler::reportTooManySuffices() {
LOG_TOPIC(WARN, Logger::AGENCY) << "Agency handles a single suffix: vote, log or configure";
LOG_TOPIC(WARN, Logger::AGENCY)
<< "Agency handles a single suffix: vote, log or configure";
generateError(rest::ResponseCode::NOT_FOUND, 404);
return RestHandler::status::DONE;
}
inline RestHandler::status RestAgencyPrivHandler::reportBadQuery(
std::string const& message) {
std::string const& message) {
generateError(rest::ResponseCode::BAD, 400, message);
return RestHandler::status::DONE;
}
@ -137,9 +138,9 @@ RestHandler::status RestAgencyPrivHandler::execute() {
query_t query = _request->toVelocyPackBuilderPtr(&options);
try {
query_t ret = _agent->gossip(query);
result.add("id",ret->slice().get("id"));
result.add("endpoint",ret->slice().get("endpoint"));
result.add("pool",ret->slice().get("pool"));
result.add("id", ret->slice().get("id"));
result.add("endpoint", ret->slice().get("endpoint"));
result.add("pool", ret->slice().get("pool"));
} catch (std::exception const& e) {
return reportBadQuery(e.what());
}
@ -148,7 +149,8 @@ RestHandler::status RestAgencyPrivHandler::execute() {
return reportMethodNotAllowed();
}
if (_agent->leaderID() != NO_LEADER) {
result.add("active", _agent->config().activeAgentsToBuilder()->slice());
result.add("active",
_agent->config().activeAgentsToBuilder()->slice());
}
} else if (_request->suffix()[0] == "inform") {
arangodb::velocypack::Options options;
@ -159,8 +161,7 @@ RestHandler::status RestAgencyPrivHandler::execute() {
return reportBadQuery(e.what());
}
} else {
generateError(rest::ResponseCode::NOT_FOUND,
404); // nothing else here
generateError(rest::ResponseCode::NOT_FOUND, 404); // nothing else here
return RestHandler::status::DONE;
}
}

View File

@ -158,6 +158,7 @@ class GeneralCommTask : public SocketTask {
void processResponse(GeneralResponse*);
public:
virtual void handleSimpleError(rest::ResponseCode, uint64_t messagid) = 0;
virtual void handleSimpleError(rest::ResponseCode, int code,
std::string const& errorMessage,

View File

@ -192,6 +192,7 @@ bool GeneralServer::handleRequest(GeneralCommTask* task,
if (res != TRI_ERROR_NO_ERROR) {
task->handleSimpleError(rest::ResponseCode::SERVICE_UNAVAILABLE, res, TRI_errno_string(res), messageId);
return true;
}

View File

@ -60,7 +60,8 @@ HttpCommTask::HttpCommTask(GeneralServer* server, TRI_socket_t sock,
_sinceCompactification(0),
_originalBodyLength(0) { // TODO(fc) remove
_protocol = "http";
connectionStatisticsAgentSetHttp(); // old
connectionStatisticsAgentSetHttp(); // this agent is inherited form
// sockettask or task
_agents.emplace(std::make_pair(1UL, RequestStatisticsAgent(true)));
}
@ -588,6 +589,7 @@ void HttpCommTask::processRequest(std::unique_ptr<HttpRequest> request) {
std::unique_ptr<GeneralResponse> response(
new HttpResponse(rest::ResponseCode::SERVER_ERROR));
response->setContentType(request->contentTypeResponse());
response->setContentTypeRequested(request->contentTypeResponse());
executeRequest(std::move(request), std::move(response));
}

View File

@ -176,7 +176,9 @@ void VppCommTask::addResponse(VppResponse* response) {
std::vector<VPackSlice> slices;
slices.push_back(response_message._header);
slices.push_back(response_message._payload);
if (response->generateBody()) {
slices.push_back(response_message._payload);
}
LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "VppCommTask: "
<< "created response:";
@ -482,6 +484,7 @@ bool VppCommTask::processRead() {
std::unique_ptr<VppResponse> response(new VppResponse(
rest::ResponseCode::SERVER_ERROR, chunkHeader._messageID));
response->setContentTypeRequested(request->contentTypeResponse());
executeRequest(std::move(request), std::move(response));
}
}

View File

@ -51,31 +51,34 @@ void RestBaseHandler::handleError(Exception const& ex) {
/// @brief generates a result from VelocyPack
////////////////////////////////////////////////////////////////////////////////
template<typename Payload>
void RestBaseHandler::generateResult(rest::ResponseCode code,
VPackSlice const& slice) {
Payload&& payload) {
resetResponse(code);
VPackOptions options(VPackOptions::Defaults);
options.escapeUnicode = true;
writeResult(slice, options);
writeResult(std::forward<Payload>(payload), options);
}
template<typename Payload>
void RestBaseHandler::generateResult(rest::ResponseCode code,
VPackSlice const& slice,
Payload&& payload,
VPackOptions const* options) {
resetResponse(code);
VPackOptions tmpoptions(*options);
tmpoptions.escapeUnicode = true;
writeResult(slice, tmpoptions);
writeResult(std::forward<Payload>(payload), tmpoptions);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates a result from VelocyPack
////////////////////////////////////////////////////////////////////////////////
template<typename Payload>
void RestBaseHandler::generateResult(
rest::ResponseCode code, VPackSlice const& slice,
rest::ResponseCode code, Payload&& payload,
std::shared_ptr<TransactionContext> context) {
resetResponse(code);
writeResult(slice, *(context->getVPackOptionsForDump()));
writeResult(std::forward<Payload>(payload), *(context->getVPackOptionsForDump()));
}
////////////////////////////////////////////////////////////////////////////////
@ -100,7 +103,8 @@ void RestBaseHandler::generateError(rest::ResponseCode code, int errorCode,
std::string const& message) {
resetResponse(code);
VPackBuilder builder;
VPackBuffer<uint8_t> buffer;
VPackBuilder builder(buffer);
try {
builder.add(VPackValue(VPackValueType::Object));
builder.add("error", VPackValue(true));
@ -116,7 +120,7 @@ void RestBaseHandler::generateError(rest::ResponseCode code, int errorCode,
VPackOptions options(VPackOptions::Defaults);
options.escapeUnicode = true;
writeResult(builder.slice(), options);
writeResult(std::move(buffer), options);
} catch (...) {
// Building the error response failed
}
@ -142,14 +146,15 @@ void RestBaseHandler::generateCanceled() {
/// @brief writes volocypack or json to response
//////////////////////////////////////////////////////////////////////////////
void RestBaseHandler::writeResult(arangodb::velocypack::Slice const& slice,
template<typename Payload>
void RestBaseHandler::writeResult(Payload&& payload,
VPackOptions const& options) {
try {
TRI_ASSERT(options.escapeUnicode);
if (_request != nullptr) {
_response->setContentType(_request->contentTypeResponse());
}
_response->setPayload(slice, true, options);
_response->setPayload(std::forward<Payload>(payload), true, options);
} catch (std::exception const& ex) {
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL,
ex.what());
@ -158,3 +163,21 @@ void RestBaseHandler::writeResult(arangodb::velocypack::Slice const& slice,
"cannot generate output");
}
}
//TODO -- rather move code to header (slower linking) or remove templates
template void RestBaseHandler::generateResult<VPackBuffer<uint8_t>>(rest::ResponseCode, VPackBuffer<uint8_t>&&);
template void RestBaseHandler::generateResult<VPackSlice>(rest::ResponseCode, VPackSlice&&);
template void RestBaseHandler::generateResult<VPackSlice&>(rest::ResponseCode, VPackSlice&);
template void RestBaseHandler::generateResult<VPackBuffer<uint8_t>>(rest::ResponseCode, VPackBuffer<uint8_t>&&, VPackOptions const*);
template void RestBaseHandler::generateResult<VPackSlice>(rest::ResponseCode, VPackSlice&&, VPackOptions const*);
template void RestBaseHandler::generateResult<VPackSlice&>(rest::ResponseCode, VPackSlice&, VPackOptions const*);
template void RestBaseHandler::generateResult<VPackBuffer<uint8_t>>(rest::ResponseCode, VPackBuffer<uint8_t>&&, std::shared_ptr<arangodb::TransactionContext>);
template void RestBaseHandler::generateResult<VPackSlice>(rest::ResponseCode, VPackSlice&&, std::shared_ptr<arangodb::TransactionContext>);
template void RestBaseHandler::generateResult<VPackSlice&>(rest::ResponseCode, VPackSlice&, std::shared_ptr<arangodb::TransactionContext>);
template void RestBaseHandler::writeResult<VPackBuffer<uint8_t>>(VPackBuffer<uint8_t>&& payload, VPackOptions const&);
template void RestBaseHandler::writeResult<VPackSlice>(VPackSlice&& payload, VPackOptions const&);
template void RestBaseHandler::writeResult<VPackSlice&>(VPackSlice& payload, VPackOptions const&);
template void RestBaseHandler::writeResult<VPackSlice const&>(VPackSlice const& payload, VPackOptions const&);

View File

@ -44,17 +44,16 @@ class RestBaseHandler : public rest::RestHandler {
public:
// generates a result from VelocyPack
void generateResult(rest::ResponseCode,
arangodb::velocypack::Slice const& slice);
template <typename Payload>
void generateResult(rest::ResponseCode, Payload&&);
// generates a result from VelocyPack
void generateResult(rest::ResponseCode,
arangodb::velocypack::Slice const& slice,
VPackOptions const*);
template <typename Payload>
void generateResult(rest::ResponseCode, Payload&&, VPackOptions const*);
// generates a result from VelocyPack
void generateResult(rest::ResponseCode,
arangodb::velocypack::Slice const& slice,
template <typename Payload>
void generateResult(rest::ResponseCode, Payload&&,
std::shared_ptr<arangodb::TransactionContext> context);
// generates an error
@ -70,9 +69,8 @@ class RestBaseHandler : public rest::RestHandler {
void generateCanceled();
protected:
// write result back to client
void writeResult(arangodb::velocypack::Slice const& slice,
arangodb::velocypack::Options const& options);
template <typename Payload>
void writeResult(Payload&&, arangodb::velocypack::Options const& options);
};
}

View File

@ -48,6 +48,26 @@ RestBatchHandler::~RestBatchHandler() {}
////////////////////////////////////////////////////////////////////////////////
RestHandler::status RestBatchHandler::execute() {
switch (_response->transportType()) {
case Endpoint::TransportType::HTTP: {
return executeHttp();
}
case Endpoint::TransportType::VPP: {
return executeVpp();
}
}
// should never get here
TRI_ASSERT(false);
return RestHandler::status::FAILED;
}
RestHandler::status RestBatchHandler::executeVpp() {
generateError(rest::ResponseCode::METHOD_NOT_ALLOWED, TRI_ERROR_NO_ERROR,
"The RestBatchHandler is not supported for this protocol!");
return status::DONE;
}
RestHandler::status RestBatchHandler::executeHttp() {
HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(_response.get());
if (httpResponse == nullptr) {
@ -66,8 +86,7 @@ RestHandler::status RestBatchHandler::execute() {
// extract the request type
auto const type = _request->requestType();
if (type != rest::RequestType::POST &&
type != rest::RequestType::PUT) {
if (type != rest::RequestType::POST && type != rest::RequestType::PUT) {
generateError(rest::ResponseCode::METHOD_NOT_ALLOWED,
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
return status::DONE;
@ -77,8 +96,7 @@ RestHandler::status RestBatchHandler::execute() {
// invalid content-type or boundary sent
if (!getBoundary(&boundary)) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid content-type or boundary received");
return status::FAILED;
}
@ -110,8 +128,7 @@ RestHandler::status RestBatchHandler::execute() {
// get the next part from the multipart message
if (!extractPart(&helper)) {
// error
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid multipart message received");
LOG(WARN) << "received a corrupted multipart message";

View File

@ -64,6 +64,8 @@ class RestBatchHandler : public RestVocbaseBaseHandler {
RestHandler::status execute() override;
private:
RestHandler::status executeHttp();
RestHandler::status executeVpp();
// extract the boundary from the body of a multipart message
bool getBoundaryBody(std::string*);

View File

@ -92,15 +92,32 @@ RestHandler::status RestImportHandler::execute() {
// extract the import type
std::string const& documentType = _request->value("type", found);
if (found && (documentType == "documents" || documentType == "array" ||
documentType == "list" || documentType == "auto")) {
createFromJson(documentType);
} else {
// CSV
createFromKeyValueList();
/////////////////////////////////////////////////////////////////////////////////
switch (_response->transportType()) {
case Endpoint::TransportType::HTTP: {
if (found &&
(documentType == "documents" || documentType == "array" ||
documentType == "list" || documentType == "auto")) {
createFromJson(documentType);
} else {
// CSV
createFromKeyValueList();
}
} break;
/////////////////////////////////////////////////////////////////////////////////
case Endpoint::TransportType::VPP: {
if (found &&
(documentType == "documents" || documentType == "array" ||
documentType == "list" || documentType == "auto")) {
createFromVPack(documentType);
} else {
generateNotImplemented("ILLEGAL " + IMPORT_PATH);
createFromKeyValueListVPack();
}
} break;
}
break;
}
/////////////////////////////////////////////////////////////////////////////////
} break;
default:
generateNotImplemented("ILLEGAL " + IMPORT_PATH);
@ -122,7 +139,6 @@ std::string RestImportHandler::positionize(size_t i) const {
////////////////////////////////////////////////////////////////////////////////
/// @brief register an error
////////////////////////////////////////////////////////////////////////////////
void RestImportHandler::registerError(RestImportResult& result,
std::string const& errorMsg) {
++result._numErrors;
@ -133,7 +149,6 @@ void RestImportHandler::registerError(RestImportResult& result,
////////////////////////////////////////////////////////////////////////////////
/// @brief construct an error message
////////////////////////////////////////////////////////////////////////////////
std::string RestImportHandler::buildParseError(size_t i,
char const* lineStart) {
if (lineStart != nullptr) {
@ -155,13 +170,11 @@ std::string RestImportHandler::buildParseError(size_t i,
}
////////////////////////////////////////////////////////////////////////////////
/// @brief process a single VelocyPack document
/// @brief process a single VelocyPack document of Object Type
////////////////////////////////////////////////////////////////////////////////
int RestImportHandler::handleSingleDocument(SingleCollectionTransaction& trx,
RestImportResult& result,
VPackBuilder& babies,
char const* lineStart,
VPackSlice slice,
bool isEdgeCollection, size_t i) {
if (!slice.isObject()) {
@ -267,8 +280,7 @@ bool RestImportHandler::createFromJson(std::string const& type) {
std::vector<std::string> const& suffix = _request->suffix();
if (suffix.size() != 0) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
"superfluous suffix, expecting " + IMPORT_PATH +
"?collection=<identifier>");
return false;
@ -439,7 +451,7 @@ bool RestImportHandler::createFromJson(std::string const& type) {
continue;
}
res = handleSingleDocument(trx, result, babies, oldPtr, builder->slice(),
res = handleSingleDocument(trx, result, babies, builder->slice(),
isEdgeCollection, i);
if (res != TRI_ERROR_NO_ERROR) {
@ -455,27 +467,21 @@ bool RestImportHandler::createFromJson(std::string const& type) {
else {
// the entire request body is one JSON document
std::shared_ptr<VPackBuilder> parsedDocuments;
HttpRequest* req = dynamic_cast<HttpRequest*>(_request.get());
if (req == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
}
VPackSlice documents;
try {
parsedDocuments = VPackParser::fromJson(req->body());
documents = _request->payload();
} catch (VPackException const&) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting a JSON array in the request");
return false;
}
VPackSlice const documents = parsedDocuments->slice();
// VPackSlice const documents = _request->payload(); //yields different
// error from what is expected in the server test
if (!documents.isArray()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting a JSON array in the request");
return false;
}
@ -485,8 +491,8 @@ bool RestImportHandler::createFromJson(std::string const& type) {
for (VPackValueLength i = 0; i < n; ++i) {
VPackSlice const slice = documents.at(i);
res = handleSingleDocument(trx, result, babies, nullptr, slice,
isEdgeCollection, static_cast<size_t>(i + 1));
res = handleSingleDocument(trx, result, babies, slice, isEdgeCollection,
static_cast<size_t>(i + 1));
if (res != TRI_ERROR_NO_ERROR) {
if (complete) {
@ -517,6 +523,110 @@ bool RestImportHandler::createFromJson(std::string const& type) {
return true;
}
bool RestImportHandler::createFromVPack(std::string const& type) {
if (_request == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
}
RestImportResult result;
std::vector<std::string> const& suffix = _request->suffix();
if (suffix.size() != 0) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
"superfluous suffix, expecting " + IMPORT_PATH +
"?collection=<identifier>");
return false;
}
bool const complete = extractBooleanParameter("complete", false);
bool const overwrite = extractBooleanParameter("overwrite", false);
OperationOptions opOptions;
opOptions.waitForSync = extractBooleanParameter("waitForSync", false);
// extract the collection name
bool found;
std::string const& collectionName = _request->value("collection", found);
if (!found || collectionName.empty()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_ARANGO_COLLECTION_PARAMETER_MISSING,
"'collection' is missing, expecting " + IMPORT_PATH +
"?collection=<identifier>");
return false;
}
// find and load collection given by name or identifier
SingleCollectionTransaction trx(
StandaloneTransactionContext::Create(_vocbase), collectionName,
TRI_TRANSACTION_WRITE);
// .............................................................................
// inside write transaction
// .............................................................................
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
generateTransactionError(collectionName, res, "");
return false;
}
bool const isEdgeCollection = trx.isEdgeCollection(collectionName);
if (overwrite) {
OperationOptions truncateOpts;
truncateOpts.waitForSync = false;
// truncate collection first
trx.truncate(collectionName, truncateOpts);
// Ignore the result ...
}
VPackBuilder babies;
babies.openArray();
VPackSlice const documents = _request->payload();
if (!documents.isArray()) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting a JSON array in the request");
return false;
}
VPackValueLength const n = documents.length();
for (VPackValueLength i = 0; i < n; ++i) {
VPackSlice const slice = documents.at(i);
res = handleSingleDocument(trx, result, babies, slice, isEdgeCollection,
static_cast<size_t>(i + 1));
if (res != TRI_ERROR_NO_ERROR) {
if (complete) {
// only perform a full import: abort
break;
}
res = TRI_ERROR_NO_ERROR;
}
}
babies.close();
if (res == TRI_ERROR_NO_ERROR) {
// no error so far. go on and perform the actual insert
res =
performImport(trx, result, collectionName, babies, complete, opOptions);
}
res = trx.finish(res);
if (res != TRI_ERROR_NO_ERROR) {
generateTransactionError(collectionName, res, "");
} else {
generateDocumentsCreated(result);
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock JSF_import_document
////////////////////////////////////////////////////////////////////////////////
@ -531,8 +641,7 @@ bool RestImportHandler::createFromKeyValueList() {
std::vector<std::string> const& suffix = _request->suffix();
if (suffix.size() != 0) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
"superfluous suffix, expecting " + IMPORT_PATH +
"?collection=<identifier>");
return false;
@ -578,8 +687,7 @@ bool RestImportHandler::createFromKeyValueList() {
static_cast<char const*>(memchr(current, '\n', bodyEnd - current));
if (next == nullptr) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"no JSON array found in second line");
return false;
}
@ -608,16 +716,14 @@ bool RestImportHandler::createFromKeyValueList() {
parsedKeys = parseVelocyPackLine(lineStart, lineEnd, success);
} catch (...) {
// This throws if the body is not parseable
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"no JSON string array found in first line");
return false;
}
VPackSlice const keys = parsedKeys->slice();
if (!success || !checkKeys(keys)) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"no JSON string array found in first line");
return false;
}
@ -707,8 +813,8 @@ bool RestImportHandler::createFromKeyValueList() {
try {
std::shared_ptr<VPackBuilder> objectBuilder =
createVelocyPackObject(keys, values, errorMsg, i);
res = handleSingleDocument(trx, result, babies, lineStart,
objectBuilder->slice(), isEdgeCollection, i);
res = handleSingleDocument(trx, result, babies, objectBuilder->slice(),
isEdgeCollection, i);
} catch (...) {
// raise any error
res = TRI_ERROR_INTERNAL;

View File

@ -68,7 +68,6 @@ class RestImportHandler : public RestVocbaseBaseHandler {
status execute() override final;
private:
//////////////////////////////////////////////////////////////////////////////
/// @brief create a position string
//////////////////////////////////////////////////////////////////////////////
@ -91,10 +90,10 @@ class RestImportHandler : public RestVocbaseBaseHandler {
/// @brief process a single VelocyPack document
//////////////////////////////////////////////////////////////////////////////
int handleSingleDocument(SingleCollectionTransaction& trx,
int handleSingleDocument(SingleCollectionTransaction& trx,
RestImportResult& result,
arangodb::velocypack::Builder& babies,
char const* lineStart, arangodb::velocypack::Slice slice,
arangodb::velocypack::Builder& babies,
arangodb::velocypack::Slice slice,
bool isEdgeCollection, size_t);
//////////////////////////////////////////////////////////////////////////////
@ -103,6 +102,7 @@ class RestImportHandler : public RestVocbaseBaseHandler {
//////////////////////////////////////////////////////////////////////////////
bool createFromJson(std::string const&);
bool createFromVPack(std::string const&);
//////////////////////////////////////////////////////////////////////////////
/// @brief creates documents by JSON objects
@ -116,16 +116,18 @@ class RestImportHandler : public RestVocbaseBaseHandler {
//////////////////////////////////////////////////////////////////////////////
bool createFromKeyValueList();
bool createFromKeyValueListVPack() {
LOG(ERR) << " not implemened";
return false;
}
//////////////////////////////////////////////////////////////////////////////
/// @brief perform the actual import (insert/update/replace) operations
//////////////////////////////////////////////////////////////////////////////
int performImport(SingleCollectionTransaction& trx,
RestImportResult& result,
int performImport(SingleCollectionTransaction& trx, RestImportResult& result,
std::string const& collectionName,
VPackBuilder const& babies,
bool complete,
VPackBuilder const& babies, bool complete,
OperationOptions const& opOptions);
//////////////////////////////////////////////////////////////////////////////
@ -152,9 +154,8 @@ class RestImportHandler : public RestVocbaseBaseHandler {
//////////////////////////////////////////////////////////////////////////////
std::shared_ptr<arangodb::velocypack::Builder> createVelocyPackObject(
arangodb::velocypack::Slice const&,
arangodb::velocypack::Slice const&,
std::string&, size_t);
arangodb::velocypack::Slice const&, arangodb::velocypack::Slice const&,
std::string&, size_t);
//////////////////////////////////////////////////////////////////////////////
/// @brief checks the keys, returns true if all values in the list are

View File

@ -106,8 +106,7 @@ RestHandler::status RestReplicationHandler::execute() {
}
handleCommandLoggerFirstTick();
} else if (command == "logger-follow") {
if (type != rest::RequestType::GET &&
type != rest::RequestType::PUT) {
if (type != rest::RequestType::GET && type != rest::RequestType::PUT) {
goto BAD_CALL;
}
if (isCoordinatorError()) {
@ -140,8 +139,7 @@ RestHandler::status RestReplicationHandler::execute() {
handleCommandInventory();
}
} else if (command == "keys") {
if (type != rest::RequestType::GET &&
type != rest::RequestType::POST &&
if (type != rest::RequestType::GET && type != rest::RequestType::POST &&
type != rest::RequestType::PUT &&
type != rest::RequestType::DELETE_REQ) {
goto BAD_CALL;
@ -303,8 +301,8 @@ RestHandler::status RestReplicationHandler::execute() {
}
}
} else {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid command");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid command");
}
return status::DONE;
@ -312,8 +310,7 @@ RestHandler::status RestReplicationHandler::execute() {
BAD_CALL:
if (len != 1) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_SUPERFLUOUS_SUFFICES,
"expecting URL /_api/replication/<command>");
} else {
generateError(rest::ResponseCode::METHOD_NOT_ALLOWED,
@ -326,8 +323,9 @@ BAD_CALL:
/// @brief comparator to sort collections
/// sort order is by collection type first (vertices before edges, this is
/// because edges depend on vertices being there), then name
bool RestReplicationHandler::sortCollections(arangodb::LogicalCollection const* l,
arangodb::LogicalCollection const* r) {
bool RestReplicationHandler::sortCollections(
arangodb::LogicalCollection const* l,
arangodb::LogicalCollection const* r) {
if (l->type() != r->type()) {
return l->type() < r->type();
}
@ -338,8 +336,8 @@ bool RestReplicationHandler::sortCollections(arangodb::LogicalCollection const*
}
/// @brief filter a collection based on collection attributes
bool RestReplicationHandler::filterCollection(arangodb::LogicalCollection* collection,
void* data) {
bool RestReplicationHandler::filterCollection(
arangodb::LogicalCollection* collection, void* data) {
bool includeSystem = *((bool*)data);
std::string const collectionName(collection->name());
@ -467,8 +465,7 @@ void RestReplicationHandler::handleCommandLoggerState() {
generateResult(rest::ResponseCode::OK, builder.slice());
} catch (...) {
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_OUT_OF_MEMORY);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
}
}
@ -494,8 +491,7 @@ void RestReplicationHandler::handleCommandLoggerTickRanges() {
b.close();
generateResult(rest::ResponseCode::OK, b.slice());
} catch (...) {
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_OUT_OF_MEMORY);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
return;
}
}
@ -531,8 +527,7 @@ void RestReplicationHandler::handleCommandLoggerFirstTick() {
b.close();
generateResult(rest::ResponseCode::OK, b.slice());
} catch (...) {
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_OUT_OF_MEMORY);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
}
}
@ -554,8 +549,8 @@ void RestReplicationHandler::handleCommandBatch() {
_request->toVelocyPackBuilderPtr(&VPackOptions::Defaults);
if (input == nullptr || !input->slice().isObject()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid JSON");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid JSON");
return;
}
@ -579,8 +574,7 @@ void RestReplicationHandler::handleCommandBatch() {
b.close();
generateResult(rest::ResponseCode::OK, b.slice());
} catch (...) {
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_OUT_OF_MEMORY);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
}
return;
}
@ -593,8 +587,8 @@ void RestReplicationHandler::handleCommandBatch() {
auto input = _request->toVelocyPackBuilderPtr(&VPackOptions::Defaults);
if (input == nullptr || !input->slice().isObject()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid JSON");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid JSON");
return;
}
@ -654,8 +648,8 @@ void RestReplicationHandler::handleCommandBarrier() {
_request->toVelocyPackBuilderPtr(&VPackOptions::Defaults);
if (input == nullptr || !input->slice().isObject()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid JSON");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid JSON");
return;
}
@ -673,8 +667,8 @@ void RestReplicationHandler::handleCommandBarrier() {
}
if (minTick == 0) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid tick value");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid tick value");
return;
}
@ -690,8 +684,7 @@ void RestReplicationHandler::handleCommandBarrier() {
b.close();
generateResult(rest::ResponseCode::OK, b.slice());
} catch (...) {
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_OUT_OF_MEMORY);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
}
return;
}
@ -704,8 +697,8 @@ void RestReplicationHandler::handleCommandBarrier() {
_request->toVelocyPackBuilderPtr(&VPackOptions::Defaults);
if (input == nullptr || !input->slice().isObject()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid JSON");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid JSON");
return;
}
@ -758,8 +751,7 @@ void RestReplicationHandler::handleCommandBarrier() {
b.close();
generateResult(rest::ResponseCode::OK, b.slice());
} catch (...) {
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_OUT_OF_MEMORY);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
}
return;
}
@ -782,8 +774,8 @@ void RestReplicationHandler::handleTrampolineCoordinator() {
ServerID DBserver = _request->value("DBserver");
if (DBserver.empty()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "need \"DBserver\" parameter");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"need \"DBserver\" parameter");
return;
}
@ -831,8 +823,7 @@ void RestReplicationHandler::handleTrampolineCoordinator() {
}
if (res->status == CL_COMM_BACKEND_UNAVAILABLE) {
// there is no result
generateError(rest::ResponseCode::BAD,
TRI_ERROR_CLUSTER_CONNECTION_LOST,
generateError(rest::ResponseCode::BAD, TRI_ERROR_CLUSTER_CONNECTION_LOST,
"lost connection within cluster");
return;
}
@ -845,8 +836,8 @@ void RestReplicationHandler::handleTrampolineCoordinator() {
}
bool dummy;
resetResponse(static_cast<rest::ResponseCode>(
res->result->getHttpReturnCode()));
resetResponse(
static_cast<rest::ResponseCode>(res->result->getHttpReturnCode()));
HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(_response.get());
@ -891,8 +882,8 @@ void RestReplicationHandler::handleCommandLoggerFollow() {
}
if (found && (tickStart > tickEnd || tickEnd == 0)) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid from/to values");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid from/to values");
return;
}
@ -925,26 +916,23 @@ void RestReplicationHandler::handleCommandLoggerFollow() {
VPackOptions options = VPackOptions::Defaults;
options.checkAttributeUniqueness = true;
std::shared_ptr<VPackBuilder> parsedRequest;
VPackSlice slice;
try {
parsedRequest = _request->toVelocyPackBuilderPtr(&options);
slice = _request->payload(&options);
} catch (...) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid body value. expecting array");
return;
}
VPackSlice const slice = parsedRequest->slice();
if (!slice.isArray()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid body value. expecting array");
return;
}
for (auto const& id : VPackArrayIterator(slice)) {
if (!id.isString()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid body value. expecting array of ids");
return;
}
@ -1075,8 +1063,8 @@ void RestReplicationHandler::handleCommandDetermineOpenTransactions() {
}
if (found && (tickStart > tickEnd || tickEnd == 0)) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid from/to values");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid from/to values");
return;
}
@ -1188,8 +1176,7 @@ void RestReplicationHandler::handleCommandInventory() {
generateResult(rest::ResponseCode::OK, builder.slice());
} catch (std::bad_alloc&) {
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_OUT_OF_MEMORY);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
return;
}
}
@ -1372,8 +1359,8 @@ void RestReplicationHandler::handleCommandRestoreCollection() {
try {
parsedRequest = _request->toVelocyPackBuilderPtr(&options);
} catch (...) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid JSON");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid JSON");
return;
}
VPackSlice const slice = parsedRequest->slice();
@ -1456,8 +1443,8 @@ void RestReplicationHandler::handleCommandRestoreIndexes() {
try {
parsedRequest = _request->toVelocyPackBuilderPtr(&options);
} catch (...) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid JSON");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid JSON");
return;
}
VPackSlice const slice = parsedRequest->slice();
@ -2413,8 +2400,7 @@ void RestReplicationHandler::handleCommandRestoreData() {
std::string const& value1 = _request->value("collection");
if (value1.empty()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid collection parameter, not given");
return;
}
@ -2427,8 +2413,7 @@ void RestReplicationHandler::handleCommandRestoreData() {
std::string msg = "invalid collection parameter: '";
msg += value1;
msg += "', cid is 0";
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, msg);
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER, msg);
return;
}
@ -2478,8 +2463,8 @@ void RestReplicationHandler::handleCommandRestoreDataCoordinator() {
std::string const& name = _request->value("collection");
if (name.empty()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid collection parameter");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid collection parameter");
return;
}
@ -2669,8 +2654,7 @@ void RestReplicationHandler::handleCommandRestoreDataCoordinator() {
} else {
LOG(ERR) << "result body is no object";
}
} else if (result.answer_code ==
rest::ResponseCode::SERVER_ERROR) {
} else if (result.answer_code == rest::ResponseCode::SERVER_ERROR) {
// copy default options
VPackOptions options = VPackOptions::Defaults;
options.checkAttributeUniqueness = true;
@ -2746,8 +2730,8 @@ void RestReplicationHandler::handleCommandCreateKeys() {
std::string const& collection = _request->value("collection");
if (collection.empty()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid collection parameter");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid collection parameter");
return;
}
@ -2829,8 +2813,7 @@ void RestReplicationHandler::handleCommandGetKeys() {
std::vector<std::string> const& suffix = _request->suffix();
if (suffix.size() != 2) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting GET /_api/replication/keys/<keys-id>");
return;
}
@ -2922,8 +2905,7 @@ void RestReplicationHandler::handleCommandFetchKeys() {
std::vector<std::string> const& suffix = _request->suffix();
if (suffix.size() != 2) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting PUT /_api/replication/keys/<keys-id>");
return;
}
@ -2960,8 +2942,8 @@ void RestReplicationHandler::handleCommandFetchKeys() {
} else if (value3 == "docs") {
keys = false;
} else {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid 'type' value");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid 'type' value");
return;
}
@ -3035,8 +3017,7 @@ void RestReplicationHandler::handleCommandRemoveKeys() {
std::vector<std::string> const& suffix = _request->suffix();
if (suffix.size() != 2) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting DELETE /_api/replication/keys/<keys-id>");
return;
}
@ -3051,8 +3032,7 @@ void RestReplicationHandler::handleCommandRemoveKeys() {
bool found = keys->remove(collectionKeysId);
if (!found) {
generateError(rest::ResponseCode::NOT_FOUND,
TRI_ERROR_CURSOR_NOT_FOUND);
generateError(rest::ResponseCode::NOT_FOUND, TRI_ERROR_CURSOR_NOT_FOUND);
return;
}
@ -3060,13 +3040,11 @@ void RestReplicationHandler::handleCommandRemoveKeys() {
resultBuilder.openObject();
resultBuilder.add("id", VPackValue(id)); // id as a string
resultBuilder.add("error", VPackValue(false));
resultBuilder.add(
"code",
VPackValue(static_cast<int>(rest::ResponseCode::ACCEPTED)));
resultBuilder.add("code",
VPackValue(static_cast<int>(rest::ResponseCode::ACCEPTED)));
resultBuilder.close();
generateResult(rest::ResponseCode::ACCEPTED,
resultBuilder.slice());
generateResult(rest::ResponseCode::ACCEPTED, resultBuilder.slice());
}
////////////////////////////////////////////////////////////////////////////////
@ -3077,8 +3055,8 @@ void RestReplicationHandler::handleCommandDump() {
std::string const& collection = _request->value("collection");
if (collection.empty()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid collection parameter");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid collection parameter");
return;
}
@ -3122,8 +3100,8 @@ void RestReplicationHandler::handleCommandDump() {
}
if (tickStart > tickEnd || tickEnd == 0) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "invalid from/to values");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid from/to values");
return;
}
@ -3215,8 +3193,8 @@ void RestReplicationHandler::handleCommandDump() {
response->setContentType(rest::ContentType::DUMP);
// set headers
_response->setHeaderNC(
TRI_REPLICATION_HEADER_CHECKMORE, (dump._hasMore ? "true" : "false"));
_response->setHeaderNC(TRI_REPLICATION_HEADER_CHECKMORE,
(dump._hasMore ? "true" : "false"));
_response->setHeaderNC(TRI_REPLICATION_HEADER_LASTINCLUDED,
StringUtils::itoa(dump._lastFoundTick));
@ -3255,8 +3233,7 @@ void RestReplicationHandler::handleCommandMakeSlave() {
VelocyPackHelper::getStringValue(body, "endpoint", "");
if (endpoint.empty()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"<endpoint> must be a valid endpoint");
return;
}
@ -3353,8 +3330,7 @@ void RestReplicationHandler::handleCommandMakeSlave() {
(!restrictType.empty() && config._restrictCollections.empty()) ||
(!restrictType.empty() && restrictType != "include" &&
restrictType != "exclude")) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid value for <restrictCollections> or <restrictType>");
return;
}
@ -3415,8 +3391,7 @@ void RestReplicationHandler::handleCommandMakeSlave() {
_vocbase->replicationApplier()->toVelocyPack();
generateResult(rest::ResponseCode::OK, result->slice());
} catch (...) {
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_OUT_OF_MEMORY);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
return;
}
}
@ -3440,8 +3415,7 @@ void RestReplicationHandler::handleCommandSync() {
VelocyPackHelper::getStringValue(body, "endpoint", "");
if (endpoint.empty()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"<endpoint> must be a valid endpoint");
return;
}
@ -3482,8 +3456,7 @@ void RestReplicationHandler::handleCommandSync() {
(!restrictType.empty() && restrictCollections.empty()) ||
(!restrictType.empty() && restrictType != "include" &&
restrictType != "exclude")) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid value for <restrictCollections> or <restrictType>");
return;
}
@ -3597,8 +3570,7 @@ void RestReplicationHandler::handleCommandApplierGetConfig() {
std::shared_ptr<VPackBuilder> configBuilder = config.toVelocyPack(false);
generateResult(rest::ResponseCode::OK, configBuilder->slice());
} catch (...) {
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_OUT_OF_MEMORY);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
}
}
@ -3793,8 +3765,7 @@ void RestReplicationHandler::handleCommandApplierGetState() {
_vocbase->replicationApplier()->toVelocyPack();
generateResult(rest::ResponseCode::OK, result->slice());
} catch (...) {
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_OUT_OF_MEMORY);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
return;
}
}
@ -3838,8 +3809,7 @@ void RestReplicationHandler::handleCommandAddFollower() {
VPackSlice const followerId = body.get("followerId");
VPackSlice const shard = body.get("shard");
if (!followerId.isString() || !shard.isString()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"'followerId' and 'shard' attributes must be strings");
return;
}
@ -3886,8 +3856,7 @@ void RestReplicationHandler::handleCommandRemoveFollower() {
VPackSlice const followerId = body.get("followerId");
VPackSlice const shard = body.get("shard");
if (!followerId.isString() || !shard.isString()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"'followerId' and 'shard' attributes must be strings");
return;
}
@ -3926,8 +3895,7 @@ void RestReplicationHandler::handleCommandHoldReadLockCollection() {
}
VPackSlice const body = parsedBody->slice();
if (!body.isObject()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"body needs to be an object with attributes 'collection', "
"'ttl' and 'id'");
return;
@ -3936,8 +3904,7 @@ void RestReplicationHandler::handleCommandHoldReadLockCollection() {
VPackSlice const ttlSlice = body.get("ttl");
VPackSlice const idSlice = body.get("id");
if (!collection.isString() || !ttlSlice.isNumber() || !idSlice.isString()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"'collection' must be a string and 'ttl' a number and "
"'id' a string");
return;
@ -4032,15 +3999,14 @@ void RestReplicationHandler::handleCommandCheckHoldReadLockCollection() {
}
VPackSlice const body = parsedBody->slice();
if (!body.isObject()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"body needs to be an object with attribute 'id'");
return;
}
VPackSlice const idSlice = body.get("id");
if (!idSlice.isString()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "'id' needs to be a string");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"'id' needs to be a string");
return;
}
std::string id = idSlice.copyString();
@ -4049,8 +4015,7 @@ void RestReplicationHandler::handleCommandCheckHoldReadLockCollection() {
CONDITION_LOCKER(locker, _condVar);
auto it = _holdReadLockJobs.find(id);
if (it == _holdReadLockJobs.end()) {
generateError(rest::ResponseCode::NOT_FOUND,
TRI_ERROR_HTTP_NOT_FOUND,
generateError(rest::ResponseCode::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND,
"no hold read lock job found for 'id'");
return;
}
@ -4079,15 +4044,14 @@ void RestReplicationHandler::handleCommandCancelHoldReadLockCollection() {
}
VPackSlice const body = parsedBody->slice();
if (!body.isObject()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"body needs to be an object with attribute 'id'");
return;
}
VPackSlice const idSlice = body.get("id");
if (!idSlice.isString()) {
generateError(rest::ResponseCode::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER, "'id' needs to be a string");
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"'id' needs to be a string");
return;
}
std::string id = idSlice.copyString();

View File

@ -28,8 +28,8 @@
#include "Basics/MutexLocker.h"
#include "Basics/ScopeGuard.h"
#include "Basics/StaticStrings.h"
#include "Basics/VelocyPackHelper.h"
#include "Basics/VPackStringBufferAdapter.h"
#include "Basics/VelocyPackHelper.h"
#include "Utils/SingleCollectionTransaction.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/Traverser.h"
@ -256,9 +256,7 @@ void RestSimpleHandler::removeByKeys(VPackSlice const& slice) {
result.add("removed", VPackValue(removed));
result.add("ignored", VPackValue(ignored));
result.add("error", VPackValue(false));
result.add(
"code",
VPackValue(static_cast<int>(rest::ResponseCode::OK)));
result.add("code", VPackValue(static_cast<int>(rest::ResponseCode::OK)));
if (!silent) {
result.add("old", queryResult.result->slice());
}
@ -273,8 +271,7 @@ void RestSimpleHandler::removeByKeys(VPackSlice const& slice) {
ex.what());
} catch (...) {
unregisterQuery();
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_INTERNAL);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL);
}
}
@ -355,7 +352,8 @@ void RestSimpleHandler::lookupByKeys(VPackSlice const& slice) {
resultSize = static_cast<size_t>(qResult.length());
}
VPackBuilder result;
VPackBuffer<uint8_t> resultBuffer;
VPackBuilder result(resultBuffer);
{
VPackObjectBuilder guard(&result);
resetResponse(rest::ResponseCode::OK);
@ -436,32 +434,26 @@ void RestSimpleHandler::lookupByKeys(VPackSlice const& slice) {
VPackValue(static_cast<int>(_response->responseCode())));
// reserve a few bytes per result document by default
int res = response->body().reserve(32 * resultSize);
int res = response->reservePayload(32 * resultSize);
if (res != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(res);
}
}
auto customTypeHandler = queryResult.context->orderCustomTypeHandler();
VPackOptions options = VPackOptions::Defaults; // copy defaults
options.customTypeHandler = customTypeHandler.get();
generateResult(rest::ResponseCode::OK, std::move(resultBuffer),
queryResult.context);
arangodb::basics::VPackStringBufferAdapter buffer(
response->body().stringBuffer());
VPackDumper dumper(&buffer, &options);
dumper.dump(result.slice());
} catch (arangodb::basics::Exception const& ex) {
unregisterQuery();
generateError(GeneralResponse::responseCode(ex.code()), ex.code(),
ex.what());
} catch (std::exception const& ex) {
unregisterQuery();
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_INTERNAL, ex.what());
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL,
ex.what());
} catch (...) {
unregisterQuery();
generateError(rest::ResponseCode::SERVER_ERROR,
TRI_ERROR_INTERNAL);
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL);
}
}

View File

@ -114,8 +114,7 @@ class RequestStatisticsAgent
RequestStatisticsAgentDesc> {
public:
RequestStatisticsAgent(bool standalone = false)
: StatisticsAgent(standalone) {
}
: StatisticsAgent(standalone) {}
RequestStatisticsAgent(RequestStatisticsAgent const&) = delete;

View File

@ -30,48 +30,61 @@
using namespace arangodb;
using namespace arangodb::basics;
void GeneralResponse::addPayload(VPackSlice const& slice,
arangodb::velocypack::Options const* options,
bool resolve_externals) {
addPayloadPreconditions();
addPayloadPreHook(false, resolve_externals);
if (!options) {
options = &arangodb::velocypack::Options::Defaults;
namespace detail {
VPackOptions const* getOptions(VPackOptions const* options) {
if (options) {
return options;
}
return &VPackOptions::Options::Defaults;
}
}
if (resolve_externals) {
auto tmpBuffer =
basics::VelocyPackHelper::sanitizeExternalsChecked(slice, options);
_vpackPayloads.push_back(std::move(tmpBuffer));
} else {
// just copy
_vpackPayloads.emplace_back(slice.byteSize());
_vpackPayloads.back().append(slice.startAs<char const>(), slice.byteSize());
void GeneralResponse::addPayload(VPackSlice const& slice,
VPackOptions const* options,
bool resolveExternals) {
addPayloadPreconditions();
_numPayloads++;
options = detail::getOptions(options);
bool skipBody = false;
addPayloadPreHook(true, resolveExternals, skipBody);
if (!skipBody) {
if (resolveExternals) {
auto tmpBuffer =
basics::VelocyPackHelper::sanitizeExternalsChecked(slice, options);
_vpackPayloads.push_back(std::move(tmpBuffer));
} else {
// just copy
_vpackPayloads.emplace_back(slice.byteSize());
_vpackPayloads.back().append(slice.startAs<char const>(),
slice.byteSize());
}
}
addPayloadPostHook(options);
// we pass the original slice here the new one can be accessed
addPayloadPostHook(slice, options, resolveExternals, skipBody);
};
void GeneralResponse::addPayload(VPackBuffer<uint8_t>&& buffer,
arangodb::velocypack::Options const* options,
bool resolve_externals) {
bool resolveExternals) {
addPayloadPreconditions();
// TODO
// skip sanatizing here for http if conent type is json because it will
// be dumped anyway -- check with jsteemann
addPayloadPreHook(true, resolve_externals);
_numPayloads++;
options = detail::getOptions(options);
if (!options) {
options = &arangodb::velocypack::Options::Defaults;
bool skipBody = false;
addPayloadPreHook(true, resolveExternals, skipBody);
if (!skipBody) {
if (resolveExternals) {
auto tmpBuffer = basics::VelocyPackHelper::sanitizeExternalsChecked(
VPackSlice(buffer.data()), options);
_vpackPayloads.push_back(std::move(tmpBuffer));
} else {
_vpackPayloads.push_back(std::move(buffer));
}
}
if (resolve_externals) {
auto tmpBuffer = basics::VelocyPackHelper::sanitizeExternalsChecked(
VPackSlice(buffer.data()), options);
_vpackPayloads.push_back(std::move(tmpBuffer));
} else {
_vpackPayloads.push_back(std::move(buffer));
}
addPayloadPostHook(options);
addPayloadPostHook(VPackSlice(buffer.data()), options, resolveExternals,
skipBody);
};
std::string GeneralResponse::responseString(ResponseCode code) {
@ -460,4 +473,6 @@ GeneralResponse::GeneralResponse(ResponseCode responseCode)
: _responseCode(responseCode),
_contentType(ContentType::UNSET),
_connectionType(ConnectionType::CONNECTION_NONE),
_options(velocypack::Options::Defaults) {}
_options(velocypack::Options::Defaults),
_generateBody(false),
_contentTypeRequested(ContentType::UNSET) {}

View File

@ -79,6 +79,9 @@ class GeneralResponse {
}
void setConnectionType(ConnectionType type) { _connectionType = type; }
void setContentTypeRequested(ContentType type) {
_contentTypeRequested = type;
}
virtual arangodb::Endpoint::TransportType transportType() = 0;
@ -122,25 +125,42 @@ class GeneralResponse {
// generates the response body, sets the content type; this might
// throw an error
virtual void setPayload(arangodb::velocypack::Slice const&,
bool generateBody = true,
arangodb::velocypack::Options const& =
arangodb::velocypack::Options::Defaults) = 0;
void setPayload(VPackSlice&& slice, bool generateBody,
VPackOptions const& options = VPackOptions::Options::Defaults,
bool resolveExternals = true) {
_generateBody = generateBody;
auto tmp = std::move(slice);
addPayload(tmp, &options, resolveExternals);
}
// Payload needs to be of type: VPackSlice const&
// or VPackBuffer<uint8_t>&&
template <typename Payload>
void setPayload(Payload&& payload, bool generateBody,
VPackOptions const& options = VPackOptions::Options::Defaults,
bool resolveExternals = true) {
_generateBody = generateBody;
addPayload(std::forward<Payload>(payload), &options, resolveExternals);
}
void addPayloadPreconditions() { TRI_ASSERT(_vpackPayloads.size() == 0); }
virtual void addPayloadPreHook(bool inputIsBuffer, bool& resolveExternals) {}
virtual void addPayloadPostHook(
arangodb::velocypack::Options const* options) {}
void addPayload(VPackSlice const& slice,
arangodb::velocypack::Options const* options = nullptr,
virtual void addPayloadPreHook(bool inputIsBuffer, bool& resolveExternals,
bool& skipBody) {}
void addPayload(VPackSlice const&,
arangodb::velocypack::Options const* = nullptr,
bool resolve_externals = true);
void addPayload(VPackBuffer<uint8_t>&& buffer,
arangodb::velocypack::Options const* options = nullptr,
void addPayload(VPackBuffer<uint8_t>&&,
arangodb::velocypack::Options const* = nullptr,
bool resolve_externals = true);
virtual void addPayloadPostHook(VPackSlice const&,
arangodb::velocypack::Options const*,
bool resolveExternals, bool bodySkipped) {}
virtual int reservePayload(std::size_t size) { return size; }
virtual bool setGenerateBody(bool) { return true; }; // used for head
// resonses
virtual int reservePayload(std::size_t size) { return TRI_ERROR_NO_ERROR; }
bool generateBody() const { return _generateBody; }; // used for head
virtual bool setGenerateBody(bool) {
return _generateBody;
}; // used for head
// resonses
void setOptions(VPackOptions options) { _options = std::move(options); };
protected:
@ -149,9 +169,12 @@ class GeneralResponse {
_headers; // headers/metadata map
std::vector<VPackBuffer<uint8_t>> _vpackPayloads;
std::size_t _numPayloads;
ContentType _contentType;
ConnectionType _connectionType;
velocypack::Options _options;
bool _generateBody;
ContentType _contentTypeRequested;
};
}

View File

@ -47,8 +47,8 @@ HttpResponse::HttpResponse(ResponseCode code)
: GeneralResponse(code),
_isHeadResponse(false),
_body(TRI_UNKNOWN_MEM_ZONE, false),
_bodySize(0),
_generateBody(false) {
_bodySize(0) {
_generateBody = false;
_contentType = ContentType::TEXT;
_connectionType = rest::CONNECTION_KEEP_ALIVE;
if (_body.c_str() == nullptr) {
@ -300,14 +300,25 @@ void HttpResponse::writeHeader(StringBuffer* output) {
// end of header, body to follow
}
void HttpResponse::addPayloadPostHook(VPackOptions const* options) {
VPackSlice slice(_vpackPayloads.front().data());
void HttpResponse::addPayloadPostHook(
VPackSlice const& slice,
VPackOptions const* options = &VPackOptions::Options::Defaults,
bool resolveExternals = true, bool bodySkipped = false) {
VPackSlice const* slicePtr;
if (!bodySkipped) {
// we have Probably resolved externals
TRI_ASSERT(!_vpackPayloads.empty());
VPackSlice tmpSlice = VPackSlice(_vpackPayloads.front().data());
slicePtr = &tmpSlice;
} else {
slicePtr = &slice;
}
switch (_contentType) {
case rest::ContentType::VPACK: {
size_t length = static_cast<size_t>(slice.byteSize());
size_t length = static_cast<size_t>(slicePtr->byteSize());
if (_generateBody) {
_body.appendText(slice.startAs<const char>(), length);
_body.appendText(slicePtr->startAs<const char>(), length);
} else {
headResponse(length);
}
@ -317,7 +328,7 @@ void HttpResponse::addPayloadPostHook(VPackOptions const* options) {
setContentType(rest::ContentType::JSON);
if (_generateBody) {
arangodb::basics::VelocyPackDumper dumper(&_body, options);
dumper.dumpValue(slice);
dumper.dumpValue(*slicePtr);
} else {
// TODO can we optimize this?
// Just dump some where else to find real length
@ -328,17 +339,10 @@ void HttpResponse::addPayloadPostHook(VPackOptions const* options) {
// usual dumping - but not to the response body
VPackDumper dumper(&buffer, options);
dumper.dump(slice);
dumper.dump(*slicePtr);
headResponse(tmp.length());
}
}
}
//_vpackPayloads.clear();
}
void HttpResponse::setPayload(arangodb::velocypack::Slice const& slice,
bool generateBody, VPackOptions const& options) {
_generateBody = generateBody;
addPayload(slice, &options, true);
};

View File

@ -74,11 +74,10 @@ class HttpResponse : public GeneralResponse {
public:
void reset(ResponseCode code) override final;
void addPayloadPreHook(bool inputIsBuffer, bool& resolveExternals) override {
void addPayloadPreHook(bool inputIsBuffer, bool& resolveExternals,
bool& skipBody) override {
if (_contentType == ContentType::JSON) {
// resolveExternals = false; // they get resolved during dump in post
// hook
// this optimization leads to bad bas crahses
skipBody = true;
}
}
@ -86,9 +85,8 @@ class HttpResponse : public GeneralResponse {
return _generateBody = generateBody;
} // used for head-responses
int reservePayload(std::size_t size) override { return _body.reserve(size); }
void addPayloadPostHook(VPackOptions const* options) override;
void setPayload(arangodb::velocypack::Slice const&, bool generateBody,
arangodb::velocypack::Options const&) override final;
void addPayloadPostHook(VPackSlice const&, VPackOptions const* options,
bool resolveExternals, bool bodySkipped) override;
arangodb::Endpoint::TransportType transportType() override {
return arangodb::Endpoint::TransportType::HTTP;
@ -103,7 +101,6 @@ class HttpResponse : public GeneralResponse {
std::vector<std::string> _cookies;
basics::StringBuffer _body;
size_t _bodySize;
bool _generateBody;
};
}

View File

@ -53,17 +53,10 @@ void VppResponse::reset(ResponseCode code) {
_responseCode = code;
_headers.clear();
_connectionType = rest::CONNECTION_KEEP_ALIVE;
_contentType = ContentType::TEXT;
_contentType = ContentType::VPACK;
_generateBody = false; // payload has to be set
}
void VppResponse::setPayload(arangodb::velocypack::Slice const& slice,
bool generateBody, VPackOptions const& options) {
if (setGenerateBody(generateBody)) {
addPayload(slice, &options);
}
};
VPackMessageNoOwnBuffer VppResponse::prepareForNetwork() {
// initalize builder with vpackbuffer. then we do not need to
// steal the header and can avoid the shared pointer
@ -75,8 +68,18 @@ VPackMessageNoOwnBuffer VppResponse::prepareForNetwork() {
VPackValue(static_cast<int>(meta::underlyingValue(_responseCode))));
builder.close();
_header = builder.steal();
return VPackMessageNoOwnBuffer(VPackSlice(_header->data()),
VPackSlice(_vpackPayloads.front().data()),
_messageId, _generateBody);
if (_vpackPayloads.empty()) {
if (_generateBody) {
LOG_TOPIC(INFO, Logger::REQUESTS)
<< "Response should generate body but no Data available";
_generateBody = false; // no body availalbe
}
return VPackMessageNoOwnBuffer(VPackSlice(_header->data()),
VPackSlice::noneSlice(), _messageId,
_generateBody);
} else {
return VPackMessageNoOwnBuffer(VPackSlice(_header->data()),
VPackSlice(_vpackPayloads.front().data()),
_messageId, _generateBody);
}
}
// void VppResponse::writeHeader(basics::StringBuffer*) {}

View File

@ -51,8 +51,6 @@ class VppResponse : public GeneralResponse {
// required by base
virtual uint64_t messageId() const override { return _messageId; }
void reset(ResponseCode code) final;
void setPayload(arangodb::velocypack::Slice const&, bool generateBody,
arangodb::velocypack::Options const&) final;
virtual arangodb::Endpoint::TransportType transportType() override {
return arangodb::Endpoint::TransportType::VPP;
};
@ -65,7 +63,6 @@ class VppResponse : public GeneralResponse {
std::shared_ptr<VPackBuffer<uint8_t>>
_header; // generated form _headers when prepared for network
uint64_t _messageId;
bool _generateBody; // this must be true if payload should be send
};
}