1
0
Fork 0

Replace rocksdb export cursor with query (#5657)

This commit is contained in:
Simon 2018-06-25 18:14:27 +02:00 committed by Jan
parent 83bbd403b2
commit 8c48fdf4ab
10 changed files with 159 additions and 530 deletions

View File

@ -681,31 +681,38 @@ describe ArangoDB do
end
it "calls wrong cursor API" do
cmd = api + "?collection=#{@cn}"
body = "{ \"count\" : true, \"batchSize\" : 100, \"flush\" : true }"
doc = ArangoDB.log_post("#{prefix}-limit-return", cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(201)
doc.parsed_response['id'].should be_kind_of(String)
doc.parsed_response['id'].should match(@reId)
doc.parsed_response['hasMore'].should eq(true)
doc.parsed_response['count'].should eq(2000)
doc.parsed_response['result'].length.should eq(100)
id = doc.parsed_response['id']
cmd = "/_api/engine"
doc = ArangoDB.log_get("#{prefix}-limit-return", cmd)
doc.code.should eq(200)
if doc.parsed_response['name'] != 'rocksdb'
cmd = api + "?collection=#{@cn}"
body = "{ \"count\" : true, \"batchSize\" : 100, \"flush\" : true }"
doc = ArangoDB.log_post("#{prefix}-limit-return", cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(201)
doc.parsed_response['id'].should be_kind_of(String)
doc.parsed_response['id'].should match(@reId)
doc.parsed_response['hasMore'].should eq(true)
doc.parsed_response['count'].should eq(2000)
doc.parsed_response['result'].length.should eq(100)
# intentionally wrong
cmd = "/_api/cursor/#{id}"
doc = ArangoDB.log_put("#{prefix}-return-cont", cmd)
doc.code.should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(404)
doc.parsed_response['errorNum'].should eq(1600)
id = doc.parsed_response['id']
# intentionally wrong
cmd = "/_api/cursor/#{id}"
doc = ArangoDB.log_put("#{prefix}-return-cont", cmd)
doc.code.should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(404)
doc.parsed_response['errorNum'].should eq(1600)
end
end
end

View File

@ -121,6 +121,7 @@ class Query {
return _profile.get();
}
velocypack::Slice optionsSlice() const { return _options->slice(); }
TEST_VIRTUAL QueryOptions const& queryOptions() const { return _queryOptions; }
void increaseMemoryUsage(size_t value) { _resourceMonitor.increaseMemoryUsage(value); }
@ -348,10 +349,10 @@ class Query {
/// @brief bind parameters for the query
BindParameters _bindParameters;
/// @brief query options
/// @brief raw query options
std::shared_ptr<arangodb::velocypack::Builder> _options;
/// @brief query options
/// @brief parsed query options
QueryOptions _queryOptions;
/// @brief collections used in the query

View File

@ -152,7 +152,7 @@ QueryStreamCursor::QueryStreamCursor(
)
: Cursor(id, batchSize, ttl, /*hasCount*/ false),
_guard(vocbase),
_queryString(query) {
_exportCount(-1) {
TRI_ASSERT(QueryRegistryFeature::QUERY_REGISTRY != nullptr);
auto prevLockHeaders = CollectionLockState::_noLockHeaders;
TRI_DEFER(CollectionLockState::_noLockHeaders = prevLockHeaders);
@ -160,14 +160,30 @@ QueryStreamCursor::QueryStreamCursor(
_query = std::make_unique<Query>(
false,
_guard.database(),
aql::QueryString(_queryString.c_str(), _queryString.length()),
aql::QueryString(query),
std::move(bindVars),
std::move(opts),
arangodb::aql::PART_MAIN
);
_query->prepare(QueryRegistryFeature::QUERY_REGISTRY, aql::Query::DontCache);
TRI_ASSERT(_query->state() == aql::QueryExecutionState::ValueType::EXECUTION);
// we replaced the rocksdb export cursor with a stream AQL query
// for this case we need to support printing the collection "count"
if (_query->optionsSlice().hasKey("exportCollection")) {
std::string cname = _query->optionsSlice().get("exportCollection").copyString();
TRI_ASSERT(_query->trx()->status() == transaction::Status::RUNNING);
OperationResult opRes = _query->trx()->count(cname, true);
if (opRes.fail()) {
THROW_ARANGO_EXCEPTION(opRes.result);
}
_exportCount = opRes.slice().getInt();
VPackSlice limit = _query->bindParameters()->slice().get("limit");
if (limit.isInteger()) {
_exportCount = std::min(limit.getInt(), _exportCount);
}
}
// If we have set _noLockHeaders, we need to unset it:
if (CollectionLockState::_noLockHeaders != nullptr &&
CollectionLockState::_noLockHeaders == _query->engine()->lockedShards()) {
@ -195,7 +211,7 @@ Result QueryStreamCursor::dump(VPackBuilder& builder) {
TRI_DEFER(CollectionLockState::_noLockHeaders = prevLockHeaders);
LOG_TOPIC(TRACE, Logger::QUERIES) << "executing query " << _id << ": '"
<< _queryString.substr(1024) << "'";
<< _query->queryString().extract(1024) << "'";
VPackOptions const* oldOptions = builder.options;
TRI_DEFER(builder.options = oldOptions);
@ -241,7 +257,9 @@ Result QueryStreamCursor::dump(VPackBuilder& builder) {
if (hasMore) {
builder.add("id", VPackValue(std::to_string(id())));
}
if (_exportCount >= 0) { // this is coming from /_api/export
builder.add("count", VPackValue(_exportCount));
}
builder.add("cached", VPackValue(false));
} catch (...) {
delete value;
@ -250,7 +268,7 @@ Result QueryStreamCursor::dump(VPackBuilder& builder) {
if (!hasMore) {
QueryResult result;
_query->finalize(result);
_query->finalize(result); // will commit transaction
if (result.extra && result.extra->slice().isObject()) {
builder.add("extra", result.extra->slice());
}

View File

@ -105,7 +105,7 @@ class QueryStreamCursor final : public arangodb::Cursor {
private:
DatabaseGuard _guard;
std::string _queryString;
int64_t _exportCount; // used by RocksDBRestExportHandler
std::unique_ptr<aql::Query> _query;
};

View File

@ -45,7 +45,6 @@ set(ROCKSDB_SOURCES
RocksDBEngine/RocksDBComparator.cpp
RocksDBEngine/RocksDBEdgeIndex.cpp
RocksDBEngine/RocksDBEngine.cpp
RocksDBEngine/RocksDBExportCursor.cpp
RocksDBEngine/RocksDBFulltextIndex.cpp
RocksDBEngine/RocksDBGeoIndex.cpp
RocksDBEngine/RocksDBHashIndex.cpp

View File

@ -1,193 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 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 Daniel H. Larkin
////////////////////////////////////////////////////////////////////////////////
#include "RocksDBEngine/RocksDBExportCursor.h"
#include "Basics/WriteLocker.h"
#include "Indexes/IndexIterator.h"
#include "Logger/Logger.h"
#include "RocksDBEngine/RocksDBCollection.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "StorageEngine/PhysicalCollection.h"
#include "StorageEngine/StorageEngine.h"
#include "Transaction/Hints.h"
#include "Transaction/StandaloneContext.h"
#include "Utils/SingleCollectionTransaction.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/vocbase.h"
#include <velocypack/Builder.h>
#include <velocypack/Dumper.h>
#include <velocypack/Iterator.h>
#include <velocypack/Options.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
RocksDBExportCursor::RocksDBExportCursor(
TRI_vocbase_t& vocbase,
std::string const& name,
CollectionExport::Restrictions const& restrictions,
CursorId id,
size_t limit,
size_t batchSize,
double ttl,
bool hasCount
): Cursor(id, batchSize, ttl, hasCount),
_guard(vocbase),
_resolver(vocbase),
_restrictions(restrictions),
_name(name),
_trx(new SingleCollectionTransaction(
transaction::StandaloneContext::Create(vocbase),
_name,
AccessMode::Type::READ
)),
_position(0) {
Result res = _trx->begin();
if (!res.ok()) {
THROW_ARANGO_EXCEPTION(res);
}
LogicalCollection* collection = _trx->documentCollection();
TRI_ASSERT(collection != nullptr);
auto rocksColl = static_cast<RocksDBCollection*>(collection->getPhysical());
_iter = rocksColl->getAllIterator(_trx.get());
_size = collection->numberDocuments(_trx.get());
if (limit > 0 && limit < _size) {
_size = limit;
}
}
RocksDBExportCursor::~RocksDBExportCursor() {}
////////////////////////////////////////////////////////////////////////////////
/// @brief check whether the cursor contains more data
////////////////////////////////////////////////////////////////////////////////
bool RocksDBExportCursor::hasNext() {
if (_iter.get() == nullptr) {
return false;
}
return (_position < _size);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the next element (not implemented)
////////////////////////////////////////////////////////////////////////////////
VPackSlice RocksDBExportCursor::next() {
// should not be called directly
return VPackSlice();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the cursor size
////////////////////////////////////////////////////////////////////////////////
size_t RocksDBExportCursor::count() const { return _size; }
Result RocksDBExportCursor::dump(VPackBuilder& builder) {
auto ctx = transaction::StandaloneContext::Create(_guard.database());
VPackOptions const* oldOptions = builder.options;
builder.options = ctx->getVPackOptions();
TRI_ASSERT(_iter.get() != nullptr);
auto const restrictionType = _restrictions.type;
try {
builder.add("result", VPackValue(VPackValueType::Array));
size_t const n = batchSize();
auto cb = [&, this](LocalDocumentId const& token, VPackSlice slice) {
if (_position == _size) {
return false;
}
builder.openObject();
// Copy over shaped values
for (auto const& entry : VPackObjectIterator(slice)) {
std::string key(entry.key.copyString());
if (!CollectionExport::IncludeAttribute(restrictionType,
_restrictions.fields, key)) {
// Ignore everything that should be excluded or not included
continue;
}
// If we get here we need this entry in the final result
if (entry.value.isCustom()) {
builder.add(key,
VPackValue(builder.options->customTypeHandler->toString(
entry.value, builder.options, slice)));
} else {
builder.add(key, entry.value);
}
}
builder.close();
_position++;
return true;
};
_iter->nextDocument(cb, n);
builder.close(); // close Array
// builder.add("hasMore", VPackValue(hasNext() ? "true" : "false"));
// //should not be string
builder.add("hasMore", VPackValue(hasNext()));
if (hasNext()) {
builder.add("id", VPackValue(std::to_string(id())));
}
if (hasCount()) {
builder.add("count", VPackValue(static_cast<uint64_t>(count())));
}
if (!hasNext()) {
// mark the cursor as deleted
_iter.reset();
this->deleted();
}
} catch (arangodb::basics::Exception const& ex) {
return Result(ex.code(), ex.what());
} catch (std::exception const& ex) {
return Result(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
return Result(TRI_ERROR_INTERNAL, "internal error during RocksDBExportCursor::dump");
}
builder.options = oldOptions;
return Result();
}
std::shared_ptr<transaction::Context> RocksDBExportCursor::context() const {
return _trx->transactionContext(); // likely not used
}

View File

@ -1,80 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 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
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_ROCKSDB_ROCKSDB_EXPORT_CURSOR_H
#define ARANGOD_ROCKSDB_ROCKSDB_EXPORT_CURSOR_H 1
#include "Basics/Common.h"
#include "Utils/CollectionExport.h"
#include "Utils/CollectionGuard.h"
#include "Utils/CollectionNameResolver.h"
#include "Utils/Cursor.h"
#include "Utils/DatabaseGuard.h"
#include "VocBase/voc-types.h"
namespace arangodb {
class IndexIterator;
class SingleCollectionTransaction;
class RocksDBExportCursor final : public Cursor {
public:
RocksDBExportCursor(
TRI_vocbase_t& vocbase,
std::string const& name,
CollectionExport::Restrictions const& restrictions,
CursorId id,
size_t limit,
size_t batchSize,
double ttl,
bool hasCount
);
~RocksDBExportCursor();
CursorType type() const override final { return CURSOR_EXPORT; }
bool hasNext();
arangodb::velocypack::Slice next();
size_t count() const override final;
Result dump(velocypack::Builder&) override final;
std::shared_ptr<transaction::Context> context() const override final;
private:
DatabaseGuard _guard;
arangodb::CollectionNameResolver _resolver;
CollectionExport::Restrictions _restrictions;
std::string const _name;
std::unique_ptr<SingleCollectionTransaction> _trx;
std::unique_ptr<IndexIterator> _iter;
size_t _position;
size_t _size;
};
}
#endif

View File

@ -25,12 +25,14 @@
#include "Basics/Exceptions.h"
#include "Basics/MutexLocker.h"
#include "Basics/VelocyPackHelper.h"
#include "Cluster/ServerState.h"
#include "RocksDBEngine/RocksDBCommon.h"
#include "RocksDBEngine/RocksDBEngine.h"
#include "RocksDBEngine/RocksDBExportCursor.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "Transaction/StandaloneContext.h"
#include "Utils/Cursor.h"
#include "Utils/CursorRepository.h"
#include "Utils/SingleCollectionTransaction.h"
#include "VocBase/ticks.h"
#include <velocypack/Builder.h>
@ -43,8 +45,9 @@ using namespace arangodb;
using namespace arangodb::rest;
RocksDBRestExportHandler::RocksDBRestExportHandler(GeneralRequest* request,
GeneralResponse* response)
: RestVocbaseBaseHandler(request, response), _restrictions() {}
GeneralResponse* response,
aql::QueryRegistry* queryRegistry)
: RestCursorHandler(request, response, queryRegistry), _restrictions() {}
RestStatus RocksDBRestExportHandler::execute() {
if (ServerState::instance()->isCoordinator()) {
@ -63,13 +66,11 @@ RestStatus RocksDBRestExportHandler::execute() {
}
if (type == rest::RequestType::PUT) {
modifyCursor();
return RestStatus::DONE;
return RestCursorHandler::execute();
}
if (type == rest::RequestType::DELETE_REQ) {
deleteCursor();
return RestStatus::DONE;
return RestCursorHandler::execute();
}
generateError(rest::ResponseCode::METHOD_NOT_ALLOWED,
@ -81,17 +82,15 @@ RestStatus RocksDBRestExportHandler::execute() {
/// @brief build options for the query as JSON
////////////////////////////////////////////////////////////////////////////////
VPackBuilder RocksDBRestExportHandler::buildOptions(VPackSlice const& slice) {
VPackBuilder RocksDBRestExportHandler::buildQueryOptions(std::string const& cname,
VPackSlice const& slice) {
if (!slice.isObject()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
}
VPackBuilder options;
options.openObject();
VPackSlice count = slice.get("count");
if (count.isBool()) {
options.add("count", count);
} else {
options.add("count", VPackValue(false));
}
VPackSlice batchSize = slice.get("batchSize");
if (batchSize.isNumber()) {
if ((batchSize.isInteger() && batchSize.getUInt() == 0) ||
@ -103,73 +102,95 @@ VPackBuilder RocksDBRestExportHandler::buildOptions(VPackSlice const& slice) {
} else {
options.add("batchSize", VPackValue(1000));
}
VPackSlice limit = slice.get("limit");
if (limit.isNumber()) {
options.add("limit", limit);
}
VPackSlice flush = slice.get("flush");
if (flush.isBool()) {
options.add("flush", flush);
} else {
options.add("flush", VPackValue(false));
}
VPackSlice ttl = slice.get("ttl");
if (ttl.isNumber()) {
options.add("ttl", ttl);
} else {
options.add("ttl", VPackValue(30));
}
VPackSlice flushWait = slice.get("flushWait");
if (flushWait.isNumber()) {
options.add("flushWait", flushWait);
} else {
options.add("flushWait", VPackValue(10));
int64_t limit = INT64_MAX;
VPackSlice limitSlice = slice.get("limit");
if (limitSlice.isNumber()) {
limit = limitSlice.getInt();
}
options.close();
options.add("options", VPackValue(VPackValueType::Object));
options.add("stream", VPackValue(true)); // important!!
VPackSlice count = slice.get("count");
if (count.isBool() && count.getBool()) {
// QueryStreamCursor will add `exportCount` as `count`
options.add("exportCollection", VPackValue(cname));
}
options.close(); // options
std::string query = "FOR doc IN @@collection ";
options.add("bindVars", VPackValue(VPackValueType::Object));
options.add("@collection", VPackValue(cname));
if (limit != INT64_MAX) {
query.append("LIMIT @limit ");
options.add("limit", limitSlice);
}
// handle "restrict" parameter
VPackSlice restrct = slice.get("restrict");
if (!restrct.isObject()) {
if (!restrct.isNone()) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_TYPE_ERROR,
"expecting object for 'restrict'");
}
} else {
if (restrct.isObject()) {
// "restrict"."type"
VPackSlice type = restrct.get("type");
if (!type.isString()) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER,
"expecting string for 'restrict.type'");
}
std::string typeString = type.copyString();
if (typeString == "include") {
_restrictions.type = CollectionExport::Restrictions::RESTRICTION_INCLUDE;
} else if (typeString == "exclude") {
_restrictions.type = CollectionExport::Restrictions::RESTRICTION_EXCLUDE;
} else {
THROW_ARANGO_EXCEPTION_MESSAGE(
TRI_ERROR_BAD_PARAMETER,
"expecting either 'include' or 'exclude' for 'restrict.type'");
}
// "restrict"."fields"
VPackSlice fields = restrct.get("fields");
if (!fields.isArray()) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER,
"expecting array for 'restrict.fields'");
}
for (auto const& name : VPackArrayIterator(fields)) {
if (name.isString()) {
_restrictions.fields.emplace(name.copyString());
if (type.isEqualString("include")) {
if (fields.length() == 0) {
query.append("RETURN {}");
} else {
query.append("RETURN KEEP(doc");
}
} else if (type.isEqualString("exclude")) {
if (fields.length() == 0) {
query.append("RETURN doc");
} else {
query.append("RETURN UNSET(doc");
}
} else {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER,
"expecting either 'include' or 'exclude' for 'restrict.type'");
}
if (fields.length() > 0) {
// "restrict"."fields"
int i = 0;
for (auto const& name : VPackArrayIterator(fields)) {
if (name.isString()) {
std::string varName = std::string("var").append(std::to_string(i++));
query.append(", @").append(varName);
options.add(varName, VPackValue(name.copyString()));
}
}
query += ")";
}
}
} else {
if (!restrct.isNone()) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_TYPE_ERROR, "expecting object for 'restrict'");
}
query.append("RETURN doc");
}
options.close(); // bindVars
options.add("query", VPackValue(query));
options.close();
return options;
}
@ -205,147 +226,6 @@ void RocksDBRestExportHandler::createCursor() {
return;
}
VPackBuilder optionsBuilder;
if (!body.isNone()) {
if (!body.isObject()) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_QUERY_EMPTY);
return;
}
optionsBuilder = buildOptions(body);
} else {
// create an empty options object
optionsBuilder.openObject();
optionsBuilder.close();
}
VPackSlice options = optionsBuilder.slice();
size_t limit = arangodb::basics::VelocyPackHelper::getNumericValue<size_t>(
options, "limit", 0);
size_t batchSize =
arangodb::basics::VelocyPackHelper::getNumericValue<size_t>(
options, "batchSize", 1000);
double ttl = arangodb::basics::VelocyPackHelper::getNumericValue<double>(
options, "ttl", 30);
bool count = arangodb::basics::VelocyPackHelper::getBooleanValue(
options, "count", false);
auto cursors = _vocbase.cursorRepository();
TRI_ASSERT(cursors != nullptr);
Cursor* c = nullptr;
{
auto cursor = std::make_unique<RocksDBExportCursor>(
_vocbase,
name,
_restrictions,
TRI_NewTickServer(),
limit,
batchSize,
ttl,
count
);
cursor->use();
c = cursors->addCursor(std::move(cursor));
}
TRI_ASSERT(c != nullptr);
TRI_DEFER(cursors->release(c));
resetResponse(rest::ResponseCode::CREATED);
VPackBuffer<uint8_t> buffer;
VPackBuilder builder(buffer);
builder.openObject();
builder.add(StaticStrings::Error, VPackValue(false));
builder.add(StaticStrings::Code, VPackValue(static_cast<int>(ResponseCode::CREATED)));
Result r = c->dump(builder);
if (r.fail()) {
generateError(r);
return;
}
builder.close();
_response->setContentType(rest::ContentType::JSON);
generateResult(rest::ResponseCode::CREATED, std::move(buffer));
}
void RocksDBRestExportHandler::modifyCursor() {
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting PUT /_api/export/<cursor-id>");
return;
}
std::string const& id = suffixes[0];
auto cursors = _vocbase.cursorRepository();
TRI_ASSERT(cursors != nullptr);
auto cursorId = static_cast<arangodb::CursorId>(
arangodb::basics::StringUtils::uint64(id));
bool busy;
auto cursor = cursors->find(cursorId, Cursor::CURSOR_EXPORT, busy);
if (cursor == nullptr) {
if (busy) {
generateError(GeneralResponse::responseCode(TRI_ERROR_CURSOR_BUSY),
TRI_ERROR_CURSOR_BUSY);
} else {
generateError(GeneralResponse::responseCode(TRI_ERROR_CURSOR_NOT_FOUND),
TRI_ERROR_CURSOR_NOT_FOUND);
}
return;
}
TRI_DEFER(cursors->release(cursor));
VPackBuffer<uint8_t> buffer;
VPackBuilder builder(buffer);
builder.openObject();
builder.add(StaticStrings::Error, VPackValue(false));
builder.add(StaticStrings::Code, VPackValue(static_cast<int>(ResponseCode::OK)));
Result r = cursor->dump(builder);
if (r.fail()) {
generateError(r);
return;
}
builder.close();
_response->setContentType(rest::ContentType::JSON);
generateResult(rest::ResponseCode::OK, std::move(buffer));
}
void RocksDBRestExportHandler::deleteCursor() {
std::vector<std::string> const& suffixes = _request->suffixes();
if (suffixes.size() != 1) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
"expecting DELETE /_api/export/<cursor-id>");
return;
}
std::string const& id = suffixes[0];
CursorRepository* cursors = _vocbase.cursorRepository();
TRI_ASSERT(cursors != nullptr);
auto cursorId = static_cast<arangodb::CursorId>(
arangodb::basics::StringUtils::uint64(id));
bool found = cursors->remove(cursorId, Cursor::CURSOR_EXPORT);
if (!found) {
generateError(rest::ResponseCode::NOT_FOUND, TRI_ERROR_CURSOR_NOT_FOUND);
return;
}
VPackBuilder result;
result.openObject();
result.add("id", VPackValue(id));
result.add(StaticStrings::Error, VPackValue(false));
result.add(StaticStrings::Code, VPackValue(static_cast<int>(ResponseCode::ACCEPTED)));
result.close();
generateResult(rest::ResponseCode::ACCEPTED, result.slice());
VPackBuilder queryBody = buildQueryOptions(name, body);
RestCursorHandler::processQuery(queryBody.slice());
}

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -19,31 +19,34 @@
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Simon Grätzer
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_MMFILES_MMFILES_REST_EXPORT_HANDLER_H
#define ARANGOD_MMFILES_MMFILES_REST_EXPORT_HANDLER_H 1
#ifndef ARANGOD_ROCKSDB_ROCKSDB_REST_EXPORT_HANDLER_H
#define ARANGOD_ROCKSDB_ROCKSDB_REST_EXPORT_HANDLER_H 1
#include "Basics/Common.h"
#include "Basics/Mutex.h"
#include "RestHandler/RestVocbaseBaseHandler.h"
#include "RestHandler/RestCursorHandler.h"
#include "Utils/CollectionExport.h"
namespace arangodb {
class RocksDBRestExportHandler : public RestVocbaseBaseHandler {
namespace aql {
class QueryRegistry;
}
class RocksDBRestExportHandler : public RestCursorHandler {
public:
RocksDBRestExportHandler(GeneralRequest*, GeneralResponse*);
RocksDBRestExportHandler(GeneralRequest*, GeneralResponse*, aql::QueryRegistry*);
public:
RestStatus execute() override;
char const* name() const override final { return "RocksDBRestExportHandler"; }
private:
//////////////////////////////////////////////////////////////////////////////
/// @brief build options for the query as JSON
//////////////////////////////////////////////////////////////////////////////
VPackBuilder buildOptions(VPackSlice const&);
VPackBuilder buildQueryOptions(std::string const& cname, VPackSlice const&);
//////////////////////////////////////////////////////////////////////////////
/// @brief create an export cursor and return the first results
@ -51,18 +54,6 @@ class RocksDBRestExportHandler : public RestVocbaseBaseHandler {
void createCursor();
//////////////////////////////////////////////////////////////////////////////
/// @brief return the next results from an existing cursor
//////////////////////////////////////////////////////////////////////////////
void modifyCursor();
//////////////////////////////////////////////////////////////////////////////
/// @brief dispose an existing cursor
//////////////////////////////////////////////////////////////////////////////
void deleteCursor();
private:
//////////////////////////////////////////////////////////////////////////////
/// @brief restrictions for export

View File

@ -22,8 +22,11 @@
////////////////////////////////////////////////////////////////////////////////
#include "RocksDBRestHandlers.h"
#include "Aql/QueryRegistry.h"
#include "GeneralServer/RestHandlerFactory.h"
#include "RestHandler/RestHandlerCreator.h"
#include "RestServer/QueryRegistryFeature.h"
#include "RocksDBEngine/RocksDBRestExportHandler.h"
#include "RocksDBEngine/RocksDBRestReplicationHandler.h"
#include "RocksDBEngine/RocksDBRestWalHandler.h"
@ -32,9 +35,12 @@ using namespace arangodb;
void RocksDBRestHandlers::registerResources(
rest::RestHandlerFactory* handlerFactory) {
auto queryRegistry = QueryRegistryFeature::QUERY_REGISTRY;
handlerFactory->addPrefixHandler(
"/_api/export",
RestHandlerCreator<RocksDBRestExportHandler>::createNoData);
RestHandlerCreator<RocksDBRestExportHandler>::createData<aql::QueryRegistry*>,
queryRegistry);
handlerFactory->addPrefixHandler(
"/_api/replication",