mirror of https://gitee.com/bigwinds/arangodb
fix restrict-to-single-shard rule (#5050)
* fix restrict-to-single-shard rule * added tests for specific cases
This commit is contained in:
parent
4a624d523f
commit
2a97de317e
|
@ -1,6 +1,10 @@
|
||||||
v3.3.6 (XXXX-XX-XX)
|
v3.3.6 (XXXX-XX-XX)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
* fixed issue in AQL query optimizer rule "restrict-to-single-shard", which
|
||||||
|
may have sent documents to a wrong shard in AQL INSERT queries that specified
|
||||||
|
the value for `_key` using an expression (and not a constant value)
|
||||||
|
|
||||||
* fix restoring of smart graph edge collections (may have run into timeout before)
|
* fix restoring of smart graph edge collections (may have run into timeout before)
|
||||||
|
|
||||||
* added ArangoShell helper function for packaging all information about an
|
* added ArangoShell helper function for packaging all information about an
|
||||||
|
|
|
@ -143,6 +143,10 @@ std::string getSingleShardId(ExecutionPlan const* plan, ExecutionNode const* nod
|
||||||
auto shardKeys = collection->shardKeys();
|
auto shardKeys = collection->shardKeys();
|
||||||
std::unordered_set<std::string> toFind;
|
std::unordered_set<std::string> toFind;
|
||||||
for (auto const& it : shardKeys) {
|
for (auto const& it : shardKeys) {
|
||||||
|
if (it.find('.') != std::string::npos) {
|
||||||
|
// shard key containing a "." (sub-attribute). this is not yet supported
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
toFind.emplace(it);
|
toFind.emplace(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,9 +197,9 @@ std::string getSingleShardId(ExecutionPlan const* plan, ExecutionNode const* nod
|
||||||
// builder
|
// builder
|
||||||
builder.add(VPackValue(sub->getString()));
|
builder.add(VPackValue(sub->getString()));
|
||||||
v->toVelocyPackValue(builder);
|
v->toVelocyPackValue(builder);
|
||||||
|
// remove the attribute from our to-do list
|
||||||
|
toFind.erase(it);
|
||||||
}
|
}
|
||||||
// remove the attribute from our to-do list
|
|
||||||
toFind.erase(it);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -145,6 +145,122 @@ function ahuacatlModifySuite () {
|
||||||
assertQueryError(errors.ERROR_CLUSTER_MUST_NOT_CHANGE_SHARDING_ATTRIBUTES.code, "REPLACE { _key: " + JSON.stringify(key) + ", id: 'test' } WITH { value: 2, id: 'bark' } IN " + cn);
|
assertQueryError(errors.ERROR_CLUSTER_MUST_NOT_CHANGE_SHARDING_ATTRIBUTES.code, "REPLACE { _key: " + JSON.stringify(key) + ", id: 'test' } WITH { value: 2, id: 'bark' } IN " + cn);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testInsertMainLevelWithCustomShardKeyConstant : function () {
|
||||||
|
let c = db._create(cn, {numberOfShards:5, shardKeys: ["id"]});
|
||||||
|
|
||||||
|
for (let i = 0; i < 30; ++i) {
|
||||||
|
let expected = { writesExecuted: 1, writesIgnored: 0 };
|
||||||
|
let query = "INSERT { value: " + i + ", id: 'test" + i + "' } IN " + cn;
|
||||||
|
let actual = getModifyQueryResultsRaw(query);
|
||||||
|
|
||||||
|
if (isCluster) {
|
||||||
|
let plan = AQL_EXPLAIN(query).plan;
|
||||||
|
assertFalse(hasDistributeNode(plan.nodes));
|
||||||
|
assertNotEqual(-1, plan.rules.indexOf("restrict-to-single-shard"));
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEqual(0, actual.json.length);
|
||||||
|
assertEqual(expected, sanitizeStats(actual.stats));
|
||||||
|
}
|
||||||
|
assertEqual(30, c.count());
|
||||||
|
|
||||||
|
for (let i = 0; i < 30; ++i) {
|
||||||
|
let r = db._query("FOR doc IN " + cn + " FILTER doc.id == 'test" + i + "' RETURN doc").toArray();
|
||||||
|
assertEqual(1, r.length);
|
||||||
|
assertEqual("test" + i, r[0].id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
testInsertMainLevelWithCustomShardKeyMultiLevel : function () {
|
||||||
|
let c = db._create(cn, {numberOfShards:5, shardKeys: ["a.b"]});
|
||||||
|
|
||||||
|
for (let i = 0; i < 30; ++i) {
|
||||||
|
let expected = { writesExecuted: 1, writesIgnored: 0 };
|
||||||
|
let query = "INSERT { value: " + i + ", a: { b: 'test" + i + "' } } IN " + cn;
|
||||||
|
let actual = getModifyQueryResultsRaw(query);
|
||||||
|
|
||||||
|
if (isCluster) {
|
||||||
|
let plan = AQL_EXPLAIN(query).plan;
|
||||||
|
assertTrue(hasDistributeNode(plan.nodes));
|
||||||
|
assertEqual(-1, plan.rules.indexOf("restrict-to-single-shard"));
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEqual(0, actual.json.length);
|
||||||
|
assertEqual(expected, sanitizeStats(actual.stats));
|
||||||
|
}
|
||||||
|
assertEqual(30, c.count());
|
||||||
|
|
||||||
|
for (let i = 0; i < 30; ++i) {
|
||||||
|
let r = db._query("FOR doc IN " + cn + " FILTER doc.a.b == 'test" + i + "' RETURN doc").toArray();
|
||||||
|
assertEqual(1, r.length);
|
||||||
|
assertEqual("test" + i, r[0].a.b);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
testInsertMainLevelWithKeyConstant : function () {
|
||||||
|
let c = db._create(cn, {numberOfShards:5});
|
||||||
|
|
||||||
|
for (let i = 0; i < 30; ++i) {
|
||||||
|
let expected = { writesExecuted: 1, writesIgnored: 0 };
|
||||||
|
let query = "INSERT { value: " + i + ", _key: 'test" + i + "' } IN " + cn;
|
||||||
|
let actual = getModifyQueryResultsRaw(query);
|
||||||
|
|
||||||
|
if (isCluster) {
|
||||||
|
let plan = AQL_EXPLAIN(query).plan;
|
||||||
|
assertFalse(hasDistributeNode(plan.nodes));
|
||||||
|
assertNotEqual(-1, plan.rules.indexOf("restrict-to-single-shard"));
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEqual(0, actual.json.length);
|
||||||
|
assertEqual(expected, sanitizeStats(actual.stats));
|
||||||
|
}
|
||||||
|
assertEqual(30, c.count());
|
||||||
|
|
||||||
|
for (let i = 0; i < 30; ++i) {
|
||||||
|
let r = db._query("FOR doc IN " + cn + " FILTER doc._key == 'test" + i + "' RETURN doc").toArray();
|
||||||
|
assertEqual(1, r.length);
|
||||||
|
assertEqual("test" + i, r[0]._key);
|
||||||
|
assertEqual(cn + "/test" + i, r[0]._id);
|
||||||
|
|
||||||
|
r = db._query("FOR doc IN " + cn + " FILTER doc._id == '" + cn + "/test" + i + "' RETURN doc").toArray();
|
||||||
|
assertEqual(1, r.length);
|
||||||
|
assertEqual("test" + i, r[0]._key);
|
||||||
|
assertEqual(cn + "/test" + i, r[0]._id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
testInsertMainLevelWithKeyExpression : function () {
|
||||||
|
let c = db._create(cn, {numberOfShards:5});
|
||||||
|
|
||||||
|
for (let i = 0; i < 30; ++i) {
|
||||||
|
let expected = { writesExecuted: 1, writesIgnored: 0 };
|
||||||
|
let query = "INSERT { value: " + i + ", _key: NOOPT(CONCAT('test', '" + i + "')) } IN " + cn;
|
||||||
|
let actual = getModifyQueryResultsRaw(query);
|
||||||
|
|
||||||
|
if (isCluster) {
|
||||||
|
let plan = AQL_EXPLAIN(query).plan;
|
||||||
|
assertTrue(hasDistributeNode(plan.nodes));
|
||||||
|
assertEqual(-1, plan.rules.indexOf("restrict-to-single-shard"));
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEqual(0, actual.json.length);
|
||||||
|
assertEqual(expected, sanitizeStats(actual.stats));
|
||||||
|
}
|
||||||
|
assertEqual(30, c.count());
|
||||||
|
|
||||||
|
for (let i = 0; i < 30; ++i) {
|
||||||
|
let r = db._query("FOR doc IN " + cn + " FILTER doc._key == 'test" + i + "' RETURN doc").toArray();
|
||||||
|
assertEqual(1, r.length);
|
||||||
|
assertEqual("test" + i, r[0]._key);
|
||||||
|
assertEqual(cn + "/test" + i, r[0]._id);
|
||||||
|
|
||||||
|
r = db._query("FOR doc IN " + cn + " FILTER doc._id == '" + cn + "/test" + i + "' RETURN doc").toArray();
|
||||||
|
assertEqual(1, r.length);
|
||||||
|
assertEqual("test" + i, r[0]._key);
|
||||||
|
assertEqual(cn + "/test" + i, r[0]._id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
testInsertMainLevelWithKey : function () {
|
testInsertMainLevelWithKey : function () {
|
||||||
let c = db._create(cn, {numberOfShards:5});
|
let c = db._create(cn, {numberOfShards:5});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue