//////////////////////////////////////////////////////////////////////////////// /// @brief V8-vocbase bridge /// /// @file /// /// DISCLAIMER /// /// Copyright 2014 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 /// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany /// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #include "v8-replication.h" #include "v8-vocbaseprivate.h" #include "Replication/InitialSyncer.h" #include "V8/v8-conv.h" #include "V8/v8-globals.h" #include "V8/v8-utils.h" #include "Wal/LogfileManager.h" #include "VocBase/replication-dump.h" using namespace std; using namespace triagens::basics; using namespace triagens::arango; using namespace triagens::rest; // ----------------------------------------------------------------------------- // --SECTION-- REPLICATION // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief get the state of the replication logger //////////////////////////////////////////////////////////////////////////////// static void JS_StateLoggerReplication (const v8::FunctionCallbackInfo& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); v8::HandleScope scope(isolate); triagens::wal::LogfileManagerState s = triagens::wal::LogfileManager::instance()->state(); v8::Handle result = v8::Object::New(isolate); v8::Handle state = v8::Object::New(isolate); state->Set(TRI_V8_ASCII_STRING("running"), v8::True(isolate)); state->Set(TRI_V8_ASCII_STRING("lastLogTick"), V8TickId(isolate, s.lastTick)); state->Set(TRI_V8_ASCII_STRING("totalEvents"), v8::Number::New(isolate, (double) s.numEvents)); state->Set(TRI_V8_ASCII_STRING("time"), TRI_V8_STD_STRING(s.timeString)); result->Set(TRI_V8_ASCII_STRING("state"), state); v8::Handle server = v8::Object::New(isolate); server->Set(TRI_V8_ASCII_STRING("version"), TRI_V8_ASCII_STRING(TRI_VERSION)); server->Set(TRI_V8_ASCII_STRING("serverId"), TRI_V8_STD_STRING(StringUtils::itoa(TRI_GetIdServer()))); /// TODO result->Set(TRI_V8_ASCII_STRING("server"), server); v8::Handle clients = v8::Object::New(isolate); result->Set(TRI_V8_ASCII_STRING("clients"), clients); 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 (const v8::FunctionCallbackInfo& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); v8::HandleScope scope(isolate); auto const& ranges = triagens::wal::LogfileManager::instance()->ranges(); v8::Handle result = v8::Array::New(isolate, (int) ranges.size()); uint32_t i = 0; for (auto& it : ranges) { v8::Handle df = v8::Object::New(isolate); df->ForceSet(TRI_V8_ASCII_STRING("datafile"), TRI_V8_STD_STRING(it.filename)); df->ForceSet(TRI_V8_ASCII_STRING("state"), TRI_V8_STD_STRING(it.state)); df->ForceSet(TRI_V8_ASCII_STRING("tickMin"), V8TickId(isolate, it.tickMin)); df->ForceSet(TRI_V8_ASCII_STRING("tickMax"), V8TickId(isolate, it.tickMax)); result->Set(i++, df); } 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 (const v8::FunctionCallbackInfo& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); v8::HandleScope scope(isolate); auto const& ranges = triagens::wal::LogfileManager::instance()->ranges(); TRI_voc_tick_t tick = UINT64_MAX; for (auto& it : ranges) { if (it.tickMin == 0) { continue; } if (it.tickMin < tick) { tick = it.tickMin; } } if (tick == UINT64_MAX) { TRI_V8_RETURN(v8::Null(isolate)); } TRI_V8_RETURN(V8TickId(isolate, tick)); TRI_V8_TRY_CATCH_END } //////////////////////////////////////////////////////////////////////////////// /// @brief get the last WAL entries //////////////////////////////////////////////////////////////////////////////// static void JS_LastLoggerReplication (const v8::FunctionCallbackInfo& 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(, )"); } TRI_replication_dump_t dump(vocbase, 0, true); TRI_voc_tick_t tickStart = TRI_ObjectToUInt64(args[0], true); TRI_voc_tick_t tickEnd = TRI_ObjectToUInt64(args[1], true); int res = TRI_DumpLogReplication(&dump, std::unordered_set(), 0, tickStart, tickEnd, true); if (res != TRI_ERROR_NO_ERROR) { TRI_V8_THROW_EXCEPTION(res); } TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, dump._buffer->_buffer); if (json == nullptr) { TRI_V8_THROW_EXCEPTION_MEMORY(); } v8::Handle result = TRI_ObjectJson(isolate, json); TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); TRI_V8_RETURN(result); TRI_V8_TRY_CATCH_END } //////////////////////////////////////////////////////////////////////////////// /// @brief sync data from a remote master //////////////////////////////////////////////////////////////////////////////// static void JS_SynchroniseReplication (const v8::FunctionCallbackInfo& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); v8::HandleScope scope(isolate); if (args.Length() != 1 || ! args[0]->IsObject()) { TRI_V8_THROW_EXCEPTION_USAGE("REPLICATION_SYNCHRONISE()"); } TRI_vocbase_t* vocbase = GetContextVocBase(isolate); if (vocbase == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } // treat the argument as an object from now on v8::Handle object = v8::Handle::Cast(args[0]); string endpoint; if (object->Has(TRI_V8_ASCII_STRING("endpoint"))) { endpoint = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING("endpoint"))); } string database; if (object->Has(TRI_V8_ASCII_STRING("database"))) { database = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING("database"))); } else { database = string(vocbase->_name); } string username; if (object->Has(TRI_V8_ASCII_STRING("username"))) { username = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING("username"))); } string password; if (object->Has(TRI_V8_ASCII_STRING("password"))) { password = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING("password"))); } std::unordered_map restrictCollections; if (object->Has(TRI_V8_ASCII_STRING("restrictCollections")) && object->Get(TRI_V8_ASCII_STRING("restrictCollections"))->IsArray()) { v8::Handle a = v8::Handle::Cast(object->Get(TRI_V8_ASCII_STRING("restrictCollections"))); const uint32_t n = a->Length(); for (uint32_t i = 0; i < n; ++i) { v8::Handle cname = a->Get(i); if (cname->IsString()) { restrictCollections.emplace(std::make_pair(TRI_ObjectToString(cname), true)); } } } std::string restrictType; if (object->Has(TRI_V8_ASCII_STRING("restrictType"))) { restrictType = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING("restrictType"))); } bool verbose = true; if (object->Has(TRI_V8_ASCII_STRING("verbose"))) { verbose = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("verbose"))); } if (endpoint.empty()) { TRI_V8_THROW_EXCEPTION_PARAMETER(" must be a valid endpoint"); } if ((restrictType.empty() && ! restrictCollections.empty()) || (! restrictType.empty() && restrictCollections.empty()) || (! restrictType.empty() && restrictType != "include" && restrictType != "exclude")) { TRI_V8_THROW_EXCEPTION_PARAMETER("invalid value for or "); } TRI_replication_applier_configuration_t config; TRI_InitConfigurationReplicationApplier(&config); config._endpoint = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE, endpoint.c_str(), endpoint.size()); config._database = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE, database.c_str(), database.size()); config._username = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE, username.c_str(), username.size()); config._password = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE, password.c_str(), password.size()); if (object->Has(TRI_V8_ASCII_STRING("chunkSize"))) { if (object->Get(TRI_V8_ASCII_STRING("chunkSize"))->IsNumber()) { config._chunkSize = TRI_ObjectToUInt64(object->Get(TRI_V8_ASCII_STRING("chunkSize")), true); } } if (object->Has(TRI_V8_ASCII_STRING("includeSystem"))) { if (object->Get(TRI_V8_ASCII_STRING("includeSystem"))->IsBoolean()) { config._includeSystem = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("includeSystem"))); } } if (object->Has(TRI_V8_ASCII_STRING("requireFromPresent"))) { if (object->Get(TRI_V8_ASCII_STRING("requireFromPresent"))->IsBoolean()) { config._requireFromPresent = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("requireFromPresent"))); } } string errorMsg = ""; InitialSyncer syncer(vocbase, &config, restrictCollections, restrictType, verbose); TRI_DestroyConfigurationReplicationApplier(&config); int res = TRI_ERROR_NO_ERROR; v8::Handle result = v8::Object::New(isolate); try { res = syncer.run(errorMsg); result->Set(TRI_V8_ASCII_STRING("lastLogTick"), V8TickId(isolate, syncer.getLastLogTick())); map::const_iterator it; map const& c = syncer.getProcessedCollections(); uint32_t j = 0; v8::Handle collections = v8::Array::New(isolate); for (it = c.begin(); it != c.end(); ++it) { const string cidString = StringUtils::itoa((*it).first); v8::Handle ci = v8::Object::New(isolate); ci->Set(TRI_V8_ASCII_STRING("id"), TRI_V8_STD_STRING(cidString)); ci->Set(TRI_V8_ASCII_STRING("name"), TRI_V8_STD_STRING((*it).second)); collections->Set(j++, ci); } result->Set(TRI_V8_ASCII_STRING("collections"), collections); } catch (...) { } if (res != TRI_ERROR_NO_ERROR) { TRI_V8_THROW_EXCEPTION_MESSAGE(res, "cannot sync from remote endpoint: " + errorMsg); } TRI_V8_RETURN(result); TRI_V8_TRY_CATCH_END } //////////////////////////////////////////////////////////////////////////////// /// @brief return the server's id //////////////////////////////////////////////////////////////////////////////// static void JS_ServerIdReplication (const v8::FunctionCallbackInfo& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); v8::HandleScope scope(isolate); const string serverId = StringUtils::itoa(TRI_GetIdServer()); TRI_V8_RETURN_STD_STRING(serverId); TRI_V8_TRY_CATCH_END } //////////////////////////////////////////////////////////////////////////////// /// @brief configure the replication applier manually //////////////////////////////////////////////////////////////////////////////// static void JS_ConfigureApplierReplication (const v8::FunctionCallbackInfo& 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 (vocbase->_replicationApplier == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_INTERNAL); } if (args.Length() == 0) { // no argument: return the current configuration TRI_replication_applier_configuration_t config; TRI_InitConfigurationReplicationApplier(&config); { READ_LOCKER(vocbase->_replicationApplier->_statusLock); TRI_CopyConfigurationReplicationApplier(&vocbase->_replicationApplier->_configuration, &config); } TRI_json_t* json = TRI_JsonConfigurationReplicationApplier(&config); TRI_DestroyConfigurationReplicationApplier(&config); if (json == nullptr) { TRI_V8_THROW_EXCEPTION_MEMORY(); } v8::Handle result = TRI_ObjectJson(isolate, json); TRI_FreeJson(TRI_CORE_MEM_ZONE, json); TRI_V8_RETURN(result); } else { // set the configuration if (args.Length() != 1 || ! args[0]->IsObject()) { TRI_V8_THROW_EXCEPTION_USAGE("REPLICATION_APPLIER_CONFIGURE()"); } TRI_replication_applier_configuration_t config; TRI_InitConfigurationReplicationApplier(&config); // fill with previous configuration { READ_LOCKER(vocbase->_replicationApplier->_statusLock); TRI_CopyConfigurationReplicationApplier(&vocbase->_replicationApplier->_configuration, &config); } // treat the argument as an object from now on v8::Handle object = v8::Handle::Cast(args[0]); if (object->Has(TRI_V8_ASCII_STRING("endpoint"))) { if (object->Get(TRI_V8_ASCII_STRING("endpoint"))->IsString()) { string endpoint = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING("endpoint"))); if (config._endpoint != nullptr) { TRI_Free(TRI_CORE_MEM_ZONE, config._endpoint); } config._endpoint = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE, endpoint.c_str(), endpoint.size()); } } if (object->Has(TRI_V8_ASCII_STRING("database"))) { if (object->Get(TRI_V8_ASCII_STRING("database"))->IsString()) { string database = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING("database"))); if (config._database != nullptr) { TRI_Free(TRI_CORE_MEM_ZONE, config._database); } config._database = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE, database.c_str(), database.size()); } } else { if (config._database == nullptr) { // no database set, use current config._database = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, vocbase->_name); } } TRI_ASSERT(config._database != nullptr); if (object->Has(TRI_V8_ASCII_STRING("username"))) { if (object->Get(TRI_V8_ASCII_STRING("username"))->IsString()) { string username = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING("username"))); if (config._username != nullptr) { TRI_Free(TRI_CORE_MEM_ZONE, config._username); } config._username = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE, username.c_str(), username.size()); } } if (object->Has(TRI_V8_ASCII_STRING("password"))) { if (object->Get(TRI_V8_ASCII_STRING("password"))->IsString()) { string password = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING("password"))); if (config._password != nullptr) { TRI_Free(TRI_CORE_MEM_ZONE, config._password); } config._password = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE, password.c_str(), password.size()); } } if (object->Has(TRI_V8_ASCII_STRING("requestTimeout"))) { if (object->Get(TRI_V8_ASCII_STRING("requestTimeout"))->IsNumber()) { config._requestTimeout = TRI_ObjectToDouble(object->Get(TRI_V8_ASCII_STRING("requestTimeout"))); } } if (object->Has(TRI_V8_ASCII_STRING("connectTimeout"))) { if (object->Get(TRI_V8_ASCII_STRING("connectTimeout"))->IsNumber()) { config._connectTimeout = TRI_ObjectToDouble(object->Get(TRI_V8_ASCII_STRING("connectTimeout"))); } } if (object->Has(TRI_V8_ASCII_STRING("ignoreErrors"))) { if (object->Get(TRI_V8_ASCII_STRING("ignoreErrors"))->IsNumber()) { config._ignoreErrors = TRI_ObjectToUInt64(object->Get(TRI_V8_ASCII_STRING("ignoreErrors")), false); } } if (object->Has(TRI_V8_ASCII_STRING("maxConnectRetries"))) { if (object->Get(TRI_V8_ASCII_STRING("maxConnectRetries"))->IsNumber()) { config._maxConnectRetries = TRI_ObjectToUInt64(object->Get(TRI_V8_ASCII_STRING("maxConnectRetries")), false); } } if (object->Has(TRI_V8_ASCII_STRING("sslProtocol"))) { if (object->Get(TRI_V8_ASCII_STRING("sslProtocol"))->IsNumber()) { config._sslProtocol = (uint32_t) TRI_ObjectToUInt64(object->Get(TRI_V8_ASCII_STRING("sslProtocol")), false); } } if (object->Has(TRI_V8_ASCII_STRING("chunkSize"))) { if (object->Get(TRI_V8_ASCII_STRING("chunkSize"))->IsNumber()) { config._chunkSize = TRI_ObjectToUInt64(object->Get(TRI_V8_ASCII_STRING("chunkSize")), true); } } if (object->Has(TRI_V8_ASCII_STRING("autoStart"))) { if (object->Get(TRI_V8_ASCII_STRING("autoStart"))->IsBoolean()) { config._autoStart = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("autoStart"))); } } if (object->Has(TRI_V8_ASCII_STRING("adaptivePolling"))) { if (object->Get(TRI_V8_ASCII_STRING("adaptivePolling"))->IsBoolean()) { config._adaptivePolling = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("adaptivePolling"))); } } if (object->Has(TRI_V8_ASCII_STRING("includeSystem"))) { if (object->Get(TRI_V8_ASCII_STRING("includeSystem"))->IsBoolean()) { config._includeSystem = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("includeSystem"))); } } if (object->Has(TRI_V8_ASCII_STRING("requireFromPresent"))) { if (object->Get(TRI_V8_ASCII_STRING("requireFromPresent"))->IsBoolean()) { config._requireFromPresent = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("requireFromPresent"))); } } if (object->Has(TRI_V8_ASCII_STRING("verbose"))) { if (object->Get(TRI_V8_ASCII_STRING("verbose"))->IsBoolean()) { config._verbose = TRI_ObjectToBoolean(object->Get(TRI_V8_ASCII_STRING("verbose"))); } } if (object->Has(TRI_V8_ASCII_STRING("restrictCollections")) && object->Get(TRI_V8_ASCII_STRING("restrictCollections"))->IsArray()) { config._restrictCollections.clear(); v8::Handle a = v8::Handle::Cast(object->Get(TRI_V8_ASCII_STRING("restrictCollections"))); uint32_t const n = a->Length(); for (uint32_t i = 0; i < n; ++i) { v8::Handle cname = a->Get(i); if (cname->IsString()) { config._restrictCollections.insert(pair(TRI_ObjectToString(cname), true)); } } } if (object->Has(TRI_V8_ASCII_STRING("restrictType"))) { config._restrictType = TRI_ObjectToString(object->Get(TRI_V8_ASCII_STRING("restrictType"))); } if ((config._restrictType.empty() && ! config._restrictCollections.empty()) || (! config._restrictType.empty() && config._restrictCollections.empty()) || (! config._restrictType.empty() && config._restrictType != "include" && config._restrictType != "exclude")) { TRI_DestroyConfigurationReplicationApplier(&config); TRI_V8_THROW_EXCEPTION_PARAMETER("invalid value for or "); } int res = TRI_ConfigureReplicationApplier(vocbase->_replicationApplier, &config); if (res != TRI_ERROR_NO_ERROR) { TRI_DestroyConfigurationReplicationApplier(&config); TRI_V8_THROW_EXCEPTION(res); } TRI_json_t* json = TRI_JsonConfigurationReplicationApplier(&config); TRI_DestroyConfigurationReplicationApplier(&config); if (json == nullptr) { TRI_V8_THROW_EXCEPTION_MEMORY(); } v8::Handle result = TRI_ObjectJson(isolate, json); TRI_FreeJson(TRI_CORE_MEM_ZONE, json); TRI_V8_RETURN(result); } TRI_V8_TRY_CATCH_END } //////////////////////////////////////////////////////////////////////////////// /// @brief start the replication applier manually //////////////////////////////////////////////////////////////////////////////// static void JS_StartApplierReplication (const v8::FunctionCallbackInfo& 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 (vocbase->_replicationApplier == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_INTERNAL); } if (args.Length() > 1) { TRI_V8_THROW_EXCEPTION_USAGE("REPLICATION_APPLIER_START()"); } TRI_voc_tick_t initialTick = 0; bool useTick = false; if (args.Length() == 1) { initialTick = TRI_ObjectToUInt64(args[0], true); useTick = true; } int res = vocbase->_replicationApplier->start(initialTick, useTick); if (res != TRI_ERROR_NO_ERROR) { TRI_V8_THROW_EXCEPTION_MESSAGE(res, "cannot start replication applier"); } TRI_V8_RETURN_TRUE(); TRI_V8_TRY_CATCH_END } //////////////////////////////////////////////////////////////////////////////// /// @brief shuts down the replication applier manually //////////////////////////////////////////////////////////////////////////////// static void JS_ShutdownApplierReplication (const v8::FunctionCallbackInfo& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); v8::HandleScope scope(isolate); if (args.Length() != 0) { TRI_V8_THROW_EXCEPTION_USAGE("REPLICATION_APPLIER_SHUTDOWN()"); } TRI_vocbase_t* vocbase = GetContextVocBase(isolate); if (vocbase == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } if (vocbase->_replicationApplier == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_INTERNAL); } int res = vocbase->_replicationApplier->shutdown(); if (res != TRI_ERROR_NO_ERROR) { TRI_V8_THROW_EXCEPTION_MESSAGE(res, "cannot shut down replication applier"); } TRI_V8_RETURN_TRUE(); TRI_V8_TRY_CATCH_END } //////////////////////////////////////////////////////////////////////////////// /// @brief get the state of the replication applier //////////////////////////////////////////////////////////////////////////////// static void JS_StateApplierReplication (const v8::FunctionCallbackInfo& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); v8::HandleScope scope(isolate); if (args.Length() != 0) { TRI_V8_THROW_EXCEPTION_USAGE("REPLICATION_APPLIER_STATE()"); } TRI_vocbase_t* vocbase = GetContextVocBase(isolate); if (vocbase == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } if (vocbase->_replicationApplier == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_INTERNAL); } TRI_json_t* json = TRI_JsonReplicationApplier(vocbase->_replicationApplier); if (json == nullptr) { TRI_V8_THROW_EXCEPTION_MEMORY(); } v8::Handle result = TRI_ObjectJson(isolate, json); TRI_FreeJson(TRI_CORE_MEM_ZONE, json); TRI_V8_RETURN(result); TRI_V8_TRY_CATCH_END } //////////////////////////////////////////////////////////////////////////////// /// @brief stop the replication applier and "forget" all state //////////////////////////////////////////////////////////////////////////////// static void JS_ForgetApplierReplication (const v8::FunctionCallbackInfo& args) { TRI_V8_TRY_CATCH_BEGIN(isolate); v8::HandleScope scope(isolate); if (args.Length() != 0) { TRI_V8_THROW_EXCEPTION_USAGE("REPLICATION_APPLIER_FORGET()"); } TRI_vocbase_t* vocbase = GetContextVocBase(isolate); if (vocbase == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } if (vocbase->_replicationApplier == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_INTERNAL); } int res = vocbase->_replicationApplier->forget(); if (res != TRI_ERROR_NO_ERROR) { TRI_V8_THROW_EXCEPTION(res); } TRI_V8_RETURN_TRUE(); TRI_V8_TRY_CATCH_END } void TRI_InitV8Replication (v8::Isolate* isolate, v8::Handle context, TRI_server_t* server, TRI_vocbase_t* vocbase, JSLoader* loader, size_t threadNumber, TRI_v8_global_t* v8g) { // replication functions. not intended to be used by end users TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_LOGGER_STATE"), JS_StateLoggerReplication, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_LOGGER_LAST"), JS_LastLoggerReplication, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_LOGGER_TICK_RANGES"), JS_TickRangesLoggerReplication, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_LOGGER_FIRST_TICK"), JS_FirstTickLoggerReplication, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_SYNCHRONISE"), JS_SynchroniseReplication, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_SERVER_ID"), JS_ServerIdReplication, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_APPLIER_CONFIGURE"), JS_ConfigureApplierReplication, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_APPLIER_START"), JS_StartApplierReplication, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_APPLIER_SHUTDOWN"), JS_ShutdownApplierReplication, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_APPLIER_STATE"), JS_StateApplierReplication, true); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("REPLICATION_APPLIER_FORGET"), JS_ForgetApplierReplication, true); }