From 12d973504c8af8142a0e2000f733f5c8914da8e0 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Fri, 8 Apr 2016 10:53:11 +0200 Subject: [PATCH] Fixed babies creation in cluster with undefined keys. --- arangod/Cluster/ClusterInfo.cpp | 5 +-- arangod/Cluster/ClusterInfo.h | 3 +- arangod/Cluster/ClusterMethods.cpp | 54 ++++++++++++++++++++++++------ lib/Basics/VelocyPackHelper.cpp | 14 ++++++-- lib/Basics/VelocyPackHelper.h | 2 +- 5 files changed, 61 insertions(+), 17 deletions(-) diff --git a/arangod/Cluster/ClusterInfo.cpp b/arangod/Cluster/ClusterInfo.cpp index fd0e4e11f5..914e8662e1 100644 --- a/arangod/Cluster/ClusterInfo.cpp +++ b/arangod/Cluster/ClusterInfo.cpp @@ -2418,7 +2418,8 @@ std::shared_ptr> ClusterInfo::getShardList( int ClusterInfo::getResponsibleShard(CollectionID const& collectionID, VPackSlice slice, bool docComplete, ShardID& shardID, - bool& usesDefaultShardingAttributes) { + bool& usesDefaultShardingAttributes, + std::string const& key) { // Note that currently we take the number of shards and the shardKeys // from Plan, since they are immutable. Later we will have to switch // this to Current, when we allow to add and remove shards. @@ -2464,7 +2465,7 @@ int ClusterInfo::getResponsibleShard(CollectionID const& collectionID, int error = TRI_ERROR_NO_ERROR; uint64_t hash = arangodb::basics::VelocyPackHelper::hashByAttributes( - slice, *shardKeysPtr, docComplete, error); + slice, *shardKeysPtr, docComplete, error, key); static char const* magicPhrase = "Foxx you have stolen the goose, give she back again!"; static size_t const len = 52; diff --git a/arangod/Cluster/ClusterInfo.h b/arangod/Cluster/ClusterInfo.h index cff210fa59..05c7a37788 100644 --- a/arangod/Cluster/ClusterInfo.h +++ b/arangod/Cluster/ClusterInfo.h @@ -800,7 +800,8 @@ class ClusterInfo { int getResponsibleShard(CollectionID const&, arangodb::velocypack::Slice, bool docComplete, ShardID& shardID, - bool& usesDefaultShardingAttributes); + bool& usesDefaultShardingAttributes, + std::string const& key = ""); ////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Cluster/ClusterMethods.cpp b/arangod/Cluster/ClusterMethods.cpp index e0f2de8545..590e0914f8 100644 --- a/arangod/Cluster/ClusterMethods.cpp +++ b/arangod/Cluster/ClusterMethods.cpp @@ -568,8 +568,8 @@ int createDocumentOnCoordinator( } std::string const collid = StringUtils::itoa(collinfo->id()); - std::unordered_map> shardMap; - std::vector> reverseMapping; + std::unordered_map>> shardMap; + std::vector> reverseMapping; bool useMultiple = slice.isArray(); auto workOnOneNode = [&shardMap, &ci, &collid, &collinfo, &reverseMapping]( @@ -597,8 +597,15 @@ int createDocumentOnCoordinator( // Now find the responsible shard: bool usesDefaultShardingAttributes; ShardID shardID; - int error = ci->getResponsibleShard(collid, node, true, shardID, - usesDefaultShardingAttributes); + int error TRI_ERROR_NO_ERROR; + if (userSpecifiedKey) { + error = ci->getResponsibleShard(collid, node, true, shardID, + usesDefaultShardingAttributes); + } else { + error = ci->getResponsibleShard(collid, node, true, shardID, + usesDefaultShardingAttributes, + _key); + } if (error == TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) { return TRI_ERROR_CLUSTER_SHARD_GONE; } @@ -610,10 +617,19 @@ int createDocumentOnCoordinator( // We found the responsible shard. Add it to the list. auto it = shardMap.find(shardID); if (it == shardMap.end()) { - std::vector counter({index}); - shardMap.emplace(shardID, counter); + if (userSpecifiedKey) { + std::vector> counter({{index, ""}}); + shardMap.emplace(shardID, counter); + } else { + std::vector> counter({{index, _key}}); + shardMap.emplace(shardID, counter); + } } else { - it->second.emplace_back(index); + if (userSpecifiedKey) { + it->second.emplace_back(index, ""); + } else { + it->second.emplace_back(index, _key); + } } reverseMapping.emplace_back(shardID, index); return TRI_ERROR_NO_ERROR; @@ -649,12 +665,30 @@ int createDocumentOnCoordinator( auto body = std::make_shared(); for (auto const& it : shardMap) { if (!useMultiple) { - body->assign(slice.toJson()); + TRI_ASSERT(it.second.size() == 1); + auto idx = it.second.front(); + if (idx.second.empty()) { + body->assign(slice.toJson()); + } else { + reqBuilder.clear(); + reqBuilder.openObject(); + TRI_SanitizeObject(slice, reqBuilder); + reqBuilder.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(idx.second)); + reqBuilder.close(); + body->assign(reqBuilder.slice().toJson()); + } } else { reqBuilder.clear(); reqBuilder.openArray(); - for (auto idx : it.second) { - reqBuilder.add(slice.at(idx)); + for (auto const& idx : it.second) { + if (idx.second.empty()) { + reqBuilder.add(slice.at(idx.first)); + } else { + reqBuilder.openObject(); + TRI_SanitizeObject(slice.at(idx.first), reqBuilder); + reqBuilder.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(idx.second)); + reqBuilder.close(); + } } reqBuilder.close(); body->assign(reqBuilder.slice().toJson()); diff --git a/lib/Basics/VelocyPackHelper.cpp b/lib/Basics/VelocyPackHelper.cpp index 7c24177f68..ea5fc53edc 100644 --- a/lib/Basics/VelocyPackHelper.cpp +++ b/lib/Basics/VelocyPackHelper.cpp @@ -700,14 +700,22 @@ double VelocyPackHelper::toDouble(VPackSlice const& slice, bool& failed) { uint64_t VelocyPackHelper::hashByAttributes( VPackSlice slice, std::vector const& attributes, - bool docComplete, int& error) { + bool docComplete, int& error, std::string const& key) { error = TRI_ERROR_NO_ERROR; uint64_t hash = TRI_FnvHashBlockInitial(); if (slice.isObject()) { for (auto const& attr: attributes) { VPackSlice sub = slice.get(attr); - if (sub.isNone() && !docComplete) { - error = TRI_ERROR_CLUSTER_NOT_ALL_SHARDING_ATTRIBUTES_GIVEN; + if (sub.isNone()) { + if (attr == "_key" && !key.empty()) { + VPackBuilder temporaryBuilder; + temporaryBuilder.add(VPackValue(key)); + temporaryBuilder.slice().normalizedHash(hash); + continue; + } + if (!docComplete) { + error = TRI_ERROR_CLUSTER_NOT_ALL_SHARDING_ATTRIBUTES_GIVEN; + } } sub.normalizedHash(hash); } diff --git a/lib/Basics/VelocyPackHelper.h b/lib/Basics/VelocyPackHelper.h index ed8e06e22a..47bd744069 100644 --- a/lib/Basics/VelocyPackHelper.h +++ b/lib/Basics/VelocyPackHelper.h @@ -225,7 +225,7 @@ class VelocyPackHelper { static double toDouble(VPackSlice const&, bool&); static uint64_t hashByAttributes(VPackSlice, std::vector const&, - bool, int&); + bool, int&, std::string const& key = ""); static arangodb::velocypack::Slice NullValue(); static arangodb::velocypack::Slice TrueValue();