1
0
Fork 0

honor restrictions when creating graphs (#10136)

This commit is contained in:
Jan 2019-10-01 22:55:58 +02:00 committed by KVS85
parent b3a1b028d8
commit 7e524f9af9
3 changed files with 165 additions and 29 deletions

View File

@ -43,6 +43,7 @@
#include "Cluster/ServerState.h"
#include "Graph/Graph.h"
#include "RestServer/QueryRegistryFeature.h"
#include "Sharding/ShardingInfo.h"
#include "Transaction/Methods.h"
#include "Transaction/StandaloneContext.h"
#include "Transaction/V8Context.h"
@ -92,6 +93,13 @@ OperationResult GraphManager::createCollection(std::string const& name, TRI_col_
bool waitForSync, VPackSlice options) {
TRI_ASSERT(colType == TRI_COL_TYPE_DOCUMENT || colType == TRI_COL_TYPE_EDGE);
if (ServerState::instance()->isCoordinator()) {
Result res = ShardingInfo::validateShardsAndReplicationFactor(options);
if (res.fail()) {
return OperationResult(res);
}
}
auto res = arangodb::methods::Collections::create( // create collection
ctx()->vocbase(), // collection vocbase
name, // collection name

View File

@ -475,39 +475,41 @@ int ShardingInfo::getResponsibleShard(arangodb::velocypack::Slice slice, bool do
Result ShardingInfo::validateShardsAndReplicationFactor(arangodb::velocypack::Slice slice) {
Result res;
auto const* cl = application_features::ApplicationServer::getFeature<ClusterFeature>("Cluster");
if (slice.isObject()) {
auto const* cl = application_features::ApplicationServer::getFeature<ClusterFeature>("Cluster");
auto numberOfShardsSlice = slice.get(StaticStrings::NumberOfShards);
if (numberOfShardsSlice.isNumber()) {
uint32_t const maxNumberOfShards = cl->maxNumberOfShards();
uint32_t numberOfShards = numberOfShardsSlice.getNumber<uint32_t>();
if (maxNumberOfShards > 0 &&
numberOfShards > maxNumberOfShards) {
res.reset(TRI_ERROR_CLUSTER_TOO_MANY_SHARDS,
std::string("too many shards. maximum number of shards is ") + std::to_string(maxNumberOfShards));
auto numberOfShardsSlice = slice.get(StaticStrings::NumberOfShards);
if (numberOfShardsSlice.isNumber()) {
uint32_t const maxNumberOfShards = cl->maxNumberOfShards();
uint32_t numberOfShards = numberOfShardsSlice.getNumber<uint32_t>();
if (maxNumberOfShards > 0 &&
numberOfShards > maxNumberOfShards) {
res.reset(TRI_ERROR_CLUSTER_TOO_MANY_SHARDS,
std::string("too many shards. maximum number of shards is ") + std::to_string(maxNumberOfShards));
}
}
}
auto replicationFactorSlice = slice.get(StaticStrings::ReplicationFactor);
if (replicationFactorSlice.isNumber()) {
uint32_t const minReplicationFactor = cl->minReplicationFactor();
uint32_t const maxReplicationFactor = cl->maxReplicationFactor();
int64_t replicationFactorProbe = replicationFactorSlice.getNumber<int64_t>();
if (replicationFactorProbe <= 0) {
res.reset(TRI_ERROR_BAD_PARAMETER, "invalid value for replicationFactor");
} else {
uint32_t replicationFactor = replicationFactorSlice.getNumber<uint32_t>();
auto replicationFactorSlice = slice.get(StaticStrings::ReplicationFactor);
if (replicationFactorSlice.isNumber()) {
uint32_t const minReplicationFactor = cl->minReplicationFactor();
uint32_t const maxReplicationFactor = cl->maxReplicationFactor();
if (replicationFactor > maxReplicationFactor &&
maxReplicationFactor > 0) {
res.reset(TRI_ERROR_BAD_PARAMETER,
std::string("replicationFactor must not be higher than maximum allowed replicationFactor (") + std::to_string(maxReplicationFactor) + ")");
} else if (replicationFactor < minReplicationFactor &&
minReplicationFactor > 0) {
res.reset(TRI_ERROR_BAD_PARAMETER,
std::string("replicationFactor must not be lower than minimum allowed replicationFactor (") + std::to_string(minReplicationFactor) + ")");
int64_t replicationFactorProbe = replicationFactorSlice.getNumber<int64_t>();
if (replicationFactorProbe <= 0) {
res.reset(TRI_ERROR_BAD_PARAMETER, "invalid value for replicationFactor");
} else {
uint32_t replicationFactor = replicationFactorSlice.getNumber<uint32_t>();
if (replicationFactor > maxReplicationFactor &&
maxReplicationFactor > 0) {
res.reset(TRI_ERROR_BAD_PARAMETER,
std::string("replicationFactor must not be higher than maximum allowed replicationFactor (") + std::to_string(maxReplicationFactor) + ")");
} else if (replicationFactor < minReplicationFactor &&
minReplicationFactor > 0) {
res.reset(TRI_ERROR_BAD_PARAMETER,
std::string("replicationFactor must not be lower than minimum allowed replicationFactor (") + std::to_string(minReplicationFactor) + ")");
}
}
}
}

View File

@ -0,0 +1,126 @@
/*jshint globalstrict:false, strict:false */
/*global assertEqual, assertTrue, assertFalse, fail */
////////////////////////////////////////////////////////////////////////////////
/// @brief test the general-graph class
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-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 triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2019, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var arangodb = require("@arangodb");
var db = arangodb.db;
var graph = require("@arangodb/general-graph");
var ERRORS = arangodb.errors;
let internal = require("internal");
function GeneralGraphClusterCreationSuite() {
'use strict';
const vn = "UnitTestVertices";
const en = "UnitTestEdges";
const gn = "UnitTestGraph";
const edgeDef = [graph._relation(en, vn, vn)];
return {
setUp: function () {
try {
graph._drop(gn, true);
} catch (ignore) {
}
},
tearDown: function () {
try {
graph._drop(gn, true);
} catch (ignore) {
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test numberOfShards
////////////////////////////////////////////////////////////////////////////////
testCreateAsManyShardsAsAllowed : function () {
let max = internal.maxNumberOfShards;
let myGraph = graph._create(gn, edgeDef, null, { numberOfShards: max });
let properties = db._graphs.document(gn);
assertEqual(max, properties.numberOfShards);
},
testCreateMoreShardsThanAllowed : function () {
let max = internal.maxNumberOfShards;
try {
graph._create(gn, edgeDef, null, { numberOfShards: max + 1 });
fail();
} catch (err) {
assertEqual(ERRORS.ERROR_CLUSTER_TOO_MANY_SHARDS.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test replicationFactor
////////////////////////////////////////////////////////////////////////////////
testMinReplicationFactor : function () {
let min = internal.minReplicationFactor;
let myGraph = graph._create(gn, edgeDef, null, { replicationFactor: min });
let properties = db._graphs.document(gn);
assertEqual(min, properties.replicationFactor);
graph._drop(gn, true);
try {
graph._create(gn, edgeDef, null, { replicationFactor: min - 1 });
fail();
} catch (err) {
assertEqual(ERRORS.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
testMaxReplicationFactor : function () {
let max = internal.maxReplicationFactor;
try {
let myGraph = graph._create(gn, edgeDef, null, { replicationFactor: max });
let properties = db._graphs.document(gn);
assertEqual(max, properties.replicationFactor);
graph._drop(gn, true);
try {
graph._create(gn, edgeDef, null, { replicationFactor: max + 1 });
fail();
} catch (err) {
assertEqual(ERRORS.ERROR_BAD_PARAMETER.code, err.errorNum);
}
} catch (err) {
// if creation fails, then it must have been exactly this error
assertEqual(ERRORS.ERROR_CLUSTER_INSUFFICIENT_DBSERVERS.code, err.errorNum);
}
},
};
}
jsunity.run(GeneralGraphClusterCreationSuite);
return jsunity.done();