Skip to content

Commit

Permalink
Feature/js to cpp transaction handler (#2985)
Browse files Browse the repository at this point in the history
* implement transaction handler in c++

* add fake request object

* move general code into extra file

* improve error messages for RestJobHandler

* support cancel operation for async jobs with RestTransactionHandler

* fix integration test and add some optional debugging output

* fix returning of context

* fix error type

* fix code in cluster test

* remove unused variable
  • Loading branch information
ObiWahn authored and jsteemann committed Aug 11, 2017
1 parent a22fcd2 commit 0eaf4ca
Show file tree
Hide file tree
Showing 16 changed files with 816 additions and 308 deletions.
2 changes: 1 addition & 1 deletion UnitTests/HttpInterface/api-transactions-cluster-spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(500)
doc.parsed_response['errorNum'].should eq(500)
doc.parsed_response['errorNum'].should eq(1650)
end
end

Expand Down
106 changes: 52 additions & 54 deletions UnitTests/HttpInterface/api-transactions-noncluster-spec.rb

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions arangod/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ SET(ARANGOD_SOURCES
RestHandler/RestShutdownHandler.cpp
RestHandler/RestSimpleHandler.cpp
RestHandler/RestSimpleQueryHandler.cpp
RestHandler/RestTransactionHandler.cpp
RestHandler/RestUploadHandler.cpp
RestHandler/RestUsersHandler.cpp
RestHandler/RestVersionHandler.cpp
Expand Down Expand Up @@ -382,6 +383,7 @@ SET(ARANGOD_SOURCES
VocBase/Methods/Collections.cpp
VocBase/Methods/Databases.cpp
VocBase/Methods/Indexes.cpp
VocBase/Methods/Transactions.cpp
VocBase/AuthInfo.cpp
VocBase/AuthUserEntry.cpp
VocBase/EdgeCollectionInfo.cpp
Expand Down
19 changes: 16 additions & 3 deletions arangod/GeneralServer/AsyncJobManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "Basics/ReadLocker.h"
#include "Basics/WriteLocker.h"
#include "Basics/voc-errors.h"
#include "GeneralServer/RestHandler.h"
#include "Logger/Logger.h"
#include "Rest/GeneralResponse.h"
Expand Down Expand Up @@ -180,13 +181,18 @@ void AsyncJobManager::deleteExpiredJobResults(double stamp) {
}
}

bool AsyncJobManager::cancelJob(AsyncJobResult::IdType jobId) {
Result AsyncJobManager::cancelJob(AsyncJobResult::IdType jobId) {
Result rv;
WRITE_LOCKER(writeLocker, _lock);

auto it = _jobs.find(jobId);

if (it == _jobs.end()) {
return false;
rv.reset(TRI_ERROR_HTTP_NOT_FOUND
, "could not find job (" + std::to_string(jobId) +
") in AsyncJobManager during cancel operation"
);
return rv;
}

bool ok = true;
Expand All @@ -196,7 +202,14 @@ bool AsyncJobManager::cancelJob(AsyncJobResult::IdType jobId) {
ok = handler->cancel();
}

return ok;
if(!ok){
// if you end up here you might need to implement the cancel method on your handler
rv.reset(TRI_ERROR_INTERNAL
,"could not cancel job (" + std::to_string(jobId) +
") in handler"
);
}
return rv;
}

std::vector<AsyncJobResult::IdType> AsyncJobManager::pending(size_t maxCount) {
Expand Down
3 changes: 2 additions & 1 deletion arangod/GeneralServer/AsyncJobManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define ARANGOD_HTTP_SERVER_ASYNC_JOB_MANAGER_H 1

#include "Basics/Common.h"
#include "Basics/Result.h"
#include "Basics/ReadWriteLock.h"

namespace arangodb {
Expand Down Expand Up @@ -82,7 +83,7 @@ class AsyncJobManager {
bool deleteJobResult(AsyncJobResult::IdType);
void deleteJobResults();
void deleteExpiredJobResults(double stamp);
bool cancelJob(AsyncJobResult::IdType);
Result cancelJob(AsyncJobResult::IdType);

std::vector<AsyncJobResult::IdType> pending(size_t maxCount);
std::vector<AsyncJobResult::IdType> done(size_t maxCount);
Expand Down
4 changes: 4 additions & 0 deletions arangod/GeneralServer/GeneralServerFeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
#include "RestHandler/RestShutdownHandler.h"
#include "RestHandler/RestSimpleHandler.h"
#include "RestHandler/RestSimpleQueryHandler.h"
#include "RestHandler/RestTransactionHandler.h"
#include "RestHandler/RestUploadHandler.h"
#include "RestHandler/RestUsersHandler.h"
#include "RestHandler/RestVersionHandler.h"
Expand Down Expand Up @@ -473,6 +474,9 @@ void GeneralServerFeature::defineHandlers() {

_handlerFactory->addHandler(
"/_api/version", RestHandlerCreator<RestVersionHandler>::createNoData);

_handlerFactory->addHandler(
"/_api/transaction", RestHandlerCreator<RestTransactionHandler>::createNoData);

#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
_handlerFactory->addHandler(
Expand Down
2 changes: 2 additions & 0 deletions arangod/GeneralServer/RestHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class RestHandler : public std::enable_shared_from_this<RestHandler> {
virtual RestStatus execute() = 0;
virtual void finalizeExecute() {}

// you might need to implment this in you handler
// if it will be executed in an async job
virtual bool cancel() {
_canceled.store(true);
return false;
Expand Down
6 changes: 3 additions & 3 deletions arangod/RestHandler/RestJobHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ void RestJobHandler::putJobMethod() {
uint64_t jobId = StringUtils::uint64(value);

if (method == "cancel") {
bool status = _jobManager->cancelJob(jobId);
Result status = _jobManager->cancelJob(jobId);

// unknown or already fetched job
if (!status) {
generateError(rest::ResponseCode::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
if (status.fail()) {
generateError(status);
} else {
VPackBuilder json;
json.add(VPackValue(VPackValueType::Object));
Expand Down
118 changes: 118 additions & 0 deletions arangod/RestHandler/RestTransactionHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Christoph Uhde
////////////////////////////////////////////////////////////////////////////////

#include "Basics/WriteLocker.h"
#include "Basics/ReadLocker.h"
#include "RestTransactionHandler.h"

#include "ApplicationFeatures/ApplicationServer.h"
#include "VocBase/Methods/Transactions.h"
#include "Rest/HttpRequest.h"
#include "Basics/voc-errors.h"
#include "V8Server/V8Context.h"
#include "V8Server/V8DealerFeature.h"

#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>

using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;

RestTransactionHandler::RestTransactionHandler(GeneralRequest* request, GeneralResponse* response)
: RestVocbaseBaseHandler(request, response)
, _v8Context(nullptr)
, _lock()
{}

void RestTransactionHandler::returnContext(){
WRITE_LOCKER(writeLock, _lock);
V8DealerFeature::DEALER->exitContext(_v8Context);
_v8Context = nullptr;
}

RestStatus RestTransactionHandler::execute() {
if (_request->requestType() != rest::RequestType::POST) {
generateError(rest::ResponseCode::METHOD_NOT_ALLOWED, 405);
return RestStatus::DONE;
}

auto slice = _request->payload();
if(!slice.isObject()){
generateError(GeneralResponse::responseCode(TRI_ERROR_BAD_PARAMETER),TRI_ERROR_BAD_PARAMETER, "could not acquire v8 context");
return RestStatus::DONE;
}

std::string portType = _request->connectionInfo().portType();

_v8Context = V8DealerFeature::DEALER->enterContext(_vocbase, true /*allow use database*/);
if (!_v8Context) {
generateError(GeneralResponse::responseCode(TRI_ERROR_INTERNAL),TRI_ERROR_INTERNAL, "could not acquire v8 context");
return RestStatus::DONE;
}

TRI_DEFER(returnContext());

VPackBuilder result;
try {
{
WRITE_LOCKER(lock, _lock);
if(_canceled){
generateCanceled();
return RestStatus::DONE;
}
}

Result res = executeTransaction(_v8Context->_isolate, _lock, _canceled, slice , portType, result);

if (res.ok()){
VPackSlice slice = result.slice();
if (slice.isNone()) {
generateSuccess(rest::ResponseCode::OK, VPackSlice::nullSlice());
} else {
generateSuccess(rest::ResponseCode::OK, slice);
}
} else {
generateError(res);
}
} catch (arangodb::basics::Exception const& ex) {
generateError(GeneralResponse::responseCode(ex.code()),ex.code(), ex.what());
} catch (std::exception const& ex) {
generateError(GeneralResponse::responseCode(TRI_ERROR_INTERNAL), TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
generateError(GeneralResponse::responseCode(TRI_ERROR_INTERNAL), TRI_ERROR_INTERNAL);
}

return RestStatus::DONE;
}

bool RestTransactionHandler::cancel() {
//cancel v8 transaction
WRITE_LOCKER(writeLock, _lock);
_canceled.store(true);
auto isolate = _v8Context->_isolate;
if (!v8::V8::IsExecutionTerminating(isolate)) {
v8::V8::TerminateExecution(isolate);
}
return true;
}
52 changes: 52 additions & 0 deletions arangod/RestHandler/RestTransactionHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Christoph Uhde
////////////////////////////////////////////////////////////////////////////////

#ifndef ARANGOD_REST_HANDLER_REST_TRANSACTION_HANDLER_H
#define ARANGOD_REST_HANDLER_REST_TRANSACTION_HANDLER_H 1

#include "Basics/ReadWriteLock.h"
#include "RestHandler/RestVocbaseBaseHandler.h"

namespace arangodb {

class V8Context;

class RestTransactionHandler : public arangodb::RestVocbaseBaseHandler {
V8Context* _v8Context;
basics::ReadWriteLock _lock;

public:
RestTransactionHandler(GeneralRequest*, GeneralResponse*);

public:
char const* name() const override final { return "RestTransactionHandler"; }
bool isDirect() const override { return false; }
RestStatus execute() override;
bool cancel() override final;

private:
void returnContext();
};
}

#endif
Loading

0 comments on commit 0eaf4ca

Please sign in to comment.