mirror of https://gitee.com/bigwinds/arangodb
340 lines
13 KiB
C++
340 lines
13 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2018 ArangoDB 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 ArangoDB GmbH, Cologne, Germany
|
|
///
|
|
/// @author Simon Grätzer
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "ClusterIndexFactory.h"
|
|
#include "Basics/StaticStrings.h"
|
|
#include "Basics/StringUtils.h"
|
|
#include "Basics/VelocyPackHelper.h"
|
|
#include "Cluster/ServerState.h"
|
|
#include "ClusterEngine/ClusterEngine.h"
|
|
#include "ClusterEngine/ClusterIndex.h"
|
|
#include "Indexes/Index.h"
|
|
#include "Logger/LogMacros.h"
|
|
#include "Logger/Logger.h"
|
|
#include "Logger/LoggerStream.h"
|
|
#include "StorageEngine/EngineSelectorFeature.h"
|
|
#include "VocBase/LogicalCollection.h"
|
|
#include "VocBase/ticks.h"
|
|
#include "VocBase/voc-types.h"
|
|
|
|
#include <velocypack/Builder.h>
|
|
#include <velocypack/Iterator.h>
|
|
#include <velocypack/Slice.h>
|
|
#include <velocypack/velocypack-aliases.h>
|
|
|
|
namespace {
|
|
|
|
struct DefaultIndexFactory : public arangodb::IndexTypeFactory {
|
|
std::string const _type;
|
|
|
|
explicit DefaultIndexFactory(std::string const& type) : _type(type) {}
|
|
|
|
bool equal(arangodb::velocypack::Slice const& lhs,
|
|
arangodb::velocypack::Slice const& rhs) const override {
|
|
auto* clusterEngine =
|
|
static_cast<arangodb::ClusterEngine*>(arangodb::EngineSelectorFeature::ENGINE);
|
|
|
|
if (!clusterEngine) {
|
|
THROW_ARANGO_EXCEPTION(arangodb::Result(
|
|
TRI_ERROR_INTERNAL,
|
|
"cannot find cluster engine while normalizing index"));
|
|
}
|
|
|
|
auto* engine = clusterEngine->actualEngine();
|
|
|
|
if (!engine) {
|
|
THROW_ARANGO_EXCEPTION(arangodb::Result(
|
|
TRI_ERROR_INTERNAL,
|
|
"cannot find storage engine while normalizing index"));
|
|
}
|
|
|
|
return engine->indexFactory().factory(_type).equal(lhs, rhs);
|
|
}
|
|
|
|
std::shared_ptr<arangodb::Index> instantiate(arangodb::LogicalCollection& collection,
|
|
arangodb::velocypack::Slice const& definition, TRI_idx_iid_t id,
|
|
bool /* isClusterConstructor */) const override {
|
|
auto* clusterEngine =
|
|
static_cast<arangodb::ClusterEngine*>(arangodb::EngineSelectorFeature::ENGINE);
|
|
|
|
if (!clusterEngine) {
|
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
|
"cannot find cluster engine while creating index");
|
|
}
|
|
|
|
auto ct = clusterEngine->engineType();
|
|
|
|
return std::make_shared<arangodb::ClusterIndex>(id, collection, ct,
|
|
arangodb::Index::type(_type),
|
|
definition);
|
|
}
|
|
|
|
virtual arangodb::Result normalize( // normalize definition
|
|
arangodb::velocypack::Builder& normalized, // normalized definition (out-param)
|
|
arangodb::velocypack::Slice definition, // source definition
|
|
bool isCreation, // definition for index creation
|
|
TRI_vocbase_t const& vocbase // index vocbase
|
|
) const override {
|
|
auto* clusterEngine =
|
|
static_cast<arangodb::ClusterEngine*>(arangodb::EngineSelectorFeature::ENGINE);
|
|
|
|
if (!clusterEngine) {
|
|
return arangodb::Result(
|
|
TRI_ERROR_INTERNAL,
|
|
"cannot find cluster engine while normalizing index");
|
|
}
|
|
|
|
auto* engine = clusterEngine->actualEngine();
|
|
|
|
if (!engine) {
|
|
return arangodb::Result(
|
|
TRI_ERROR_INTERNAL,
|
|
"cannot find storage engine while normalizing index");
|
|
}
|
|
|
|
return engine->indexFactory().factory(_type).normalize( // normalize definition
|
|
normalized, definition, isCreation, vocbase // args
|
|
);
|
|
}
|
|
};
|
|
|
|
struct EdgeIndexFactory : public DefaultIndexFactory {
|
|
explicit EdgeIndexFactory(std::string const& type)
|
|
: DefaultIndexFactory(type) {}
|
|
|
|
std::shared_ptr<arangodb::Index> instantiate(arangodb::LogicalCollection& collection,
|
|
arangodb::velocypack::Slice const& definition,
|
|
TRI_idx_iid_t id, bool isClusterConstructor) const override {
|
|
if (!isClusterConstructor) {
|
|
// this index type cannot be created directly
|
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "cannot create edge index");
|
|
}
|
|
|
|
auto* clusterEngine =
|
|
static_cast<arangodb::ClusterEngine*>(arangodb::EngineSelectorFeature::ENGINE);
|
|
|
|
if (!clusterEngine) {
|
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
|
"cannot find storage engine while creating index");
|
|
}
|
|
|
|
auto ct = clusterEngine->engineType();
|
|
|
|
return std::make_shared<arangodb::ClusterIndex>(id, collection, ct,
|
|
arangodb::Index::TRI_IDX_TYPE_EDGE_INDEX,
|
|
definition);
|
|
}
|
|
};
|
|
|
|
struct PrimaryIndexFactory : public DefaultIndexFactory {
|
|
explicit PrimaryIndexFactory(std::string const& type)
|
|
: DefaultIndexFactory(type) {}
|
|
|
|
std::shared_ptr<arangodb::Index> instantiate(arangodb::LogicalCollection& collection,
|
|
arangodb::velocypack::Slice const& definition,
|
|
TRI_idx_iid_t id, bool isClusterConstructor) const override {
|
|
if (!isClusterConstructor) {
|
|
// this index type cannot be created directly
|
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "cannot create primary index");
|
|
}
|
|
|
|
auto* clusterEngine =
|
|
static_cast<arangodb::ClusterEngine*>(arangodb::EngineSelectorFeature::ENGINE);
|
|
|
|
if (!clusterEngine) {
|
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
|
"cannot find storage engine while creating index");
|
|
}
|
|
|
|
auto ct = clusterEngine->engineType();
|
|
|
|
return std::make_shared<arangodb::ClusterIndex>(0, collection, ct,
|
|
arangodb::Index::TRI_IDX_TYPE_PRIMARY_INDEX,
|
|
definition);
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
namespace arangodb {
|
|
|
|
ClusterIndexFactory::ClusterIndexFactory() {
|
|
static const EdgeIndexFactory edgeIndexFactory("edge");
|
|
static const DefaultIndexFactory fulltextIndexFactory("fulltext");
|
|
static const DefaultIndexFactory geoIndexFactory("geo");
|
|
static const DefaultIndexFactory geo1IndexFactory("geo1");
|
|
static const DefaultIndexFactory geo2IndexFactory("geo2");
|
|
static const DefaultIndexFactory hashIndexFactory("hash");
|
|
static const DefaultIndexFactory persistentIndexFactory("persistent");
|
|
static const PrimaryIndexFactory primaryIndexFactory("primary");
|
|
static const DefaultIndexFactory skiplistIndexFactory("skiplist");
|
|
static const DefaultIndexFactory ttlIndexFactory("ttl");
|
|
|
|
emplace(edgeIndexFactory._type, edgeIndexFactory);
|
|
emplace(fulltextIndexFactory._type, fulltextIndexFactory);
|
|
emplace(geoIndexFactory._type, geoIndexFactory);
|
|
emplace(geo1IndexFactory._type, geo1IndexFactory);
|
|
emplace(geo2IndexFactory._type, geo2IndexFactory);
|
|
emplace(hashIndexFactory._type, hashIndexFactory);
|
|
emplace(persistentIndexFactory._type, persistentIndexFactory);
|
|
emplace(primaryIndexFactory._type, primaryIndexFactory);
|
|
emplace(skiplistIndexFactory._type, skiplistIndexFactory);
|
|
emplace(ttlIndexFactory._type, ttlIndexFactory);
|
|
}
|
|
|
|
/// @brief index name aliases (e.g. "persistent" => "hash", "skiplist" =>
|
|
/// "hash") used to display storage engine capabilities
|
|
std::unordered_map<std::string, std::string> ClusterIndexFactory::indexAliases() const {
|
|
auto* ce = static_cast<ClusterEngine*>(EngineSelectorFeature::ENGINE);
|
|
auto* ae = ce->actualEngine();
|
|
if (!ae) {
|
|
THROW_ARANGO_EXCEPTION_MESSAGE(
|
|
TRI_ERROR_INTERNAL, "no actual storage engine for ClusterIndexFactory");
|
|
}
|
|
return ae->indexFactory().indexAliases();
|
|
}
|
|
|
|
Result ClusterIndexFactory::enhanceIndexDefinition( // normalize definition
|
|
velocypack::Slice const definition, // source definition
|
|
velocypack::Builder& normalized, // normalized definition (out-param)
|
|
bool isCreation, // definition for index creation
|
|
TRI_vocbase_t const& vocbase // index vocbase
|
|
) const {
|
|
auto* ce = static_cast<ClusterEngine*>(EngineSelectorFeature::ENGINE);
|
|
|
|
if (!ce) {
|
|
return TRI_ERROR_INTERNAL;
|
|
}
|
|
|
|
auto* ae = ce->actualEngine();
|
|
|
|
if (!ae) {
|
|
return TRI_ERROR_INTERNAL;
|
|
}
|
|
|
|
return ae->indexFactory().enhanceIndexDefinition( // normalize definition
|
|
definition, normalized, isCreation, vocbase // args
|
|
);
|
|
}
|
|
|
|
void ClusterIndexFactory::fillSystemIndexes(arangodb::LogicalCollection& col,
|
|
std::vector<std::shared_ptr<arangodb::Index>>& systemIndexes) const {
|
|
// create primary index
|
|
VPackBuilder input;
|
|
input.openObject();
|
|
input.add(StaticStrings::IndexType, VPackValue("primary"));
|
|
input.add(StaticStrings::IndexId, VPackValue("0"));
|
|
input.add(StaticStrings::IndexName, VPackValue(StaticStrings::IndexNamePrimary));
|
|
input.add(StaticStrings::IndexFields, VPackValue(VPackValueType::Array));
|
|
input.add(VPackValue(StaticStrings::KeyString));
|
|
input.close();
|
|
input.add(StaticStrings::IndexUnique, VPackValue(true));
|
|
input.add(StaticStrings::IndexSparse, VPackValue(false));
|
|
input.close();
|
|
|
|
// get the storage engine type
|
|
ClusterEngine* ce = static_cast<ClusterEngine*>(EngineSelectorFeature::ENGINE);
|
|
ClusterEngineType ct = ce->engineType();
|
|
|
|
systemIndexes.emplace_back(
|
|
std::make_shared<arangodb::ClusterIndex>(0, col, ct, Index::TRI_IDX_TYPE_PRIMARY_INDEX,
|
|
input.slice()));
|
|
|
|
// create edges indexes
|
|
if (col.type() == TRI_COL_TYPE_EDGE) {
|
|
// first edge index
|
|
input.clear();
|
|
input.openObject();
|
|
input.add(StaticStrings::IndexType,
|
|
VPackValue(Index::oldtypeName(Index::TRI_IDX_TYPE_EDGE_INDEX)));
|
|
input.add(StaticStrings::IndexId, VPackValue("1"));
|
|
|
|
input.add(StaticStrings::IndexFields, VPackValue(VPackValueType::Array));
|
|
input.add(VPackValue(StaticStrings::FromString));
|
|
if (ct == ClusterEngineType::MMFilesEngine) {
|
|
input.add(VPackValue(StaticStrings::ToString));
|
|
}
|
|
input.close();
|
|
|
|
if (ct == ClusterEngineType::MMFilesEngine) {
|
|
input.add(StaticStrings::IndexName, VPackValue(StaticStrings::IndexNameEdge));
|
|
} else if (ct == ClusterEngineType::RocksDBEngine) {
|
|
input.add(StaticStrings::IndexName, VPackValue(StaticStrings::IndexNameEdgeFrom));
|
|
}
|
|
|
|
input.add(StaticStrings::IndexUnique, VPackValue(false));
|
|
input.add(StaticStrings::IndexSparse, VPackValue(false));
|
|
input.close();
|
|
systemIndexes.emplace_back(
|
|
std::make_shared<arangodb::ClusterIndex>(1, col, ct, Index::TRI_IDX_TYPE_EDGE_INDEX,
|
|
input.slice()));
|
|
|
|
// second edge index
|
|
if (ct == ClusterEngineType::RocksDBEngine) {
|
|
input.clear();
|
|
input.openObject();
|
|
input.add(StaticStrings::IndexType,
|
|
VPackValue(Index::oldtypeName(Index::TRI_IDX_TYPE_EDGE_INDEX)));
|
|
input.add(StaticStrings::IndexId, VPackValue("2"));
|
|
input.add(StaticStrings::IndexName, VPackValue(StaticStrings::IndexNameEdgeTo));
|
|
input.add(StaticStrings::IndexFields, VPackValue(VPackValueType::Array));
|
|
input.add(VPackValue(StaticStrings::ToString));
|
|
input.close();
|
|
input.add(StaticStrings::IndexUnique, VPackValue(false));
|
|
input.add(StaticStrings::IndexSparse, VPackValue(false));
|
|
input.close();
|
|
systemIndexes.emplace_back(std::make_shared<arangodb::ClusterIndex>(
|
|
2, col, ct, Index::TRI_IDX_TYPE_EDGE_INDEX, input.slice()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ClusterIndexFactory::prepareIndexes(
|
|
LogicalCollection& col, arangodb::velocypack::Slice const& indexesSlice,
|
|
std::vector<std::shared_ptr<arangodb::Index>>& indexes) const {
|
|
TRI_ASSERT(indexesSlice.isArray());
|
|
|
|
for (VPackSlice v : VPackArrayIterator(indexesSlice)) {
|
|
if (!validateFieldsDefinition(v, 0, SIZE_MAX).ok()) {
|
|
// We have an error here. Do not add.
|
|
continue;
|
|
}
|
|
|
|
if (basics::VelocyPackHelper::getBooleanValue(v, StaticStrings::IndexIsBuilding, false)) {
|
|
// This index is still being built. Do not add.
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
auto idx = prepareIndexFromSlice(v, false, col, true);
|
|
TRI_ASSERT(idx != nullptr);
|
|
indexes.emplace_back(std::move(idx));
|
|
} catch (std::exception const& ex) {
|
|
LOG_TOPIC("7ed52", ERR, arangodb::Logger::ENGINES)
|
|
<< "error creating index from definition '" << v.toString() << "': " << ex.what();
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace arangodb
|