1
0
Fork 0

[3.3] Bug fix 3.3/allow agency ops in active failover (#9961)

* Backported #9881

* Fixed merge
This commit is contained in:
Tobias Gödderz 2019-10-21 15:07:12 +02:00 committed by KVS85
parent e877d184e5
commit 917ad26d0d
3 changed files with 98 additions and 105 deletions

View File

@ -1,7 +1,10 @@
v3.3.25 (2019-XX-XX)
--------------------
* Fix config directory handling, so we don't trap into UNC path lookups on windows
* Fixed "ArangoDB is not running in cluster mode" errors in active failover setups.
This affected at least /_admin/cluster/health.
* Fix config directory handling, so we don't trap into UNC path lookups on Windows.
* Fixed non-deterministic occurrences of "document not found" errors in sharded
collections with custom shard keys (i.e. non-`_key`) and multi-document lookups.

View File

@ -27,11 +27,13 @@
#include <velocypack/velocypack-aliases.h>
#include "Agency/AgencyComm.h"
#include "Basics/Exceptions.h"
#include "Cluster/ClusterComm.h"
#include "Cluster/ClusterInfo.h"
#include "Cluster/ServerState.h"
#include "Cluster/ShardDistributionReporter.h"
#include "GeneralServer/AuthenticationFeature.h"
#include "Replication/ReplicationFeature.h"
#include "V8/v8-buffer.h"
#include "V8/v8-conv.h"
#include "V8/v8-globals.h"
@ -52,12 +54,24 @@ using namespace arangodb::basics;
CreateAgencyException(args, data); \
return;
#define ONLY_IN_CLUSTER \
if (!ServerState::instance()->isRunningInCluster()) { \
TRI_V8_THROW_EXCEPTION_INTERNAL( \
"ArangoDB is not running in cluster mode"); \
static void onlyInCluster() {
if (ServerState::instance()->isRunningInCluster()) {
return;
}
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "ArangoDB is not running in cluster mode");
}
static void onlyInClusterOrActiveFailover() {
auto replicationFeature = ReplicationFeature::INSTANCE;
if (replicationFeature != nullptr && replicationFeature->isActiveFailoverEnabled()) {
// active failover enabled
return;
}
return onlyInCluster();
}
static void CreateAgencyException(v8::FunctionCallbackInfo<v8::Value> const& args,
AgencyCommResult const& result) {
v8::Isolate* isolate = args.GetIsolate();
@ -99,7 +113,7 @@ static void JS_CasAgency(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() < 3) {
TRI_V8_THROW_EXCEPTION_USAGE(
@ -161,7 +175,7 @@ static void JS_CreateDirectoryAgency(v8::FunctionCallbackInfo<v8::Value> const&
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE("createDirectory(<key>)");
@ -208,7 +222,7 @@ static void JS_IncreaseVersionAgency(v8::FunctionCallbackInfo<v8::Value> const&
TRI_V8_TRY_CATCH_BEGIN(isolate)
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE("increaseVersion(<key>)");
@ -234,7 +248,7 @@ static void JS_GetAgency(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate)
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() < 1) {
TRI_V8_THROW_EXCEPTION_USAGE("get(<key>)");
@ -276,7 +290,7 @@ static void JS_APIAgency(std::string const& envelope,
TRI_V8_TRY_CATCH_BEGIN(isolate)
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() < 1) {
TRI_V8_THROW_EXCEPTION_USAGE(std::string(envelope) + "([[...]])");
@ -341,7 +355,7 @@ static void JS_RemoveAgency(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() < 1) {
TRI_V8_THROW_EXCEPTION_USAGE("remove(<key>, <recursive>)");
@ -373,7 +387,7 @@ static void JS_SetAgency(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() < 2) {
TRI_V8_THROW_EXCEPTION_USAGE("set(<key>, <value>, <ttl>)");
@ -412,7 +426,7 @@ static void JS_Agency(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate)
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() > 0) {
TRI_V8_THROW_EXCEPTION_USAGE("agency()");
@ -455,7 +469,7 @@ static void JS_EndpointsAgency(v8::FunctionCallbackInfo<v8::Value> const& args)
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("endpoints()");
@ -500,7 +514,7 @@ static void JS_UniqidAgency(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() > 2) {
TRI_V8_THROW_EXCEPTION_USAGE("uniqid(<count>, <timeout>)");
@ -537,7 +551,7 @@ static void JS_VersionAgency(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER;
onlyInClusterOrActiveFailover();
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("version()");
@ -558,7 +572,8 @@ static void JS_DoesDatabaseExistClusterInfo(v8::FunctionCallbackInfo<v8::Value>
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE("doesDatabaseExist(<database-id>)");
}
@ -580,12 +595,13 @@ static void JS_DoesDatabaseExistClusterInfo(v8::FunctionCallbackInfo<v8::Value>
static void JS_Databases(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
onlyInCluster();
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("databases()");
}
ONLY_IN_CLUSTER
std::vector<DatabaseID> res = ClusterInfo::instance()->databases(true);
v8::Handle<v8::Array> a = v8::Array::New(isolate, (int)res.size());
std::vector<DatabaseID>::iterator it;
@ -605,7 +621,8 @@ static void JS_FlushClusterInfo(v8::FunctionCallbackInfo<v8::Value> const& args)
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("flush()");
}
@ -624,7 +641,8 @@ static void JS_GetCollectionInfoClusterInfo(v8::FunctionCallbackInfo<v8::Value>
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 2) {
TRI_V8_THROW_EXCEPTION_USAGE(
"getCollectionInfo(<database-id>, <collection-id>)");
@ -689,7 +707,8 @@ static void JS_GetCollectionInfoCurrentClusterInfo(v8::FunctionCallbackInfo<v8::
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 3) {
TRI_V8_THROW_EXCEPTION_USAGE(
"getCollectionInfoCurrent(<database-id>, <collection-id>, <shardID>)");
@ -761,7 +780,8 @@ static void JS_GetResponsibleServerClusterInfo(v8::FunctionCallbackInfo<v8::Valu
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE("getResponsibleServer(<shard-id>)");
}
@ -786,7 +806,8 @@ static void JS_GetResponsibleShardClusterInfo(v8::FunctionCallbackInfo<v8::Value
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() < 2 || args.Length() > 3) {
TRI_V8_THROW_EXCEPTION_USAGE(
"getResponsibleShard(<collection-id>, <document>, "
@ -844,7 +865,8 @@ static void JS_GetServerEndpointClusterInfo(v8::FunctionCallbackInfo<v8::Value>
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE("getServerEndpoint(<server-id>)");
}
@ -864,7 +886,8 @@ static void JS_GetServerNameClusterInfo(v8::FunctionCallbackInfo<v8::Value> cons
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE("getServerName(<endpoint>)");
}
@ -884,7 +907,8 @@ static void JS_GetDBServers(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("getDBServers()");
}
@ -925,7 +949,8 @@ static void JS_ReloadDBServers(v8::FunctionCallbackInfo<v8::Value> const& args)
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("reloadDBServers()");
}
@ -943,7 +968,7 @@ static void JS_GetCoordinators(v8::FunctionCallbackInfo<v8::Value> const& args)
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("getCoordinators()");
@ -1023,7 +1048,8 @@ static void JS_IdServerState(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInClusterOrActiveFailover();
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("id()");
}
@ -1106,40 +1132,6 @@ static void JS_GetFoxxmasterSince(v8::FunctionCallbackInfo<v8::Value> const& arg
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the primary servers id (only for secondaries)
////////////////////////////////////////////////////////////////////////////////
static void JS_IdOfPrimaryServerState(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("idOfPrimary()");
}
TRI_V8_RETURN_STRING(""); // no more secondaries
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the javascript startup path
////////////////////////////////////////////////////////////////////////////////
static void JS_JavaScriptPathServerState(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("javaScriptPath()");
}
std::string const path = ServerState::instance()->getJavaScriptPath();
TRI_V8_RETURN_STD_STRING(path);
TRI_V8_TRY_CATCH_END
}
#ifdef DEBUG_SYNC_REPLICATION
////////////////////////////////////////////////////////////////////////////////
/// @brief set arangoserver state to initialized
@ -1260,29 +1252,6 @@ static void JS_SetRoleServerState(v8::FunctionCallbackInfo<v8::Value> const& arg
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief redetermines the role from the agency
////////////////////////////////////////////////////////////////////////////////
static void JS_RedetermineRoleServerState(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("redetermineRole()");
}
/*bool changed = ServerState::instance()->redetermineRole();
if (changed) {
TRI_V8_RETURN_TRUE();
} else {
}*/
TRI_V8_RETURN_FALSE();
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the server state
////////////////////////////////////////////////////////////////////////////////
@ -1317,7 +1286,8 @@ static void PrepareClusterCommRequest(
v8::Isolate* isolate = args.GetIsolate();
TRI_V8_CURRENT_GLOBALS_AND_SCOPE;
ONLY_IN_CLUSTER
onlyInClusterOrActiveFailover();
TRI_ASSERT(args.Length() >= 4);
reqType = arangodb::rest::RequestType::GET;
@ -1564,7 +1534,8 @@ static void Return_PrepareClusterCommResultForJS(v8::FunctionCallbackInfo<v8::Va
static void JS_AsyncRequest(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInClusterOrActiveFailover();
if (args.Length() < 4 || args.Length() > 7) {
TRI_V8_THROW_EXCEPTION_USAGE(
@ -1624,7 +1595,8 @@ static void JS_AsyncRequest(v8::FunctionCallbackInfo<v8::Value> const& args) {
static void JS_SyncRequest(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() < 4 || args.Length() > 7) {
TRI_V8_THROW_EXCEPTION_USAGE(
@ -1688,7 +1660,8 @@ static void JS_SyncRequest(v8::FunctionCallbackInfo<v8::Value> const& args) {
static void JS_Enquire(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE("enquire(operationID)");
@ -1719,7 +1692,8 @@ static void JS_Enquire(v8::FunctionCallbackInfo<v8::Value> const& args) {
static void JS_Wait(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
TRI_V8_CURRENT_GLOBALS_AND_SCOPE;
ONLY_IN_CLUSTER
onlyInClusterOrActiveFailover();
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE("wait(obj)");
@ -1787,7 +1761,8 @@ static void JS_Wait(v8::FunctionCallbackInfo<v8::Value> const& args) {
static void JS_Drop(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
TRI_V8_CURRENT_GLOBALS_AND_SCOPE;
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE("drop(obj)");
@ -1892,7 +1867,8 @@ static void JS_ClusterDownload(v8::FunctionCallbackInfo<v8::Value> const& args)
static void JS_GetShardDistribution(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
v8::HandleScope scope(isolate);
auto vocbase = GetContextVocBase(isolate);
@ -1912,7 +1888,8 @@ static void JS_GetShardDistribution(v8::FunctionCallbackInfo<v8::Value> const& a
static void JS_GetCollectionShardDistribution(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
ONLY_IN_CLUSTER
onlyInCluster();
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE(
@ -2068,11 +2045,6 @@ void TRI_InitV8Cluster(v8::Isolate* isolate, v8::Handle<v8::Context> context) {
TRI_AddMethodVocbase(isolate, rt,
TRI_V8_ASCII_STRING(isolate, "getFoxxmasterSince"),
JS_GetFoxxmasterSince);
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "idOfPrimary"),
JS_IdOfPrimaryServerState);
TRI_AddMethodVocbase(isolate, rt,
TRI_V8_ASCII_STRING(isolate, "javaScriptPath"),
JS_JavaScriptPathServerState);
#ifdef DEBUG_SYNC_REPLICATION
TRI_AddMethodVocbase(isolate, rt,
TRI_V8_ASCII_STRING(isolate,
@ -2089,9 +2061,6 @@ void TRI_InitV8Cluster(v8::Isolate* isolate, v8::Handle<v8::Context> context) {
JS_SetIdServerState, true);
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "setRole"),
JS_SetRoleServerState, true);
TRI_AddMethodVocbase(isolate, rt,
TRI_V8_ASCII_STRING(isolate, "redetermineRole"),
JS_RedetermineRoleServerState, true);
TRI_AddMethodVocbase(isolate, rt, TRI_V8_ASCII_STRING(isolate, "status"), JS_StatusServerState);
v8g->ServerStateTempl.Reset(isolate, rt);

View File

@ -27,7 +27,8 @@
const jsunity = require('jsunity');
const internal = require('internal');
const fs = require('fs');
const console = require('console');
const expect = require('chai').expect;
const arangosh = require('@arangodb/arangosh');
const crypto = require('@arangodb/crypto');
@ -75,12 +76,12 @@ function getUrl(endpoint) {
function baseUrl() {
return getUrl(arango.getEndpoint());
};
}
function connectToServer(leader) {
arango.reconnect(leader, "_system", "root", "");
db._flushCache();
};
}
// getEndponts works with any server
function getClusterEndpoints() {
@ -569,6 +570,26 @@ function ActiveFailoverSuite() {
assertTrue(checkInSync(lead, servers));
}*/
// Regression test. This endpoint was broken due to added checks in v8-cluster.cpp,
// which allowed certain calls only in cluster mode, but not in active failover.
testClusterHealth: function () {
console.warn({currentLead: getUrl(currentLead)});
const res = request.get({
url: getUrl(currentLead) + "/_admin/cluster/health",
auth: {
bearer: jwtRoot,
},
timeout: 30
});
console.warn(JSON.stringify(res));
console.warn(res.json);
expect(res).to.be.an.instanceof(request.Response);
// expect(res).to.be.have.property('statusCode', 200);
expect(res).to.have.property('json');
expect(res.json).to.include({error: false, code: 200});
expect(res.json).to.have.property('Health');
},
};
}