mirror of https://gitee.com/bigwinds/arangodb
Feature/cluster inventory version (#3152)
* Get rid of a compiler warning in community edition. * Teach /_api/replication/clusterInventory to report Plan/Version and readiness. This is first implemented in the ClusterInfo library. Then the clusterInventory code uses it and checks readiness. Readiness of a collection means that it is created and all shards and all replications have been created and are in sync.
This commit is contained in:
parent
5677baf561
commit
f3acea797b
|
@ -903,7 +903,9 @@ struct CoordinatorInstanciator : public WalkerWorker<ExecutionNode> {
|
|||
Serv2ColMap mappingServerToCollections;
|
||||
size_t length = edges.size();
|
||||
|
||||
#ifdef USE_ENTERPRISE
|
||||
transaction::Methods* trx = query->trx();
|
||||
#endif
|
||||
|
||||
auto findServerLists = [&] (ShardID const& shard) -> Serv2ColMap::iterator {
|
||||
auto serverList = clusterInfo->getResponsibleServer(shard);
|
||||
|
|
|
@ -108,61 +108,8 @@ static std::string extractErrorMessage(std::string const& shardId,
|
|||
/// @brief creates an empty collection info object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CollectionInfoCurrent::CollectionInfoCurrent() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a collection info object from json
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CollectionInfoCurrent::CollectionInfoCurrent(ShardID const& shardID,
|
||||
VPackSlice slice) {
|
||||
add(shardID, slice);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a collection info object from another
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CollectionInfoCurrent::CollectionInfoCurrent(CollectionInfoCurrent const& other)
|
||||
: _vpacks(other._vpacks) {
|
||||
copyAllVPacks();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief moves a collection info current object from another
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CollectionInfoCurrent::CollectionInfoCurrent(CollectionInfoCurrent&& other) {
|
||||
_vpacks.swap(other._vpacks);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief copy assigns a collection info current object from another one
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CollectionInfoCurrent& CollectionInfoCurrent::operator=(
|
||||
CollectionInfoCurrent const& other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
_vpacks = other._vpacks;
|
||||
copyAllVPacks();
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a collection info object from json
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CollectionInfoCurrent& CollectionInfoCurrent::operator=(
|
||||
CollectionInfoCurrent&& other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
_vpacks.clear();
|
||||
_vpacks.swap(other._vpacks);
|
||||
return *this;
|
||||
}
|
||||
CollectionInfoCurrent::CollectionInfoCurrent(uint64_t currentVersion)
|
||||
: _currentVersion(currentVersion) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroys a collection info object
|
||||
|
@ -170,17 +117,6 @@ CollectionInfoCurrent& CollectionInfoCurrent::operator=(
|
|||
|
||||
CollectionInfoCurrent::~CollectionInfoCurrent() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief copy slices behind the pointers in the map _vpacks
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CollectionInfoCurrent::copyAllVPacks() {
|
||||
for (auto it : _vpacks) {
|
||||
auto builder = std::make_shared<VPackBuilder>();
|
||||
builder->add(it.second->slice());
|
||||
it.second = builder;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the clusterinfo instance
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -201,7 +137,8 @@ ClusterInfo* ClusterInfo::instance() { return _instance.get(); }
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClusterInfo::ClusterInfo(AgencyCallbackRegistry* agencyCallbackRegistry)
|
||||
: _agency(), _agencyCallbackRegistry(agencyCallbackRegistry), _uniqid() {
|
||||
: _agency(), _agencyCallbackRegistry(agencyCallbackRegistry),
|
||||
_planVersion(0), _currentVersion(0), _uniqid() {
|
||||
_uniqid._currentValue = 1ULL;
|
||||
_uniqid._upperValue = 0ULL;
|
||||
|
||||
|
@ -450,6 +387,19 @@ void ClusterInfo::loadPlan() {
|
|||
VPackSlice planSlice = planBuilder->slice();
|
||||
|
||||
if (planSlice.isObject()) {
|
||||
uint64_t newPlanVersion = 0;
|
||||
VPackSlice planVersionSlice = planSlice.get("Version");
|
||||
if (planVersionSlice.isNumber()) {
|
||||
try {
|
||||
newPlanVersion = planVersionSlice.getNumber<uint64_t>();
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
if (newPlanVersion == 0) {
|
||||
LOG_TOPIC(WARN, Logger::CLUSTER)
|
||||
<< "Attention: /arango/Plan/Version in the agency is not set or not "
|
||||
"a positive number.";
|
||||
}
|
||||
decltype(_plannedDatabases) newDatabases;
|
||||
decltype(_plannedCollections) newCollections; // map<string /*database id*/
|
||||
// ,map<string /*collection id*/
|
||||
|
@ -590,6 +540,7 @@ void ClusterInfo::loadPlan() {
|
|||
vocbase, collectionSlice);
|
||||
}
|
||||
#endif
|
||||
newCollection->setPlanVersion(newPlanVersion);
|
||||
std::string const collectionName = newCollection->name();
|
||||
if (isCoordinator && !selectivityEstimates.empty()){
|
||||
LOG_TOPIC(TRACE, Logger::CLUSTER) << "copy index estimates";
|
||||
|
@ -662,6 +613,7 @@ void ClusterInfo::loadPlan() {
|
|||
|
||||
WRITE_LOCKER(writeLocker, _planProt.lock);
|
||||
_plan = planBuilder;
|
||||
_planVersion = newPlanVersion;
|
||||
if (swapDatabases) {
|
||||
_plannedDatabases.swap(newDatabases);
|
||||
}
|
||||
|
@ -718,6 +670,20 @@ void ClusterInfo::loadCurrent() {
|
|||
VPackSlice currentSlice = currentBuilder->slice();
|
||||
|
||||
if (currentSlice.isObject()) {
|
||||
uint64_t newCurrentVersion = 0;
|
||||
VPackSlice currentVersionSlice = currentSlice.get("Version");
|
||||
if (currentVersionSlice.isNumber()) {
|
||||
try {
|
||||
newCurrentVersion = currentVersionSlice.getNumber<uint64_t>();
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
if (newCurrentVersion == 0) {
|
||||
LOG_TOPIC(WARN, Logger::CLUSTER)
|
||||
<< "Attention: /arango/Current/Version in the agency is not set or "
|
||||
"not a positive number.";
|
||||
}
|
||||
|
||||
decltype(_currentDatabases) newDatabases;
|
||||
decltype(_currentCollections) newCollections;
|
||||
decltype(_shardIds) newShardIds;
|
||||
|
@ -758,7 +724,7 @@ void ClusterInfo::loadCurrent() {
|
|||
std::string const collectionName = collectionSlice.key.copyString();
|
||||
|
||||
auto collectionDataCurrent =
|
||||
std::make_shared<CollectionInfoCurrent>();
|
||||
std::make_shared<CollectionInfoCurrent>(newCurrentVersion);
|
||||
for (auto const& shardSlice :
|
||||
VPackObjectIterator(collectionSlice.value)) {
|
||||
std::string const shardID = shardSlice.key.copyString();
|
||||
|
@ -788,6 +754,7 @@ void ClusterInfo::loadCurrent() {
|
|||
// Now set the new value:
|
||||
WRITE_LOCKER(writeLocker, _currentProt.lock);
|
||||
_current = currentBuilder;
|
||||
_currentVersion = newCurrentVersion;
|
||||
if (swapDatabases) {
|
||||
_currentDatabases.swap(newDatabases);
|
||||
}
|
||||
|
@ -929,7 +896,7 @@ std::shared_ptr<CollectionInfoCurrent> ClusterInfo::getCollectionCurrent(
|
|||
loadCurrent();
|
||||
}
|
||||
|
||||
return std::make_shared<CollectionInfoCurrent>();
|
||||
return std::make_shared<CollectionInfoCurrent>(0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -56,23 +56,18 @@ class CollectionInfoCurrent {
|
|||
friend class ClusterInfo;
|
||||
|
||||
public:
|
||||
CollectionInfoCurrent();
|
||||
CollectionInfoCurrent(uint64_t currentVersion);
|
||||
|
||||
CollectionInfoCurrent(ShardID const&, VPackSlice);
|
||||
CollectionInfoCurrent(CollectionInfoCurrent const&) = delete;
|
||||
|
||||
CollectionInfoCurrent(CollectionInfoCurrent const&);
|
||||
CollectionInfoCurrent(CollectionInfoCurrent&&) = delete;
|
||||
|
||||
CollectionInfoCurrent(CollectionInfoCurrent&&);
|
||||
CollectionInfoCurrent& operator=(CollectionInfoCurrent const&) = delete;
|
||||
|
||||
CollectionInfoCurrent& operator=(CollectionInfoCurrent const&);
|
||||
|
||||
CollectionInfoCurrent& operator=(CollectionInfoCurrent&&);
|
||||
CollectionInfoCurrent& operator=(CollectionInfoCurrent&&) = delete;
|
||||
|
||||
~CollectionInfoCurrent();
|
||||
|
||||
private:
|
||||
void copyAllVPacks();
|
||||
|
||||
public:
|
||||
bool add(ShardID const& shardID, VPackSlice slice) {
|
||||
auto it = _vpacks.find(shardID);
|
||||
|
@ -177,6 +172,14 @@ class CollectionInfoCurrent {
|
|||
return std::string();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get version that underlies this info in Current in the agency
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t getCurrentVersion() const {
|
||||
return _currentVersion;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief local helper to return boolean flags
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -206,6 +209,9 @@ class CollectionInfoCurrent {
|
|||
|
||||
private:
|
||||
std::unordered_map<ShardID, std::shared_ptr<VPackBuilder>> _vpacks;
|
||||
|
||||
uint64_t _currentVersion; // Version of Current in the agency that
|
||||
// underpins the data presented in this object
|
||||
};
|
||||
|
||||
class ClusterInfo {
|
||||
|
@ -609,6 +615,12 @@ class ClusterInfo {
|
|||
|
||||
ProtectionData _planProt;
|
||||
|
||||
uint64_t _planVersion; // This is the version in the Plan which underlies
|
||||
// the data in _plannedCollections, _shards and
|
||||
// _shardKeys
|
||||
uint64_t _currentVersion; // This is the version in Current which underlies
|
||||
// the data in _currentDatabases,
|
||||
// _currentCollections and _shardsIds
|
||||
std::unordered_map<DatabaseID,
|
||||
std::unordered_map<ServerID, VPackSlice>>
|
||||
_currentDatabases; // from Current/Databases
|
||||
|
|
|
@ -706,6 +706,8 @@ static void JS_GetCollectionInfoCurrentClusterInfo(
|
|||
ClusterInfo::instance()->getCollectionCurrent(TRI_ObjectToString(args[0]),
|
||||
cid);
|
||||
|
||||
result->Set(TRI_V8_ASCII_STRING("currentVersion"),
|
||||
v8::Number::New(isolate, (double) cic->getCurrentVersion()));
|
||||
result->Set(TRI_V8_ASCII_STRING("type"),
|
||||
v8::Number::New(isolate, (int)ci->type()));
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "Aql/Query.h"
|
||||
#include "Aql/QueryRegistry.h"
|
||||
#include "Cluster/ClusterComm.h"
|
||||
#include "Cluster/ClusterHelpers.h"
|
||||
#include "Cluster/ClusterMethods.h"
|
||||
#include "Replication/InitialSyncer.h"
|
||||
#include "RestServer/QueryRegistryFeature.h"
|
||||
|
@ -476,7 +477,22 @@ void RestReplicationHandler::handleCommandClusterInventory() {
|
|||
resultBuilder.add(VPackValue("collections"));
|
||||
resultBuilder.openArray();
|
||||
for (auto const& c : cols) {
|
||||
c->toVelocyPackForClusterInventory(resultBuilder, includeSystem);
|
||||
// We want to check if the collection is usable and all followers
|
||||
// are in sync:
|
||||
auto shardMap = c->shardIds();
|
||||
// shardMap is an unordered_map from ShardId (string) to a vector of
|
||||
// servers (strings), wrapped in a shared_ptr
|
||||
auto cic = ci->getCollectionCurrent(dbName,
|
||||
basics::StringUtils::itoa(c->cid()));
|
||||
// Check all shards:
|
||||
bool isReady = true;
|
||||
for (auto const& p : *shardMap) {
|
||||
auto currentServerList = cic->servers(p.first /* shardId */);
|
||||
if (!ClusterHelpers::compareServerLists(p.second, currentServerList)) {
|
||||
isReady = false;
|
||||
}
|
||||
}
|
||||
c->toVelocyPackForClusterInventory(resultBuilder, includeSystem, isReady);
|
||||
}
|
||||
resultBuilder.close(); // collections
|
||||
TRI_voc_tick_t tick = TRI_CurrentTickServer();
|
||||
|
|
|
@ -166,7 +166,8 @@ LogicalCollection::LogicalCollection(LogicalCollection const& other)
|
|||
_keyOptions(other._keyOptions),
|
||||
_keyGenerator(KeyGenerator::factory(VPackSlice(keyOptions()))),
|
||||
_physical(other.getPhysical()->clone(this)),
|
||||
_clusterEstimateTTL(0) {
|
||||
_clusterEstimateTTL(0),
|
||||
_planVersion(other._planVersion) {
|
||||
TRI_ASSERT(_physical != nullptr);
|
||||
if (ServerState::instance()->isDBServer() ||
|
||||
!ServerState::instance()->isRunningInCluster()) {
|
||||
|
@ -206,7 +207,8 @@ LogicalCollection::LogicalCollection(TRI_vocbase_t* vocbase,
|
|||
_keyGenerator(),
|
||||
_physical(
|
||||
EngineSelectorFeature::ENGINE->createPhysicalCollection(this, info)),
|
||||
_clusterEstimateTTL(0) {
|
||||
_clusterEstimateTTL(0),
|
||||
_planVersion(0) {
|
||||
// add keyoptions from slice
|
||||
TRI_ASSERT(info.isObject());
|
||||
VPackSlice keyOpts = info.get("keyOptions");
|
||||
|
@ -795,7 +797,8 @@ void LogicalCollection::setStatus(TRI_vocbase_col_status_e status) {
|
|||
}
|
||||
|
||||
void LogicalCollection::toVelocyPackForClusterInventory(VPackBuilder& result,
|
||||
bool useSystem) const {
|
||||
bool useSystem,
|
||||
bool isReady) const {
|
||||
if (_isSystem && !useSystem) {
|
||||
return;
|
||||
}
|
||||
|
@ -823,6 +826,8 @@ void LogicalCollection::toVelocyPackForClusterInventory(VPackBuilder& result,
|
|||
|
||||
result.add(VPackValue("indexes"));
|
||||
getIndexesVPack(result, false, false);
|
||||
result.add("planVersion", VPackValue(getPlanVersion()));
|
||||
result.add("isReady", VPackValue(isReady));
|
||||
result.close(); // CollectionInfo
|
||||
}
|
||||
|
||||
|
|
|
@ -255,7 +255,8 @@ class LogicalCollection {
|
|||
bool forPersistence) const;
|
||||
|
||||
virtual void toVelocyPackForClusterInventory(velocypack::Builder&,
|
||||
bool useSystem) const;
|
||||
bool useSystem,
|
||||
bool isReady) const;
|
||||
|
||||
inline TRI_vocbase_t* vocbase() const { return _vocbase; }
|
||||
|
||||
|
@ -346,6 +347,14 @@ class LogicalCollection {
|
|||
// with the checksum provided in the reference checksum
|
||||
Result compareChecksums(velocypack::Slice checksumSlice, std::string const& referenceChecksum) const;
|
||||
|
||||
// Set and get _planVersion, this is only used if the object is used in
|
||||
// ClusterInfo to represent a cluster wide collection in the agency.
|
||||
void setPlanVersion(uint64_t v) {
|
||||
_planVersion = v;
|
||||
}
|
||||
uint64_t getPlanVersion() const {
|
||||
return _planVersion;
|
||||
}
|
||||
private:
|
||||
void prepareIndexes(velocypack::Slice indexesSlice);
|
||||
|
||||
|
@ -431,6 +440,12 @@ class LogicalCollection {
|
|||
std::unordered_map<std::string, double> _clusterEstimates;
|
||||
double _clusterEstimateTTL; //only valid if above vector is not empty
|
||||
basics::ReadWriteLock _clusterEstimatesLock;
|
||||
|
||||
uint64_t _planVersion; // Only set if setPlanVersion was called. This only
|
||||
// happens in ClusterInfo when this object is used
|
||||
// to represent a cluster wide collection. This is
|
||||
// then the version in the agency Plan that underpins
|
||||
// the information in this object. Otherwise 0.
|
||||
};
|
||||
|
||||
} // namespace arangodb
|
||||
|
|
Loading…
Reference in New Issue