1
0
Fork 0
arangodb/arangod/Agency/v8-agency.cpp

201 lines
6.2 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 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 Kaveh Vahedipour
////////////////////////////////////////////////////////////////////////////////
#include "v8-agency.h"
#include <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>
#include "Agency/AgencyFeature.h"
#include "Agency/Agent.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Logger/LogMacros.h"
#include "V8/v8-buffer.h"
#include "V8/v8-conv.h"
#include "V8/v8-globals.h"
#include "V8/v8-utils.h"
#include "V8/v8-vpack.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::consensus;
static void JS_EnabledAgent(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
auto& server = ApplicationServer::server();
TRI_V8_RETURN(v8::Boolean::New(isolate, server.isEnabled<AgencyFeature>()));
TRI_V8_TRY_CATCH_END
}
static void JS_LeadingAgent(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
Agent* agent = nullptr;
try {
auto& server = ApplicationServer::server();
AgencyFeature& feature = server.getEnabledFeature<AgencyFeature>();
agent = feature.agent();
} catch (std::exception const& e) {
TRI_V8_THROW_EXCEPTION_MESSAGE(
TRI_ERROR_INTERNAL, std::string("couldn't access agency feature: ") + e.what());
}
v8::Handle<v8::Object> r = v8::Object::New(isolate);
r->Set(TRI_V8_ASCII_STRING(isolate, "leading"),
v8::Boolean::New(isolate, agent->leading()));
TRI_V8_RETURN(r);
TRI_V8_TRY_CATCH_END
}
static void JS_ReadAgent(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
Agent* agent = nullptr;
try {
auto& server = ApplicationServer::server();
AgencyFeature& feature = server.getEnabledFeature<AgencyFeature>();
agent = feature.agent();
} catch (std::exception const& e) {
TRI_V8_THROW_EXCEPTION_MESSAGE(
TRI_ERROR_INTERNAL, std::string("couldn't access agency feature: ") + e.what());
}
query_t query = std::make_shared<Builder>();
int res = TRI_V8ToVPack(isolate, *query, args[0], false);
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);
}
read_ret_t ret = agent->read(query);
if (ret.accepted) { // Leading
TRI_V8_RETURN(TRI_VPackToV8(isolate, ret.result->slice()));
} else { // Not leading
TRI_V8_RETURN_FALSE();
}
TRI_V8_TRY_CATCH_END
}
static void JS_WriteAgent(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
Agent* agent = nullptr;
try {
auto& server = ApplicationServer::server();
AgencyFeature& feature = server.getEnabledFeature<AgencyFeature>();
agent = feature.agent();
} catch (std::exception const& e) {
TRI_V8_THROW_EXCEPTION_MESSAGE(
TRI_ERROR_INTERNAL, std::string("couldn't access agency feature: ") + e.what());
}
query_t query = std::make_shared<Builder>();
int res = TRI_V8ToVPack(isolate, *query, args[0], false);
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);
}
write_ret_t ret = agent->write(query);
if (ret.accepted) { // Leading
Builder body;
body.openObject();
body.add("results", VPackValue(VPackValueType::Array));
for (auto const& index : ret.indices) {
body.add(VPackValue(index));
}
body.close();
body.close();
// Wait for commit of highest except if it is 0?
arangodb::consensus::index_t max_index = 0;
try {
max_index = *std::max_element(ret.indices.begin(), ret.indices.end());
} catch (std::exception const& e) {
LOG_TOPIC("bfcc6", WARN, Logger::AGENCY) << e.what();
}
if (max_index > 0) {
agent->waitFor(max_index);
}
TRI_V8_RETURN(TRI_VPackToV8(isolate, body.slice()));
} else { // Not leading
TRI_V8_RETURN_FALSE();
}
TRI_V8_TRY_CATCH_END
}
void TRI_InitV8Agency(v8::Isolate* isolate, v8::Handle<v8::Context> context) {
TRI_V8_CURRENT_GLOBALS_AND_SCOPE;
TRI_ASSERT(v8g != nullptr);
v8::Handle<v8::ObjectTemplate> rt;
v8::Handle<v8::FunctionTemplate> ft;
// ...........................................................................
// generate the agency template
// ...........................................................................
ft = v8::FunctionTemplate::New(isolate);
ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoAgent"));
rt = ft->InstanceTemplate();
rt->SetInternalFieldCount(2);
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "enabled"), JS_EnabledAgent);
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "leading"), JS_LeadingAgent);
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "read"), JS_ReadAgent);
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "write"), JS_WriteAgent);
v8g->AgentTempl.Reset(isolate, rt);
ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoAgentCtor"));
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "ArangoAgentCtor"),
ft->GetFunction(), true);
// register the global object
v8::Handle<v8::Object> aa = rt->NewInstance();
if (!aa.IsEmpty()) {
TRI_AddGlobalVariableVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "ArangoAgent"), aa);
}
}