1
0
Fork 0
arangodb/arangod/V8Server/v8-replication.cpp

725 lines
25 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// 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 Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#include "v8-replication.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/ReadLocker.h"
#include "Cluster/ClusterFeature.h"
#include "Logger/Logger.h"
#include "Replication/DatabaseTailingSyncer.h"
#include "Replication/DatabaseInitialSyncer.h"
#include "Replication/DatabaseReplicationApplier.h"
#include "Replication/GlobalInitialSyncer.h"
#include "Replication/GlobalReplicationApplier.h"
#include "Replication/ReplicationApplierConfiguration.h"
#include "Replication/ReplicationFeature.h"
#include "Rest/Version.h"
#include "RestServer/DatabaseFeature.h"
#include "RestServer/ServerIdFeature.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "StorageEngine/StorageEngine.h"
#include "Transaction/V8Context.h"
#include "Utils/DatabaseGuard.h"
#include "V8/v8-conv.h"
#include "V8/v8-globals.h"
#include "V8/v8-utils.h"
#include "V8/v8-vpack.h"
#include "V8Server/v8-vocbaseprivate.h"
#include <velocypack/Builder.h>
#include <velocypack/Parser.h>
#include <velocypack/Slice.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;
////////////////////////////////////////////////////////////////////////////////
/// @brief get the state of the replication logger
////////////////////////////////////////////////////////////////////////////////
static void JS_StateLoggerReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
// FIXME: use code in RestReplicationHandler and get rid of storage-engine
// depended code here
//
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
StorageEngine* engine = EngineSelectorFeature::ENGINE;
v8::Handle<v8::Object> result = v8::Object::New(isolate);
VPackBuilder builder;
auto res = engine->createLoggerState(nullptr,builder);
if(res.fail()){
TRI_V8_THROW_EXCEPTION(res);
}
v8::Handle<v8::Value>resultValue = TRI_VPackToV8(isolate, builder.slice());
result = v8::Handle<v8::Object>::Cast(resultValue);
TRI_V8_RETURN(result);
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the tick ranges that can be provided by the replication logger
////////////////////////////////////////////////////////////////////////////////
static void JS_TickRangesLoggerReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
v8::Handle<v8::Array> result;
VPackBuilder builder;
Result res = EngineSelectorFeature::ENGINE->createTickRanges(builder);
if (res.fail()) {
TRI_V8_THROW_EXCEPTION(res);
}
v8::Handle<v8::Value>resultValue = TRI_VPackToV8(isolate, builder.slice());
result = v8::Handle<v8::Array>::Cast(resultValue);
TRI_V8_RETURN(result);
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the first tick that can be provided by the replication logger
////////////////////////////////////////////////////////////////////////////////
static void JS_FirstTickLoggerReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
TRI_voc_tick_t tick = UINT64_MAX;
Result res = EngineSelectorFeature::ENGINE->firstTick(tick);
if(res.fail()){
TRI_V8_THROW_EXCEPTION(res);
}
if (tick == UINT64_MAX) {
TRI_V8_RETURN(v8::Null(isolate));
}
TRI_V8_RETURN(TRI_V8UInt64String<TRI_voc_tick_t>(isolate, tick));
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the last WAL entries
////////////////////////////////////////////////////////////////////////////////
static void JS_LastLoggerReplication( v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
TRI_vocbase_t* vocbase = GetContextVocBase(isolate);
if (vocbase == nullptr) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
if (args.Length() != 2) {
TRI_V8_THROW_EXCEPTION_USAGE("REPLICATION_LOGGER_LAST(<fromTick>, <toTick>)");
}
TRI_voc_tick_t tickStart = TRI_ObjectToUInt64(args[0], true);
TRI_voc_tick_t tickEnd = TRI_ObjectToUInt64(args[1], true);
if (tickEnd <= tickStart) {
TRI_V8_THROW_EXCEPTION_USAGE("tickStart < tickEnd");
}
auto transactionContext = transaction::V8Context::Create(vocbase, false);
auto builderSPtr = std::make_shared<VPackBuilder>();
Result res = EngineSelectorFeature::ENGINE->lastLogger(
vocbase, transactionContext, tickStart, tickEnd, builderSPtr);
v8::Handle<v8::Value> result;
if(res.fail()){
result = v8::Null(isolate);
TRI_V8_THROW_EXCEPTION(res);
}
result = TRI_VPackToV8(isolate, builderSPtr->slice(),
transactionContext->getVPackOptions());
TRI_V8_RETURN(result);
TRI_V8_TRY_CATCH_END
}
enum ApplierType {
APPLIER_DATABASE,
APPLIER_GLOBAL
};
////////////////////////////////////////////////////////////////////////////////
/// @brief sync data from a remote master
////////////////////////////////////////////////////////////////////////////////
static void SynchronizeReplication(
v8::FunctionCallbackInfo<v8::Value> const& args,
ApplierType applierType) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
if (args.Length() != 1 || !args[0]->IsObject()) {
TRI_V8_THROW_EXCEPTION_USAGE("synchronize(<configuration>)");
}
// treat the argument as an object from now on
v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(args[0]);
VPackBuilder builder;
int res = TRI_V8ToVPack(isolate, builder, args[0], false);
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);
}
TRI_vocbase_t* vocbase = GetContextVocBase(isolate);
if (vocbase == nullptr) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
std::string databaseName;
if (applierType == APPLIER_DATABASE) {
databaseName = vocbase->name();
}
bool keepBarrier = false;
if (object->Has(TRI_V8_ASCII_STRING(isolate, "keepBarrier"))) {
keepBarrier =
TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING(isolate, "keepBarrier")));
}
ReplicationApplierConfiguration configuration = ReplicationApplierConfiguration::fromVelocyPack(builder.slice(), databaseName);
configuration.validate();
v8::Handle<v8::Object> result = v8::Object::New(isolate);
std::unique_ptr<InitialSyncer> syncer;
if (applierType == APPLIER_DATABASE) {
// database-specific synchronization
syncer.reset(new DatabaseInitialSyncer(*vocbase, configuration));
if (object->Has(TRI_V8_ASCII_STRING(isolate, "leaderId"))) {
syncer->setLeaderId(TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING(isolate, "leaderId"))));
}
} else if (applierType == APPLIER_GLOBAL) {
configuration._skipCreateDrop = false;
syncer.reset(new GlobalInitialSyncer(configuration));
} else {
TRI_ASSERT(false);
}
try {
Result r = syncer->run(configuration._incremental);
if (r.fail()) {
LOG_TOPIC(ERR, Logger::REPLICATION) << "initial sync failed for database '" << vocbase->name() << "': " << r.errorMessage();
TRI_V8_THROW_EXCEPTION_MESSAGE(r.errorNumber(), "cannot sync from remote endpoint: " + r.errorMessage() +
". last progress message was '" + syncer->progress() + "'");
}
if (keepBarrier) {
result->Set(TRI_V8_ASCII_STRING(isolate, "barrierId"),
TRI_V8UInt64String<TRI_voc_tick_t>(isolate, syncer->stealBarrier()));
}
result->Set(TRI_V8_ASCII_STRING(isolate, "lastLogTick"),
TRI_V8UInt64String<TRI_voc_tick_t>(isolate, syncer->getLastLogTick()));
std::map<TRI_voc_cid_t, std::string>::const_iterator it;
std::map<TRI_voc_cid_t, std::string> const& c =
syncer->getProcessedCollections();
uint32_t j = 0;
v8::Handle<v8::Array> collections = v8::Array::New(isolate);
for (it = c.begin(); it != c.end(); ++it) {
std::string const cidString = StringUtils::itoa((*it).first);
v8::Handle<v8::Object> ci = v8::Object::New(isolate);
ci->Set(TRI_V8_ASCII_STRING(isolate, "id"), TRI_V8_STD_STRING(isolate, cidString));
ci->Set(TRI_V8_ASCII_STRING(isolate, "name"), TRI_V8_STD_STRING(isolate, (*it).second));
collections->Set(j++, ci);
}
result->Set(TRI_V8_ASCII_STRING(isolate, "collections"), collections);
} catch (arangodb::basics::Exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(ex.code(), std::string("cannot sync from remote endpoint: ") + ex.what() + ". last progress message was '" + syncer->progress() + "'");
} catch (std::exception const& ex) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, std::string("cannot sync from remote endpoint: ") + ex.what() + ". last progress message was '" + syncer->progress() + "'");
} catch (...) {
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, std::string("cannot sync from remote endpoint: unknown exception. last progress message was '") + syncer->progress() + "'");
}
// Now check forSynchronousReplication flag and tell ClusterInfo
// about a new follower.
TRI_V8_RETURN(result);
TRI_V8_TRY_CATCH_END
}
static void JS_SynchronizeReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
SynchronizeReplication(args, APPLIER_DATABASE);
}
static void JS_SynchronizeGlobalReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
SynchronizeReplication(args, APPLIER_GLOBAL);
}
/// @brief finalize the synchronization of a collection by tailing the WAL
/// and filtering on the collection name until no more data is available
static void JS_SynchronizeReplicationFinalize(
v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
if (args.Length() != 1 || !args[0]->IsObject()) {
TRI_V8_THROW_EXCEPTION_USAGE("syncCollectionFinalize(<configure>)");
}
// treat the argument as an object from now on
v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(args[0]);
VPackBuilder builder;
int res = TRI_V8ToVPack(isolate, builder, args[0], false);
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);
}
std::string database;
if (object->Has(TRI_V8_ASCII_STRING(isolate, "database"))) {
database = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING(isolate, "database")));
}
if (database.empty()) {
TRI_V8_THROW_EXCEPTION_PARAMETER("<database> must be a valid database name");
}
std::string collection;
if (object->Has(TRI_V8_ASCII_STRING(isolate, "collection"))) {
collection = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING(isolate, "collection")));
}
if (collection.empty()) {
TRI_V8_THROW_EXCEPTION_PARAMETER("<collection> must be a valid collection name");
}
TRI_voc_tick_t fromTick = 0;
if (object->Has(TRI_V8_ASCII_STRING(isolate, "from"))) {
fromTick = TRI_ObjectToUInt64(object->Get(TRI_V8_ASCII_STRING(isolate, "from")), true);
}
if (fromTick == 0) {
TRI_V8_THROW_EXCEPTION_PARAMETER("<from> must be a valid start tick");
}
ReplicationApplierConfiguration configuration = ReplicationApplierConfiguration::fromVelocyPack(builder.slice(), database);
// will throw if invalid
configuration.validate();
DatabaseGuard guard(database);
DatabaseTailingSyncer syncer(guard.database(), configuration, fromTick, true, 0);
if (object->Has(TRI_V8_ASCII_STRING(isolate, "leaderId"))) {
syncer.setLeaderId(TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING(isolate, "leaderId"))));
}
v8::Handle<v8::Object> result = v8::Object::New(isolate);
Result r;
try {
r = syncer.syncCollectionFinalize(collection);
} catch (arangodb::basics::Exception const& ex) {
r = Result(ex.code(), ex.what());
} catch (std::exception const& ex) {
r = Result(TRI_ERROR_INTERNAL, ex.what());
} catch (...) {
r = Result(TRI_ERROR_INTERNAL, "unknown exception");
}
if (r.fail()) {
LOG_TOPIC(ERR, Logger::REPLICATION) << "syncCollectionFinalize failed: " << r.errorMessage();
std::string errorMsg = std::string("cannot sync data for shard '") + collection +
"' from remote endpoint: " + r.errorMessage();
TRI_V8_THROW_EXCEPTION_MESSAGE(r.errorNumber(), errorMsg);
}
TRI_V8_RETURN(result);
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the server's id
////////////////////////////////////////////////////////////////////////////////
static void JS_ServerIdReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
std::string const serverId = StringUtils::itoa(ServerIdFeature::getId());
TRI_V8_RETURN_STD_STRING(serverId);
TRI_V8_TRY_CATCH_END
}
static ReplicationApplier* getContinuousApplier(v8::Isolate* isolate,
ApplierType applierType) {
ReplicationApplier* applier = nullptr;
if (applierType == APPLIER_DATABASE) {
// database-specific applier
TRI_vocbase_t* vocbase = GetContextVocBase(isolate);
if (vocbase == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
applier = vocbase->replicationApplier();
} else {
// applier type global
auto replicationFeature = application_features::ApplicationServer::getFeature<ReplicationFeature>("Replication");
applier = replicationFeature->globalReplicationApplier();
}
if (applier == nullptr) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "unable to find replicationApplier");
}
return applier;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief configure the replication applier manually
////////////////////////////////////////////////////////////////////////////////
static void ConfigureApplierReplication(v8::FunctionCallbackInfo<v8::Value> const& args,
ApplierType applierType) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ReplicationApplier* applier = getContinuousApplier(isolate, applierType);
// get current configuration
ReplicationApplierConfiguration configuration = applier->configuration();
if (args.Length() == 0) {
// no argument: return the current configuration
VPackBuilder builder;
builder.openObject();
configuration.toVelocyPack(builder, true, true);
builder.close();
v8::Handle<v8::Value> result = TRI_VPackToV8(isolate, builder.slice());
TRI_V8_RETURN(result);
}
else {
// set the configuration
if (args.Length() != 1 || !args[0]->IsObject()) {
TRI_V8_THROW_EXCEPTION_USAGE(
"properties(<properties>)");
}
VPackBuilder builder;
int res = TRI_V8ToVPack(isolate, builder, args[0], false);
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);
}
std::string databaseName;
if (applierType == APPLIER_DATABASE) {
TRI_vocbase_t* vocbase = GetContextVocBase(isolate);
if (vocbase == nullptr) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
databaseName = vocbase->name();
}
// merge the passed configuration into the existing one
configuration = ReplicationApplierConfiguration::fromVelocyPack(configuration, builder.slice(), databaseName);
// will throw if invalid
configuration.validate();
// finally store the new configuration
applier->reconfigure(configuration);
// and return it
builder.clear();
builder.openObject();
configuration.toVelocyPack(builder, true, true);
builder.close();
v8::Handle<v8::Value> result = TRI_VPackToV8(isolate, builder.slice());
TRI_V8_RETURN(result);
}
TRI_V8_TRY_CATCH_END
}
static void JS_ConfigureApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
ConfigureApplierReplication(args, APPLIER_DATABASE);
}
static void JS_ConfigureGlobalApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
ConfigureApplierReplication(args, APPLIER_GLOBAL);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief start the replication applier manually
////////////////////////////////////////////////////////////////////////////////
static void StartApplierReplication(v8::FunctionCallbackInfo<v8::Value> const& args,
ApplierType applierType) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
if (args.Length() > 2) {
TRI_V8_THROW_EXCEPTION_USAGE("start(<from>)");
}
TRI_voc_tick_t initialTick = 0;
bool useTick = false;
if (args.Length() >= 1) {
initialTick = TRI_ObjectToUInt64(args[0], true);
useTick = true;
}
TRI_voc_tick_t barrierId = 0;
if (args.Length() >= 2) {
barrierId = TRI_ObjectToUInt64(args[1], true);
}
ReplicationApplier* applier = getContinuousApplier(isolate, applierType);
applier->startTailing(initialTick, useTick, barrierId);
TRI_V8_RETURN_TRUE();
TRI_V8_TRY_CATCH_END
}
static void JS_StartApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
StartApplierReplication(args, APPLIER_DATABASE);
}
static void JS_StartGlobalApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
StartApplierReplication(args, APPLIER_GLOBAL);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief shuts down the replication applier manually
////////////////////////////////////////////////////////////////////////////////
static void StopApplierReplication(v8::FunctionCallbackInfo<v8::Value> const& args,
ApplierType applierType) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("stop()");
}
ReplicationApplier* applier = getContinuousApplier(isolate, applierType);
applier->stopAndJoin();
TRI_V8_RETURN_TRUE();
TRI_V8_TRY_CATCH_END
}
static void JS_StopApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
StopApplierReplication(args, APPLIER_DATABASE);
}
static void JS_StopGlobalApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
StopApplierReplication(args, APPLIER_GLOBAL);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the state of the replication applier
////////////////////////////////////////////////////////////////////////////////
static void StateApplierReplication(v8::FunctionCallbackInfo<v8::Value> const& args,
ApplierType applierType) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("state()");
}
ReplicationApplier* applier = getContinuousApplier(isolate, applierType);
VPackBuilder builder;
builder.openObject();
applier->toVelocyPack(builder);
builder.close();
v8::Handle<v8::Value> result = TRI_VPackToV8(isolate, builder.slice());
TRI_V8_RETURN(result);
TRI_V8_TRY_CATCH_END
}
static void JS_StateApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
StateApplierReplication(args, APPLIER_DATABASE);
}
static void JS_StateGlobalApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
StateApplierReplication(args, APPLIER_GLOBAL);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief stop the replication applier and "forget" all state
////////////////////////////////////////////////////////////////////////////////
static void ForgetApplierReplication(v8::FunctionCallbackInfo<v8::Value> const& args,
ApplierType applierType) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("forget()");
}
ReplicationApplier* applier = getContinuousApplier(isolate, applierType);
applier->forget();
TRI_V8_RETURN_TRUE();
TRI_V8_TRY_CATCH_END
}
static void JS_ForgetApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
ForgetApplierReplication(args, APPLIER_DATABASE);
}
static void JS_ForgetGlobalApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
ForgetApplierReplication(args, APPLIER_GLOBAL);
}
static void JS_FailoverEnabledGlobalApplierReplication(
v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
auto replicationFeature = ReplicationFeature::INSTANCE;
if (replicationFeature != nullptr &&
replicationFeature->isActiveFailoverEnabled()) {
TRI_V8_RETURN_TRUE();
}
TRI_V8_RETURN_FALSE();
TRI_V8_TRY_CATCH_END
}
void TRI_InitV8Replication(v8::Isolate* isolate,
v8::Handle<v8::Context> context,
TRI_vocbase_t* vocbase,
size_t threadNumber, TRI_v8_global_t* v8g) {
// replication functions. not intended to be used by end users
// logger functions
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "REPLICATION_LOGGER_STATE"),
JS_StateLoggerReplication, true);
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "REPLICATION_LOGGER_LAST"),
JS_LastLoggerReplication, true);
TRI_AddGlobalFunctionVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "REPLICATION_LOGGER_TICK_RANGES"),
JS_TickRangesLoggerReplication, true);
TRI_AddGlobalFunctionVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "REPLICATION_LOGGER_FIRST_TICK"),
JS_FirstTickLoggerReplication, true);
// applier functions
TRI_AddGlobalFunctionVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "REPLICATION_APPLIER_CONFIGURE"),
JS_ConfigureApplierReplication, true);
TRI_AddGlobalFunctionVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "GLOBAL_REPLICATION_APPLIER_CONFIGURE"),
JS_ConfigureGlobalApplierReplication, true);
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "REPLICATION_APPLIER_START"),
JS_StartApplierReplication, true);
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "GLOBAL_REPLICATION_APPLIER_START"),
JS_StartGlobalApplierReplication, true);
TRI_AddGlobalFunctionVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "REPLICATION_APPLIER_STOP"),
JS_StopApplierReplication, true);
TRI_AddGlobalFunctionVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "GLOBAL_REPLICATION_APPLIER_STOP"),
JS_StopGlobalApplierReplication, true);
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "REPLICATION_APPLIER_STATE"),
JS_StateApplierReplication, true);
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "GLOBAL_REPLICATION_APPLIER_STATE"),
JS_StateGlobalApplierReplication, true);
TRI_AddGlobalFunctionVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "REPLICATION_APPLIER_FORGET"),
JS_ForgetApplierReplication, true);
TRI_AddGlobalFunctionVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "GLOBAL_REPLICATION_APPLIER_FORGET"),
JS_ForgetGlobalApplierReplication, true);
TRI_AddGlobalFunctionVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "GLOBAL_REPLICATION_APPLIER_FAILOVER_ENABLED"),
JS_FailoverEnabledGlobalApplierReplication, true);
// other functions
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "REPLICATION_SYNCHRONIZE"),
JS_SynchronizeReplication, true);
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "GLOBAL_REPLICATION_SYNCHRONIZE"),
JS_SynchronizeGlobalReplication, true);
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "REPLICATION_SYNCHRONIZE_FINALIZE"),
JS_SynchronizeReplicationFinalize, true);
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate, "REPLICATION_SERVER_ID"),
JS_ServerIdReplication, true);
}