1
0
Fork 0

Merge branch 'spdvpk' of https://github.com/arangodb/arangodb into spdvpk

This commit is contained in:
Jan Steemann 2016-02-18 16:17:07 +01:00
commit 5b3b7e673b
7 changed files with 204 additions and 66 deletions

View File

@ -253,8 +253,9 @@ class Builder {
std::shared_ptr<Buffer<uint8_t>> const& buffer() const { return _buffer; }
std::shared_ptr<Buffer<uint8_t>> steal() {
std::shared_ptr<Buffer<uint8_t>> res = std::move(_buffer);
_buffer.reset(new Buffer<uint8_t>());
// After a steal the Builder is broken!
std::shared_ptr<Buffer<uint8_t>> res = _buffer;
_buffer.reset();
_pos = 0;
return res;
}

View File

@ -164,8 +164,9 @@ class Parser {
// Not with this high-performance two-pass approach. :-(
std::shared_ptr<Builder> steal() {
// Parser object is broken after a steal()
std::shared_ptr<Builder> res(_b);
_b.reset(new Builder());
_b.reset();
return res;
}

View File

@ -253,9 +253,15 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) {
return false;
}
if (ServerState::instance()->isCoordinator()) {
return getDocumentCoordinator(collection, key, generateBody);
VPackBuilder builder;
{
VPackObjectBuilder guard(&builder);
builder.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(key));
if (ifRid != 0) {
builder.add(TRI_VOC_ATTRIBUTE_REV, VPackValue(ifRid));
}
}
VPackSlice search = builder.slice();
// find and load collection given by name or identifier
SingleCollectionReadOnlyTransaction trx(new StandaloneTransactionContext(),
@ -266,67 +272,44 @@ bool RestDocumentHandler::readSingleDocument(bool generateBody) {
// .............................................................................
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
generateTransactionError(collection, res);
return false;
}
TRI_voc_cid_t const cid = trx.cid();
// If we are a DBserver, we want to use the cluster-wide collection
// name for error reporting:
std::string collectionName = collection;
if (ServerState::instance()->isDBServer()) {
collectionName = trx.resolver()->getCollectionName(cid);
OperationOptions options;
OperationResult result = trx.document(collection, search, options);
res = trx.finish(result.code);
if(!result.successful()) {
if (result.code == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
generateDocumentNotFound(collection, (TRI_voc_key_t)key.c_str());
return false;
} else if (ifRid != 0 && result.code == TRI_ERROR_ARANGO_CONFLICT) {
generatePreconditionFailed(result.slice());
} else {
generateTransactionError(collection, res, (TRI_voc_key_t)key.c_str());
}
return false;
}
TRI_doc_mptr_copy_t mptr;
res = trx.document(trx.trxCollection(), &mptr, key);
TRI_document_collection_t* document = trx.documentCollection();
TRI_ASSERT(document != nullptr);
auto shaper = document->getShaper(); // PROTECTED by trx here
res = trx.finish(res);
// .............................................................................
// outside read transaction
// .............................................................................
TRI_ASSERT(trx.hasDitch());
if (res != TRI_ERROR_NO_ERROR) {
generateTransactionError(collectionName, res, (TRI_voc_key_t)key.c_str());
generateTransactionError(collection, res, (TRI_voc_key_t)key.c_str());
return false;
}
if (mptr.getDataPtr() == nullptr) { // PROTECTED by trx here
generateDocumentNotFound(trx, cid, (TRI_voc_key_t)key.c_str());
return false;
}
// generate result
TRI_voc_rid_t const rid = mptr._rid;
if (ifNoneRid == 0) {
if (ifRid == 0 || ifRid == rid) {
generateDocument(trx, cid, mptr, shaper, generateBody);
} else {
generatePreconditionFailed(trx, cid, mptr, rid);
}
} else if (ifNoneRid == rid) {
if (ifRid == 0 || ifRid == rid) {
generateNotModified(rid);
} else {
generatePreconditionFailed(trx, cid, mptr, rid);
}
TRI_voc_rid_t const rid =
VelocyPackHelper::getNumericValue<TRI_voc_rid_t>(
result.slice(), TRI_VOC_ATTRIBUTE_REV, 0);
if (ifNoneRid != 0 && ifNoneRid == rid) {
generateNotModified(rid);
} else {
if (ifRid == 0 || ifRid == rid) {
generateDocument(trx, cid, mptr, shaper, generateBody);
} else {
generatePreconditionFailed(trx, cid, mptr, rid);
}
VPackOptions options = VPackOptions::Defaults;
options.customTypeHandler = result.customTypeHandler;
generateDocument(result.slice(), generateBody, &options);
}
return true;
}

View File

@ -287,6 +287,48 @@ void RestVocbaseBaseHandler::generateForbidden() {
"operation forbidden");
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates precondition failed
/// DEPRECATED
////////////////////////////////////////////////////////////////////////////////
void RestVocbaseBaseHandler::generatePreconditionFailed(
VPackSlice const& slice) {
TRI_ASSERT(slice.isObject());
TRI_ASSERT(slice.hasKey(TRI_VOC_ATTRIBUTE_ID));
TRI_ASSERT(slice.hasKey(TRI_VOC_ATTRIBUTE_REV));
TRI_ASSERT(slice.hasKey(TRI_VOC_ATTRIBUTE_KEY));
createResponse(HttpResponse::PRECONDITION_FAILED);
_response->setContentType("application/json; charset=utf-8");
std::string rev = VelocyPackHelper::getStringValue(slice, TRI_VOC_ATTRIBUTE_REV, "");
_response->setHeader("etag", 4, "\"" + rev + "\"");
VPackBuilder builder;
{
VPackObjectBuilder guard(&builder);
// _id and _key are safe and do not need to be JSON-encoded
builder.add("error", VPackValue(true));
builder.add(
"code",
VPackValue(static_cast<int32_t>(HttpResponse::PRECONDITION_FAILED)));
builder.add("errorNum", VPackValue(TRI_ERROR_ARANGO_CONFLICT));
builder.add("errorMessage", VPackValue("precondition failed"));
builder.add(TRI_VOC_ATTRIBUTE_ID, slice.get(TRI_VOC_ATTRIBUTE_ID));
builder.add(TRI_VOC_ATTRIBUTE_KEY, slice.get(TRI_VOC_ATTRIBUTE_KEY));
builder.add(TRI_VOC_ATTRIBUTE_REV, slice.get(TRI_VOC_ATTRIBUTE_REV));
}
VPackStringBufferAdapter buffer(_response->body().stringBuffer());
VPackDumper dumper(&buffer);
try {
dumper.dump(builder.slice());
} catch (...) {
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL,
"cannot generate output");
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates precondition failed
////////////////////////////////////////////////////////////////////////////////
@ -315,6 +357,8 @@ void RestVocbaseBaseHandler::generatePreconditionFailed(
.appendText("\"}");
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates not modified
////////////////////////////////////////////////////////////////////////////////
@ -328,6 +372,7 @@ void RestVocbaseBaseHandler::generateNotModified(TRI_voc_rid_t rid) {
////////////////////////////////////////////////////////////////////////////////
/// @brief generates next entry from a result set
/// DEPRECATED
////////////////////////////////////////////////////////////////////////////////
void RestVocbaseBaseHandler::generateDocument(
@ -421,6 +466,53 @@ void RestVocbaseBaseHandler::generateDocument(
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates next entry from a result set
/// DEPRECATED
////////////////////////////////////////////////////////////////////////////////
void RestVocbaseBaseHandler::generateDocument(VPackSlice const& document,
bool generateBody,
VPackOptions const* options) {
TRI_ASSERT(document.isObject());
TRI_ASSERT(document.hasKey(TRI_VOC_ATTRIBUTE_REV));
std::string rev = VelocyPackHelper::getStringValue(document, TRI_VOC_ATTRIBUTE_REV, "");
// and generate a response
createResponse(HttpResponse::OK);
_response->setContentType("application/json; charset=utf-8");
_response->setHeader("etag", 4, "\"" + rev + "\"");
if (generateBody) {
VPackStringBufferAdapter buffer(_response->body().stringBuffer());
VPackDumper dumper(&buffer, options);
try {
dumper.dump(document);
} catch (...) {
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL,
"cannot generate output");
}
} else {
// TODO can we optimize this?
// Just dump some where else to find real length
TRI_string_buffer_t tmpBuffer;
// convert object to string
TRI_InitStringBuffer(&tmpBuffer, TRI_UNKNOWN_MEM_ZONE);
VPackStringBufferAdapter buffer(&tmpBuffer);
VPackDumper dumper(&buffer, options);
try {
dumper.dump(document);
} catch (...) {
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL,
"cannot generate output");
}
_response->headResponse(TRI_LengthStringBuffer(&tmpBuffer));
TRI_DestroyStringBuffer(&tmpBuffer);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate an error message for a transaction error
////////////////////////////////////////////////////////////////////////////////

View File

@ -282,11 +282,18 @@ class RestVocbaseBaseHandler : public RestBaseHandler {
//////////////////////////////////////////////////////////////////////////////
/// @brief generates precondition failed, without transaction info
/// DEPRECATED
//////////////////////////////////////////////////////////////////////////////
void generatePreconditionFailed(std::string const&, TRI_voc_key_t key,
TRI_voc_rid_t rid);
//////////////////////////////////////////////////////////////////////////////
/// @brief generates precondition failed, without transaction info
//////////////////////////////////////////////////////////////////////////////
void generatePreconditionFailed(arangodb::velocypack::Slice const& slice);
//////////////////////////////////////////////////////////////////////////////
/// @brief generates not modified
//////////////////////////////////////////////////////////////////////////////
@ -295,11 +302,19 @@ class RestVocbaseBaseHandler : public RestBaseHandler {
//////////////////////////////////////////////////////////////////////////////
/// @brief generates first entry from a result set
/// DEPRECATED
//////////////////////////////////////////////////////////////////////////////
void generateDocument(SingleCollectionReadOnlyTransaction& trx, TRI_voc_cid_t,
TRI_doc_mptr_copy_t const&, VocShaper*, bool);
//////////////////////////////////////////////////////////////////////////////
/// @brief generates first entry from a result set
//////////////////////////////////////////////////////////////////////////////
void generateDocument(arangodb::velocypack::Slice const&, bool,
arangodb::velocypack::Options const* options = nullptr);
//////////////////////////////////////////////////////////////////////////////
/// @brief generate an error message for a transaction error
//////////////////////////////////////////////////////////////////////////////

View File

@ -34,12 +34,28 @@
namespace arangodb {
struct OperationResult {
OperationResult() : buffer(), customTypeHandler(nullptr), code(TRI_ERROR_NO_ERROR), wasSynchronous(false) {}
OperationResult(std::shared_ptr<VPackBuffer<uint8_t>> buffer, VPackCustomTypeHandler* handler) : buffer(buffer), customTypeHandler(handler), code(TRI_ERROR_NO_ERROR), wasSynchronous(false) {}
OperationResult(int code, std::shared_ptr<VPackBuffer<uint8_t>> buffer) : buffer(buffer), customTypeHandler(nullptr), code(code), wasSynchronous(false) {}
OperationResult(std::shared_ptr<VPackBuffer<uint8_t>> buffer, bool wasSynchronous) : buffer(buffer), customTypeHandler(nullptr), code(TRI_ERROR_NO_ERROR), wasSynchronous(wasSynchronous) {}
explicit OperationResult(std::shared_ptr<VPackBuffer<uint8_t>> buffer) : OperationResult(TRI_ERROR_NO_ERROR, buffer) {}
explicit OperationResult(int code) : OperationResult(code, nullptr) { }
explicit OperationResult(int code)
: customTypeHandler(nullptr), code(code), wasSynchronous(false) {
if (code != TRI_ERROR_NO_ERROR) {
errorMessage = TRI_errno_string(code);
}
}
OperationResult(int code, std::string const& message)
: customTypeHandler(nullptr), errorMessage(message), code(code),
wasSynchronous(false) {
TRI_ASSERT(code != TRI_ERROR_NO_ERROR);
}
OperationResult(std::shared_ptr<VPackBuffer<uint8_t>> buffer,
VPackCustomTypeHandler* handler,
std::string const& message,
int code,
bool wasSynchronous)
: buffer(buffer), customTypeHandler(handler), errorMessage(message),
code(code), wasSynchronous(wasSynchronous) {
}
~OperationResult() {
// TODO: handle destruction of customTypeHandler
@ -60,6 +76,7 @@ struct OperationResult {
std::shared_ptr<VPackBuffer<uint8_t>> buffer;
VPackCustomTypeHandler* customTypeHandler;
std::string errorMessage;
int code;
bool wasSynchronous;
};

View File

@ -25,6 +25,7 @@
#include "Indexes/PrimaryIndex.h"
#include "Storage/Marker.h"
#include "VocBase/KeyGenerator.h"
#include "Cluster/ClusterMethods.h"
#include <velocypack/Builder.h>
#include <velocypack/Collection.h>
@ -522,7 +523,9 @@ OperationResult Transaction::documentLocal(std::string const& collectionName,
resultBuilder.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(key));
resultBuilder.close();
return OperationResult(TRI_ERROR_ARANGO_CONFLICT, resultBuilder.steal());
return OperationResult(resultBuilder.steal(), nullptr, "",
TRI_ERROR_ARANGO_CONFLICT,
options.waitForSync || document->_info.waitForSync());
}
VPackBuilder resultBuilder;
@ -530,7 +533,7 @@ OperationResult Transaction::documentLocal(std::string const& collectionName,
resultBuilder.add(VPackSlice(mptr.vpack()));
}
return OperationResult(resultBuilder.steal(), StorageOptions::getCustomTypeHandler(_vocbase));
return OperationResult(resultBuilder.steal(), StorageOptions::getCustomTypeHandler(_vocbase), "", TRI_ERROR_NO_ERROR, false);
}
//////////////////////////////////////////////////////////////////////////////
@ -572,8 +575,31 @@ OperationResult Transaction::insert(std::string const& collectionName,
OperationResult Transaction::insertCoordinator(std::string const& collectionName,
VPackSlice const& value,
OperationOptions& options) {
// TODO
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
std::map<std::string, std::string> headers;
arangodb::rest::HttpResponse::HttpResponseCode responseCode;
std::map<std::string, std::string> resultHeaders;
std::string resultBody;
int res = arangodb::createDocumentOnCoordinator(
_vocbase->_name, collectionName, options.waitForSync,
value, headers, responseCode, resultHeaders, resultBody);
if (res == TRI_ERROR_NO_ERROR) {
VPackParser parser;
try {
parser.parse(resultBody);
auto bui = parser.steal();
auto buf = bui->steal();
return OperationResult(buf, nullptr, "", TRI_ERROR_NO_ERROR,
responseCode == arangodb::rest::HttpResponse::CREATED);
}
catch (VPackException& e) {
std::string message = "JSON from DBserver not parseable: "
+ resultBody + ":" + e.what();
return OperationResult(TRI_ERROR_INTERNAL, message);
}
}
return OperationResult(res);
}
//////////////////////////////////////////////////////////////////////////////
@ -654,7 +680,8 @@ OperationResult Transaction::insertLocal(std::string const& collectionName,
resultBuilder.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(resultKey));
resultBuilder.close();
return OperationResult(resultBuilder.steal(), options.waitForSync);
return OperationResult(resultBuilder.steal(), nullptr, "", TRI_ERROR_NO_ERROR,
options.waitForSync || document->_info.waitForSync());
}
//////////////////////////////////////////////////////////////////////////////
@ -790,7 +817,8 @@ OperationResult Transaction::updateLocal(std::string const& collectionName,
resultBuilder.add("_oldRev", VPackValue(idString));
resultBuilder.close();
return OperationResult(resultBuilder.steal(), options.waitForSync);
return OperationResult(resultBuilder.steal(), nullptr, "", TRI_ERROR_NO_ERROR,
options.waitForSync || document->_info.waitForSync());
}
//////////////////////////////////////////////////////////////////////////////
@ -1052,6 +1080,7 @@ OperationResult Transaction::removeLocal(std::string const& collectionName,
resultBuilder.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(key));
resultBuilder.close();
return OperationResult(resultBuilder.steal(), options.waitForSync);
return OperationResult(resultBuilder.steal(), nullptr, "", TRI_ERROR_NO_ERROR,
options.waitForSync || document->_info.waitForSync());
}