mirror of https://gitee.com/bigwinds/arangodb
issue 505.1: move index json comparison into index-type-specific implementations to address issue with incorrect definition comparison (#7430)
* issue 505: move index json comparison into index-type-specific implementations to address issue with incorrect definition comparison * remove commented-out code * fix typo * backport: add additional logging and fix typo
This commit is contained in:
parent
6ba81d7603
commit
e16be8f3db
|
@ -38,90 +38,199 @@
|
|||
#include <velocypack/Slice.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct DefaultIndexFactory: public arangodb::IndexTypeFactory {
|
||||
std::string const _type;
|
||||
|
||||
DefaultIndexFactory(std::string const& type): _type(type) {}
|
||||
|
||||
virtual 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);
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
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) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"cannot find cluster engine while creating index"
|
||||
);
|
||||
}
|
||||
|
||||
auto ct = clusterEngine->engineType();
|
||||
|
||||
index = std::make_shared<arangodb::ClusterIndex>(
|
||||
id, collection, ct, arangodb::Index::type(_type), definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) 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(
|
||||
normalized, definition, isCreation
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct EdgeIndexFactory: public DefaultIndexFactory {
|
||||
EdgeIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
return arangodb::Result(TRI_ERROR_INTERNAL, "cannot create edge index");
|
||||
}
|
||||
|
||||
auto* clusterEngine = static_cast<arangodb::ClusterEngine*>(
|
||||
arangodb::EngineSelectorFeature::ENGINE
|
||||
);
|
||||
|
||||
if (!clusterEngine) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"cannot find storage engine while creating index"
|
||||
);
|
||||
}
|
||||
|
||||
auto ct = clusterEngine->engineType();
|
||||
|
||||
index = std::make_shared<arangodb::ClusterIndex>(
|
||||
id, collection, ct, arangodb::Index::TRI_IDX_TYPE_EDGE_INDEX, definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
struct PrimaryIndexFactory: public DefaultIndexFactory {
|
||||
PrimaryIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"cannot create primary index"
|
||||
);
|
||||
}
|
||||
|
||||
auto* clusterEngine = static_cast<arangodb::ClusterEngine*>(
|
||||
arangodb::EngineSelectorFeature::ENGINE
|
||||
);
|
||||
|
||||
if (!clusterEngine) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"cannot find storage engine while creating index"
|
||||
);
|
||||
}
|
||||
|
||||
auto ct = clusterEngine->engineType();
|
||||
|
||||
index = std::make_shared<arangodb::ClusterIndex>(
|
||||
0, collection, ct, arangodb::Index::TRI_IDX_TYPE_PRIMARY_INDEX, definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
ClusterIndexFactory::ClusterIndexFactory() {
|
||||
emplaceFactory(
|
||||
"edge",
|
||||
[](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_INTERNAL, "cannot create edge index"
|
||||
);
|
||||
}
|
||||
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");
|
||||
|
||||
auto* ce = static_cast<ClusterEngine*>(EngineSelectorFeature::ENGINE);
|
||||
auto ct = ce->engineType();
|
||||
|
||||
return std::make_shared<ClusterIndex>(
|
||||
id, collection, ct, Index::TRI_IDX_TYPE_EDGE_INDEX, definition
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
emplaceFactory(
|
||||
"primary",
|
||||
[](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_INTERNAL, "cannot create primary index"
|
||||
);
|
||||
}
|
||||
|
||||
auto* ce = static_cast<ClusterEngine*>(EngineSelectorFeature::ENGINE);
|
||||
auto ct = ce->engineType();
|
||||
|
||||
return std::make_shared<ClusterIndex>(
|
||||
0, collection, ct, Index::TRI_IDX_TYPE_PRIMARY_INDEX, definition
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// both engines support all types right now
|
||||
static const std::vector<std::string> supported = {
|
||||
"fulltext",
|
||||
"geo",
|
||||
"geo1",
|
||||
"geo2",
|
||||
"hash",
|
||||
"persistent",
|
||||
"skiplist"
|
||||
};
|
||||
|
||||
for (auto& typeStr: supported) {
|
||||
auto type = Index::type(typeStr);
|
||||
|
||||
emplaceFactory(
|
||||
typeStr,
|
||||
[type](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
auto* ce = static_cast<ClusterEngine*>(EngineSelectorFeature::ENGINE);
|
||||
auto ct = ce->engineType();
|
||||
|
||||
return std::make_shared<ClusterIndex>(
|
||||
id, collection, ct, type, definition
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Result ClusterIndexFactory::enhanceIndexDefinition(VPackSlice const definition,
|
||||
VPackBuilder& normalized,
|
||||
bool isCreation,
|
||||
|
@ -239,4 +348,4 @@ void ClusterIndexFactory::prepareIndexes(
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -197,10 +197,10 @@ void registerFilters(arangodb::aql::AqlFunctionFeature& functions) {
|
|||
}
|
||||
|
||||
void registerIndexFactory() {
|
||||
static const std::map<std::string, arangodb::IndexFactory::IndexTypeFactory> factories = {
|
||||
{ "ClusterEngine", arangodb::iresearch::IResearchLinkCoordinator::make },
|
||||
{ "MMFilesEngine", arangodb::iresearch::IResearchMMFilesLink::make },
|
||||
{ "RocksDBEngine", arangodb::iresearch::IResearchRocksDBLink::make }
|
||||
static const std::map<std::string, arangodb::IndexTypeFactory const*> factories = {
|
||||
{ "ClusterEngine", &arangodb::iresearch::IResearchLinkCoordinator::factory() },
|
||||
{ "MMFilesEngine", &arangodb::iresearch::IResearchMMFilesLink::factory() },
|
||||
{ "RocksDBEngine", &arangodb::iresearch::IResearchRocksDBLink::factory() }
|
||||
};
|
||||
auto const& indexType = arangodb::iresearch::DATA_SOURCE_TYPE.name();
|
||||
|
||||
|
@ -220,7 +220,7 @@ void registerIndexFactory() {
|
|||
// ok to const-cast since this should only be called on startup
|
||||
auto& indexFactory =
|
||||
const_cast<arangodb::IndexFactory&>(engine->indexFactory());
|
||||
auto res = indexFactory.emplaceFactory(indexType, entry.second);
|
||||
auto res = indexFactory.emplace(indexType, *(entry.second));
|
||||
|
||||
if (!res.ok()) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
|
@ -228,17 +228,6 @@ void registerIndexFactory() {
|
|||
std::string("failure registering IResearch link factory with index factory from feature '") + entry.first + "': " + res.errorMessage()
|
||||
);
|
||||
}
|
||||
|
||||
res = indexFactory.emplaceNormalizer(
|
||||
indexType, arangodb::iresearch::IResearchLinkHelper::normalize
|
||||
);
|
||||
|
||||
if (!res.ok()) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
res.errorNumber(),
|
||||
std::string("failure registering IResearch link normalizer with index factory from feature '") + entry.first + "': " + res.errorMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -196,36 +196,35 @@ TRI_idx_iid_t IResearchLink::id() const noexcept {
|
|||
return _id;
|
||||
}
|
||||
|
||||
bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
|
||||
arangodb::Result IResearchLink::init(
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) {
|
||||
// disassociate from view if it has not been done yet
|
||||
if (!unload().ok()) {
|
||||
return false;
|
||||
return arangodb::Result(TRI_ERROR_INTERNAL, "failed to unload link");
|
||||
}
|
||||
|
||||
std::string error;
|
||||
IResearchLinkMeta meta;
|
||||
|
||||
if (!meta.init(definition, error)) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error parsing view link parameters from json: " << error;
|
||||
TRI_set_errno(TRI_ERROR_BAD_PARAMETER);
|
||||
|
||||
return false; // failed to parse metadata
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error parsing view link parameters from json: ") + error
|
||||
);
|
||||
}
|
||||
|
||||
if (!definition.isObject()
|
||||
|| !(definition.get(StaticStrings::ViewIdField).isString() ||
|
||||
definition.get(StaticStrings::ViewIdField).isNumber<TRI_voc_cid_t>())) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error finding view for link '" << _id << "'";
|
||||
TRI_set_errno(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
|
||||
|
||||
return false;
|
||||
|| !definition.get(StaticStrings::ViewIdField).isString()) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
|
||||
std::string("error finding view for link '") + std::to_string(_id) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
// we continue to support the old and new ID format
|
||||
auto idSlice = definition.get(StaticStrings::ViewIdField);
|
||||
std::string viewId = idSlice.isString() ? idSlice.copyString() : std::to_string(idSlice.getUInt());
|
||||
auto viewId = idSlice.copyString();
|
||||
auto& vocbase = _collection.vocbase();
|
||||
auto logicalView = vocbase.lookupView(viewId); // will only contain IResearchView (even for a DBServer)
|
||||
|
||||
|
@ -234,15 +233,15 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
|
|||
auto* ci = ClusterInfo::instance();
|
||||
|
||||
if (!ci) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failure to find 'ClusterInfo' instance for lookup of link '" << _id << "'";
|
||||
TRI_set_errno(TRI_ERROR_INTERNAL);
|
||||
|
||||
return false;
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure to find 'ClusterInfo' instance for lookup of link '") + std::to_string(_id) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
auto logicalWiew = ci->getView(vocbase.name(), viewId);
|
||||
auto* wiew = LogicalView::cast<IResearchViewDBServer>(logicalWiew.get());
|
||||
|
||||
if (wiew) {
|
||||
// FIXME figure out elegant way of testing for cluster wide LogicalCollection
|
||||
if (_collection.id() == _collection.planId() && _collection.isAStub()) {
|
||||
|
@ -265,7 +264,7 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
|
|||
}
|
||||
}
|
||||
|
||||
return true; // leave '_view' uninitialized to mark the index as unloaded/unusable
|
||||
return arangodb::Result(); // leave '_view' uninitialized to mark the index as unloaded/unusable
|
||||
}
|
||||
|
||||
logicalView = wiew->ensure(_collection.id()); // repoint LogicalView at the per-cid instance
|
||||
|
@ -274,41 +273,38 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
|
|||
|
||||
if (!logicalView
|
||||
|| arangodb::iresearch::DATA_SOURCE_TYPE != logicalView->type()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error finding view: '" << viewId << "' for link '" << _id << "' : no such view";
|
||||
|
||||
return false; // no such view
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
|
||||
std::string("error finding view: '") + viewId + "' for link '" + std::to_string(_id) + "' : no such view"
|
||||
);
|
||||
}
|
||||
|
||||
auto* view = LogicalView::cast<IResearchView>(logicalView.get());
|
||||
|
||||
if (!view) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error finding view: '" << viewId << "' for link '" << _id << "'";
|
||||
|
||||
return false;
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
|
||||
std::string("error finding view: '") + viewId + "' for link '" + std::to_string(_id) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
auto viewSelf = view->self();
|
||||
|
||||
if (!viewSelf) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error read-locking view: '" << viewId
|
||||
<< "' for link '" << _id << "'";
|
||||
|
||||
return false;
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("error read-locking view: '") + viewId + "' for link '" + std::to_string(_id) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
_viewLock = std::unique_lock<ReadMutex>(viewSelf->mutex()); // aquire read-lock before checking view
|
||||
|
||||
if (!viewSelf->get()) {
|
||||
_viewLock.unlock();
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error getting view: '" << viewId << "' for link '" << _id << "'";
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "have raw view '" << view->guid() << "'";
|
||||
|
||||
return false;
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("error getting view: '") + viewId + "' for link '" + std::to_string(_id) + "', have raw view '" + view->guid() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
_dropCollectionInDestructor = view->emplace(_collection.id()); // track if this is the instance that called emplace
|
||||
|
@ -325,7 +321,7 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) {
|
|||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
Result IResearchLink::insert(
|
||||
|
|
|
@ -177,7 +177,7 @@ class IResearchLink {
|
|||
/// @brief initialize from the specified definition used in make(...)
|
||||
/// @return success
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool init(arangodb::velocypack::Slice const& definition);
|
||||
arangodb::Result init(arangodb::velocypack::Slice const& definition);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @return the associated IResearch view or nullptr if not associated
|
||||
|
|
|
@ -27,9 +27,10 @@
|
|||
#include "IResearchFeature.h"
|
||||
#include "IResearchViewCoordinator.h"
|
||||
#include "VelocyPackHelper.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "ClusterEngine/ClusterEngine.h"
|
||||
#include "Cluster/ClusterInfo.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Indexes/IndexFactory.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "RocksDBEngine/RocksDBColumnFamily.h"
|
||||
#include "RocksDBEngine/RocksDBIndex.h"
|
||||
|
@ -41,6 +42,77 @@
|
|||
namespace arangodb {
|
||||
namespace iresearch {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief IResearchLinkCoordinator-specific implementation of an
|
||||
/// IndexTypeFactory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
struct IResearchLinkCoordinator::IndexFactory: public arangodb::IndexTypeFactory {
|
||||
virtual bool equal(
|
||||
arangodb::velocypack::Slice const& lhs,
|
||||
arangodb::velocypack::Slice const& rhs
|
||||
) const override {
|
||||
return arangodb::iresearch::IResearchLinkHelper::equal(lhs, rhs);
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
try {
|
||||
auto link = std::shared_ptr<IResearchLinkCoordinator>(
|
||||
new IResearchLinkCoordinator(id, collection)
|
||||
);
|
||||
auto res = link->init(definition);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
index = link;
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
e.code(),
|
||||
std::string("caught exception while creating arangosearch view Coordinator link '") + std::to_string(id) + "': " + e.what()
|
||||
);
|
||||
} catch (std::exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception while creating arangosearch view Coordinator link '") + std::to_string(id) + "': " + e.what()
|
||||
);
|
||||
} catch (...) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception while creating arangosearch view Coordinator link '") + std::to_string(id) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
return IResearchLinkHelper::normalize(normalized, definition, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
/*static*/ arangodb::IndexTypeFactory const& IResearchLinkCoordinator::factory() {
|
||||
static const IndexFactory factory;
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
/*static*/ std::shared_ptr<IResearchLinkCoordinator> IResearchLinkCoordinator::find(
|
||||
LogicalCollection const& collection,
|
||||
LogicalView const& view
|
||||
|
@ -75,29 +147,28 @@ bool IResearchLinkCoordinator::operator==(LogicalView const& view) const noexcep
|
|||
return _view && _view->id() == view.id();
|
||||
}
|
||||
|
||||
bool IResearchLinkCoordinator::init(VPackSlice definition) {
|
||||
arangodb::Result IResearchLinkCoordinator::init(
|
||||
arangodb::velocypack::Slice const& definition
|
||||
) {
|
||||
std::string error;
|
||||
|
||||
if (!_meta.init(definition, error)) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error parsing view link parameters from json: " << error;
|
||||
TRI_set_errno(TRI_ERROR_BAD_PARAMETER);
|
||||
|
||||
return false; // failed to parse metadata
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error parsing view link parameters from json: ") + error
|
||||
);
|
||||
}
|
||||
|
||||
if (!definition.isObject()
|
||||
|| !(definition.get(StaticStrings::ViewIdField).isString() ||
|
||||
definition.get(StaticStrings::ViewIdField).isNumber())) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error finding view for link '" << id() << "'";
|
||||
TRI_set_errno(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
|
||||
|
||||
return false;
|
||||
|| !definition.get(StaticStrings::ViewIdField).isString()) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
|
||||
std::string("error finding view for link '") + std::to_string(id()) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
auto idSlice = definition.get(StaticStrings::ViewIdField);
|
||||
std::string viewId = idSlice.isString() ? idSlice.copyString() : std::to_string(idSlice.getUInt());
|
||||
auto viewId = idSlice.copyString();
|
||||
auto& vocbase = _collection.vocbase();
|
||||
|
||||
TRI_ASSERT(ClusterInfo::instance());
|
||||
|
@ -105,9 +176,10 @@ bool IResearchLinkCoordinator::init(VPackSlice definition) {
|
|||
|
||||
if (!logicalView
|
||||
|| arangodb::iresearch::DATA_SOURCE_TYPE != logicalView->type()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error looking up view '" << viewId << "': no such view";
|
||||
return false; // no such view
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
|
||||
std::string("error looking up view '") + viewId + "': no such view"
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
|
||||
|
@ -117,55 +189,22 @@ bool IResearchLinkCoordinator::init(VPackSlice definition) {
|
|||
#endif
|
||||
|
||||
if (!view) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error finding view '" << viewId << "' for link '" << id() << "'";
|
||||
|
||||
return false;
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
|
||||
std::string("error finding view '") + viewId + "' for link '" + std::to_string(id()) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
if (!view->emplace(_collection.id(), _collection.name(), definition)) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error emplacing link to collection '" << _collection.name() << "' into arangosearch view '" << viewId << "' link '" << id() << "'";
|
||||
|
||||
return false;
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("error emplacing link to collection '") + _collection.name() + "' into arangosearch view '" + viewId + "' link '" + std::to_string(id()) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
_view = view;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*static*/ IResearchLinkCoordinator::ptr IResearchLinkCoordinator::make(
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool // isClusterConstructor
|
||||
) noexcept {
|
||||
try {
|
||||
PTR_NAMED(IResearchLinkCoordinator, ptr, id, collection);
|
||||
|
||||
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
|
||||
auto* link = dynamic_cast<IResearchLinkCoordinator*>(ptr.get());
|
||||
#else
|
||||
auto* link = static_cast<IResearchLinkCoordinator*>(ptr.get());
|
||||
#endif
|
||||
|
||||
return link && link->init(definition) ? ptr : nullptr;
|
||||
} catch (arangodb::basics::Exception& e) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating arangosearch view Coordinator link '" << id << "': " << e.code() << " " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
} catch (std::exception const& e) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating arangosearch view Coordinator link '" << id << "': " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
} catch (...) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while creating arangosearch view Coordinator link '" << id << "'";
|
||||
IR_LOG_EXCEPTION();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
bool IResearchLinkCoordinator::matchesDefinition(VPackSlice const& slice) const {
|
||||
|
@ -220,4 +259,4 @@ char const* IResearchLinkCoordinator::typeName() const {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -28,6 +28,12 @@
|
|||
#include "ClusterEngine/ClusterIndex.h"
|
||||
#include "IResearch/IResearchLinkMeta.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
struct IndexTypeFactory; // forward declaration
|
||||
|
||||
}
|
||||
|
||||
namespace arangodb {
|
||||
namespace iresearch {
|
||||
|
||||
|
@ -77,6 +83,11 @@ class IResearchLinkCoordinator final: public arangodb::ClusterIndex {
|
|||
|
||||
virtual int drop() override { return TRI_ERROR_NO_ERROR; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the factory for this type of index
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::IndexTypeFactory const& factory();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief finds first link between specified collection and view
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -107,17 +118,6 @@ class IResearchLinkCoordinator final: public arangodb::ClusterIndex {
|
|||
|
||||
virtual void load() override { /* NOOP */ }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create and initialize an iResearch View Link instance
|
||||
/// @return nullptr on failure
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static ptr make(
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) noexcept;
|
||||
|
||||
virtual bool matchesDefinition(
|
||||
arangodb::velocypack::Slice const& slice
|
||||
) const override;
|
||||
|
@ -153,6 +153,7 @@ class IResearchLinkCoordinator final: public arangodb::ClusterIndex {
|
|||
virtual void unload() override { /* NOOP */ }
|
||||
|
||||
private:
|
||||
struct IndexFactory; // forward declaration
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief construct an uninitialized IResearch link, must call init(...) after
|
||||
|
@ -166,7 +167,7 @@ class IResearchLinkCoordinator final: public arangodb::ClusterIndex {
|
|||
/// @brief initialize from the specified definition
|
||||
/// @return success
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool init(VPackSlice definition);
|
||||
arangodb::Result init(arangodb::velocypack::Slice const& definition);
|
||||
|
||||
IResearchLinkMeta _meta; // how this collection should be indexed
|
||||
std::shared_ptr<IResearchViewCoordinator> _view; // effectively the IResearch view itself (nullptr == not associated)
|
||||
|
|
|
@ -441,6 +441,48 @@ namespace iresearch {
|
|||
return emptySlice._slice;
|
||||
}
|
||||
|
||||
/*static*/ bool IResearchLinkHelper::equal(
|
||||
arangodb::velocypack::Slice const& lhs,
|
||||
arangodb::velocypack::Slice const& rhs
|
||||
) {
|
||||
if (!lhs.isObject() || !rhs.isObject()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto lhsViewSlice = lhs.get(StaticStrings::ViewIdField);
|
||||
auto rhsViewSlice = rhs.get(StaticStrings::ViewIdField);
|
||||
|
||||
if (!lhsViewSlice.equals(rhsViewSlice)) {
|
||||
if (!lhsViewSlice.isString() || !rhsViewSlice.isString()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ls = lhsViewSlice.copyString();
|
||||
auto rs = lhsViewSlice.copyString();
|
||||
|
||||
if (ls.size() > rs.size()) {
|
||||
std::swap(ls, rs);
|
||||
}
|
||||
|
||||
// in the cluster, we may have identifiers of the form
|
||||
// `cxxx/` and `cxxx/yyy` which should be considered equal if the
|
||||
// one is a prefix of the other up to the `/`
|
||||
if (ls.empty() ||
|
||||
ls.back() != '/' ||
|
||||
ls.compare(rs.substr(0, ls.size()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string errorField;
|
||||
IResearchLinkMeta lhsMeta;
|
||||
IResearchLinkMeta rhsMeta;
|
||||
|
||||
return lhsMeta.init(lhs, errorField)
|
||||
&& rhsMeta.init(rhs, errorField)
|
||||
&& lhsMeta == rhsMeta;
|
||||
}
|
||||
|
||||
/*static*/ arangodb::Result IResearchLinkHelper::normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
|
@ -624,4 +666,4 @@ namespace iresearch {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -50,6 +50,15 @@ struct IResearchLinkHelper {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
static velocypack::Slice const& emptyIndexSlice();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compare two link definitions for equivalience if used to create a
|
||||
/// link instance
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static bool equal(
|
||||
arangodb::velocypack::Slice const& lhs,
|
||||
arangodb::velocypack::Slice const& rhs
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief validate and copy required fields from the 'definition' into
|
||||
/// 'normalized'
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "Indexes/IndexFactory.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Logger/LogMacros.h"
|
||||
#include "MMFiles/MMFilesCollection.h"
|
||||
|
@ -34,6 +35,88 @@
|
|||
NS_BEGIN(arangodb)
|
||||
NS_BEGIN(iresearch)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief IResearchLinkCoordinator-specific implementation of an
|
||||
/// IndexTypeFactory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
struct IResearchMMFilesLink::IndexFactory: public arangodb::IndexTypeFactory {
|
||||
virtual bool equal(
|
||||
arangodb::velocypack::Slice const& lhs,
|
||||
arangodb::velocypack::Slice const& rhs
|
||||
) const override {
|
||||
return arangodb::iresearch::IResearchLinkHelper::equal(lhs, rhs);
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
try {
|
||||
// ensure loaded so that we have valid data in next check
|
||||
if (TRI_VOC_COL_STATUS_LOADED != collection.status()) {
|
||||
collection.load();
|
||||
}
|
||||
|
||||
// try casting underlying collection to an MMFilesCollection
|
||||
// this may not succeed because we may have to deal with a PhysicalCollectionMock here
|
||||
auto mmfilesCollection =
|
||||
dynamic_cast<arangodb::MMFilesCollection*>(collection.getPhysical());
|
||||
|
||||
if (mmfilesCollection && !mmfilesCollection->hasAllPersistentLocalIds()) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"mmfiles collection uses pre-3.4 format and cannot be linked to an arangosearch view; try recreating collection and moving the contents to the new collection"
|
||||
);
|
||||
}
|
||||
|
||||
auto link = std::shared_ptr<IResearchMMFilesLink>(
|
||||
new IResearchMMFilesLink(id, collection)
|
||||
);
|
||||
auto res = link->init(definition);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
index = link;
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
e.code(),
|
||||
std::string("caught exception while creating arangosearch view MMFiles link '") + std::to_string(id) + "': " + e.what()
|
||||
);
|
||||
} catch (std::exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception while creating arangosearch view MMFiles link '") + std::to_string(id) + "': " + e.what()
|
||||
);
|
||||
} catch (...) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception while creating arangosearch view MMFiles link '") + std::to_string(id) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
return IResearchLinkHelper::normalize(normalized, definition, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
IResearchMMFilesLink::IResearchMMFilesLink(
|
||||
TRI_idx_iid_t iid,
|
||||
arangodb::LogicalCollection& collection
|
||||
|
@ -48,57 +131,10 @@ IResearchMMFilesLink::~IResearchMMFilesLink() {
|
|||
// NOOP
|
||||
}
|
||||
|
||||
/*static*/ IResearchMMFilesLink::ptr IResearchMMFilesLink::make(
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) noexcept {
|
||||
try {
|
||||
PTR_NAMED(IResearchMMFilesLink, ptr, id, collection);
|
||||
/*static*/ arangodb::IndexTypeFactory const& IResearchMMFilesLink::factory() {
|
||||
static const IndexFactory factory;
|
||||
|
||||
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
|
||||
auto* link = dynamic_cast<arangodb::iresearch::IResearchMMFilesLink*>(ptr.get());
|
||||
#else
|
||||
auto* link = static_cast<arangodb::iresearch::IResearchMMFilesLink*>(ptr.get());
|
||||
#endif
|
||||
|
||||
// ensure loaded so that we have valid data in next check
|
||||
if (TRI_VOC_COL_STATUS_LOADED != collection.status()) {
|
||||
collection.load();
|
||||
}
|
||||
|
||||
bool hasAllPersistentLocalIds = true;
|
||||
// try casting underlying collection to an MMFilesCollection
|
||||
// this may not succeed because we may have to deal with a PhysicalCollectionMock here
|
||||
auto mmfilesCollection = dynamic_cast<arangodb::MMFilesCollection*>(collection.getPhysical());
|
||||
if (mmfilesCollection != nullptr) {
|
||||
hasAllPersistentLocalIds = mmfilesCollection->hasAllPersistentLocalIds();
|
||||
}
|
||||
if (!hasAllPersistentLocalIds) {
|
||||
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
|
||||
<< "mmfiles collection uses pre-3.4 format and cannot be linked to an "
|
||||
<< "arangosearch view; try recreating collection and moving the "
|
||||
<< "contents to the new collection";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return link && link->init(definition) ? ptr : nullptr;
|
||||
} catch (arangodb::basics::Exception& e) {
|
||||
LOG_TOPIC(WARN, Logger::DEVEL)
|
||||
<< "caught exception while creating arangosearch view MMFiles link '" << id << "': " << e.code() << " " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
} catch (std::exception const& e) {
|
||||
LOG_TOPIC(WARN, Logger::DEVEL)
|
||||
<< "caught exception while creating arangosearch view MMFiles link '" << id << "': " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
} catch (...) {
|
||||
LOG_TOPIC(WARN, Logger::DEVEL)
|
||||
<< "caught exception while creating arangosearch view MMFiles link '" << id << "'";
|
||||
IR_LOG_EXCEPTION();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return factory;
|
||||
}
|
||||
|
||||
void IResearchMMFilesLink::toVelocyPack(
|
||||
|
@ -138,4 +174,4 @@ NS_END // arangodb
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -28,6 +28,12 @@
|
|||
|
||||
#include "Indexes/Index.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
struct IndexTypeFactory; // forward declaration
|
||||
|
||||
}
|
||||
|
||||
NS_BEGIN(arangodb)
|
||||
NS_BEGIN(iresearch)
|
||||
|
||||
|
@ -58,6 +64,11 @@ class IResearchMMFilesLink final
|
|||
return IResearchLink::drop().errorNumber();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the factory for this type of index
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::IndexTypeFactory const& factory();
|
||||
|
||||
virtual bool hasBatchInsert() const override {
|
||||
return IResearchLink::hasBatchInsert();
|
||||
}
|
||||
|
@ -87,17 +98,6 @@ class IResearchMMFilesLink final
|
|||
IResearchLink::load();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create and initialize an iResearch View Link instance
|
||||
/// @return nullptr on failure
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static ptr make(
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) noexcept;
|
||||
|
||||
virtual bool matchesDefinition(
|
||||
arangodb::velocypack::Slice const& slice
|
||||
) const override {
|
||||
|
@ -144,6 +144,8 @@ class IResearchMMFilesLink final
|
|||
}
|
||||
|
||||
private:
|
||||
struct IndexFactory; // forward declaration
|
||||
|
||||
IResearchMMFilesLink(
|
||||
TRI_idx_iid_t iid,
|
||||
arangodb::LogicalCollection& collection
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Basics/Common.h" // required for RocksDBColumnFamily.h
|
||||
#include "Indexes/IndexFactory.h"
|
||||
#include "IResearch/IResearchFeature.h"
|
||||
#include "Logger/LogMacros.h"
|
||||
#include "Logger/Logger.h"
|
||||
|
@ -36,6 +37,71 @@
|
|||
NS_BEGIN(arangodb)
|
||||
NS_BEGIN(iresearch)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief IResearchLinkCoordinator-specific implementation of an
|
||||
/// IndexTypeFactory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
struct IResearchRocksDBLink::IndexFactory: public arangodb::IndexTypeFactory {
|
||||
virtual bool equal(
|
||||
arangodb::velocypack::Slice const& lhs,
|
||||
arangodb::velocypack::Slice const& rhs
|
||||
) const override {
|
||||
return arangodb::iresearch::IResearchLinkHelper::equal(lhs, rhs);
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
try {
|
||||
auto link = std::shared_ptr<IResearchRocksDBLink>(
|
||||
new IResearchRocksDBLink(id, collection)
|
||||
);
|
||||
auto res = link->init(definition);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
index = link;
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
e.code(),
|
||||
std::string("caught exception while creating arangosearch view RocksDB link '") + std::to_string(id) + "': " + e.what()
|
||||
);
|
||||
} catch (std::exception const& e) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception while creating arangosearch view RocksDB link '") + std::to_string(id) + "': " + e.what()
|
||||
);
|
||||
} catch (...) {
|
||||
IR_LOG_EXCEPTION();
|
||||
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("caught exception while creating arangosearch view RocksDB link '") + std::to_string(id) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
return IResearchLinkHelper::normalize(normalized, definition, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
IResearchRocksDBLink::IResearchRocksDBLink(
|
||||
TRI_idx_iid_t iid,
|
||||
arangodb::LogicalCollection& collection
|
||||
|
@ -52,39 +118,10 @@ IResearchRocksDBLink::~IResearchRocksDBLink() {
|
|||
// NOOP
|
||||
}
|
||||
|
||||
/*static*/ IResearchRocksDBLink::ptr IResearchRocksDBLink::make(
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) noexcept {
|
||||
try {
|
||||
PTR_NAMED(IResearchRocksDBLink, ptr, id, collection);
|
||||
/*static*/ arangodb::IndexTypeFactory const& IResearchRocksDBLink::factory() {
|
||||
static const IndexFactory factory;
|
||||
|
||||
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
|
||||
auto* link =
|
||||
dynamic_cast<arangodb::iresearch::IResearchRocksDBLink*>(ptr.get());
|
||||
#else
|
||||
auto* link =
|
||||
static_cast<arangodb::iresearch::IResearchRocksDBLink*>(ptr.get());
|
||||
#endif
|
||||
|
||||
return link && link->init(definition) ? ptr : nullptr;
|
||||
} catch (arangodb::basics::Exception& e) {
|
||||
LOG_TOPIC(WARN, Logger::DEVEL)
|
||||
<< "caught exception while creating arangosearch view RocksDB link '" << id << "': " << e.code() << " " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
} catch (std::exception const& e) {
|
||||
LOG_TOPIC(WARN, Logger::DEVEL)
|
||||
<< "caught exception while creating arangosearch view RocksDB link '" << id << "': " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
} catch (...) {
|
||||
LOG_TOPIC(WARN, Logger::DEVEL)
|
||||
<< "caught exception while creating arangosearch view RocksDB link '" << id << "'";
|
||||
IR_LOG_EXCEPTION();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return factory;
|
||||
}
|
||||
|
||||
void IResearchRocksDBLink::toVelocyPack(
|
||||
|
@ -144,4 +181,4 @@ NS_END // arangodb
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -28,6 +28,12 @@
|
|||
|
||||
#include "RocksDBEngine/RocksDBIndex.h"
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
struct IndexTypeFactory; // forward declaration
|
||||
|
||||
}
|
||||
|
||||
NS_BEGIN(arangodb)
|
||||
NS_BEGIN(iresearch)
|
||||
|
||||
|
@ -60,6 +66,11 @@ class IResearchRocksDBLink final
|
|||
return IResearchLink::drop().errorNumber();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the factory for this type of index
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static arangodb::IndexTypeFactory const& factory();
|
||||
|
||||
virtual bool hasBatchInsert() const override {
|
||||
return IResearchLink::hasBatchInsert();
|
||||
}
|
||||
|
@ -86,17 +97,6 @@ class IResearchRocksDBLink final
|
|||
IResearchLink::load();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create and initialize a RocksDB IResearch View Link instance
|
||||
/// @return nullptr on failure
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static ptr make(
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) noexcept;
|
||||
|
||||
virtual bool matchesDefinition(
|
||||
arangodb::velocypack::Slice const& slice
|
||||
) const override {
|
||||
|
@ -144,11 +144,14 @@ class IResearchRocksDBLink final
|
|||
}
|
||||
|
||||
private:
|
||||
void writeRocksWalMarker();
|
||||
struct IndexFactory; // forward declaration
|
||||
|
||||
IResearchRocksDBLink(
|
||||
TRI_idx_iid_t iid,
|
||||
arangodb::LogicalCollection& collection
|
||||
);
|
||||
|
||||
void writeRocksWalMarker();
|
||||
};
|
||||
|
||||
NS_END // iresearch
|
||||
|
|
|
@ -2139,4 +2139,4 @@ void IResearchView::verifyKnownCollections() {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -37,6 +37,8 @@
|
|||
#include "IResearch/IResearchCommon.h"
|
||||
#endif
|
||||
|
||||
#include "StorageEngine/EngineSelectorFeature.h"
|
||||
#include "StorageEngine/StorageEngine.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
#include "VocBase/ticks.h"
|
||||
|
||||
|
@ -372,121 +374,10 @@ bool Index::Compare(VPackSlice const& lhs, VPackSlice const& rhs) {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto type = Index::type(lhsType.copyString());
|
||||
auto* engine = EngineSelectorFeature::ENGINE;
|
||||
|
||||
// unique must be identical if present
|
||||
auto value = lhs.get(arangodb::StaticStrings::IndexUnique);
|
||||
|
||||
if (value.isBoolean()) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get(arangodb::StaticStrings::IndexUnique), false
|
||||
) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// sparse must be identical if present
|
||||
value = lhs.get(arangodb::StaticStrings::IndexSparse);
|
||||
|
||||
if (value.isBoolean()) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get(arangodb::StaticStrings::IndexSparse), false
|
||||
) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == IndexType::TRI_IDX_TYPE_GEO1_INDEX ||
|
||||
type == IndexType::TRI_IDX_TYPE_GEO_INDEX) {
|
||||
// geoJson must be identical if present
|
||||
value = lhs.get("geoJson");
|
||||
if (value.isBoolean()) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(value, rhs.get("geoJson"),
|
||||
false) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (type == IndexType::TRI_IDX_TYPE_FULLTEXT_INDEX) {
|
||||
// minLength
|
||||
value = lhs.get("minLength");
|
||||
if (value.isNumber()) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get("minLength"), false) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef USE_IRESEARCH
|
||||
else if (type == IndexType::TRI_IDX_TYPE_IRESEARCH_LINK) {
|
||||
// FIXME TODO the check below is insufficient and will lead to false-positives since there are other IResearchLink-specific properties which may differ
|
||||
// FIXME TODO use IndexFactory::compare(...) instead
|
||||
// must check if the "view" field is the same, otherwise we may confuse
|
||||
// two links for different views on the same collection
|
||||
auto lhValue = lhs.get("view");
|
||||
auto rhValue = rhs.get("view");
|
||||
if (lhValue.isString() && rhValue.isString()) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get("view"), false) != 0) {
|
||||
auto ls = lhValue.copyString();
|
||||
auto rs = rhValue.copyString();
|
||||
if (ls.size() > rs.size()) {
|
||||
std::swap(ls, rs);
|
||||
}
|
||||
// in the cluster, we may have identifiers of the form
|
||||
// `cxxx/` and `cxxx/yyy` which should be considered equal if the
|
||||
// one is a prefix of the other up to the `/`
|
||||
if (ls.empty() ||
|
||||
ls.back() != '/' ||
|
||||
ls.compare(rs.substr(0, ls.size())) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// other index types: fields must be identical if present
|
||||
value = lhs.get(arangodb::StaticStrings::IndexFields);
|
||||
|
||||
if (value.isArray()) {
|
||||
if (type == IndexType::TRI_IDX_TYPE_HASH_INDEX) {
|
||||
VPackValueLength const nv = value.length();
|
||||
|
||||
// compare fields in arbitrary order
|
||||
auto r = rhs.get(arangodb::StaticStrings::IndexFields);
|
||||
|
||||
if (!r.isArray() || nv != r.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nv; ++i) {
|
||||
VPackSlice const v = value.at(i);
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto const& vr : VPackArrayIterator(r)) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(v, vr, false) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get(arangodb::StaticStrings::IndexFields), false
|
||||
) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return engine
|
||||
&& engine->indexFactory().factory(lhsType.copyString()).equal(lhs, rhs);
|
||||
}
|
||||
|
||||
/// @brief return a contextual string for logging
|
||||
|
@ -1053,4 +944,4 @@ std::ostream& operator<<(std::ostream& stream, arangodb::Index const& index) {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -29,27 +29,59 @@
|
|||
#include "Cluster/ServerState.h"
|
||||
#include "Indexes/Index.h"
|
||||
#include "RestServer/BootstrapFeature.h"
|
||||
#include "VocBase/LogicalCollection.h"
|
||||
|
||||
#include <velocypack/Slice.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct InvalidIndexFactory: public arangodb::IndexTypeFactory {
|
||||
virtual bool equal(
|
||||
arangodb::velocypack::Slice const&,
|
||||
arangodb::velocypack::Slice const&
|
||||
) const override {
|
||||
return false; // invalid definitions are never equal
|
||||
}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>&,
|
||||
arangodb::LogicalCollection&,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t,
|
||||
bool
|
||||
) const override {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("failure to instantiate index without a factory for definition: ") + definition.toString()
|
||||
);
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder&,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool
|
||||
) const override {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("failure to normalize index without a factory for definition: ") + definition.toString()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
InvalidIndexFactory const INVALID;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
void IndexFactory::clear() {
|
||||
_factories.clear();
|
||||
_normalizers.clear();
|
||||
}
|
||||
|
||||
Result IndexFactory::emplaceFactory(
|
||||
Result IndexFactory::emplace(
|
||||
std::string const& type,
|
||||
IndexTypeFactory const& factory
|
||||
) {
|
||||
if (!factory) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("index factory undefined during index factory registration for index type '") + type + "'"
|
||||
);
|
||||
}
|
||||
|
||||
auto* feature =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature("Bootstrap");
|
||||
auto* bootstrapFeature = dynamic_cast<BootstrapFeature*>(feature);
|
||||
|
@ -62,7 +94,7 @@ Result IndexFactory::emplaceFactory(
|
|||
);
|
||||
}
|
||||
|
||||
if (!_factories.emplace(type, factory).second) {
|
||||
if (!_factories.emplace(type, &factory).second) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DUPLICATE_IDENTIFIER,
|
||||
std::string("index factory previously registered during index factory registration for index type '") + type + "'"
|
||||
|
@ -72,39 +104,6 @@ Result IndexFactory::emplaceFactory(
|
|||
return arangodb::Result();
|
||||
}
|
||||
|
||||
Result IndexFactory::emplaceNormalizer(
|
||||
std::string const& type,
|
||||
IndexNormalizer const& normalizer
|
||||
) {
|
||||
if (!normalizer) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("index normalizer undefined during index normalizer registration for index type '") + type + "'"
|
||||
);
|
||||
}
|
||||
|
||||
auto* feature =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature("Bootstrap");
|
||||
auto* bootstrapFeature = dynamic_cast<BootstrapFeature*>(feature);
|
||||
|
||||
// ensure new normalizers are not added at runtime since that would require additional locks
|
||||
if (bootstrapFeature && bootstrapFeature->isReady()) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("index normalizer registration is only allowed during server startup")
|
||||
);
|
||||
}
|
||||
|
||||
if (!_normalizers.emplace(type, normalizer).second) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DUPLICATE_IDENTIFIER,
|
||||
std::string("index normalizer previously registered during index normalizer registration for index type '") + type + "'"
|
||||
);
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
Result IndexFactory::enhanceIndexDefinition(
|
||||
velocypack::Slice const definition,
|
||||
velocypack::Builder& normalized,
|
||||
|
@ -117,12 +116,7 @@ Result IndexFactory::enhanceIndexDefinition(
|
|||
return TRI_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
auto typeString = type.copyString();
|
||||
auto itr = _normalizers.find(typeString);
|
||||
|
||||
if (itr == _normalizers.end()) {
|
||||
return TRI_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
auto& factory = IndexFactory::factory(type.copyString());
|
||||
|
||||
TRI_ASSERT(ServerState::instance()->isCoordinator() == isCoordinator);
|
||||
TRI_ASSERT(normalized.isEmpty());
|
||||
|
@ -145,7 +139,7 @@ Result IndexFactory::enhanceIndexDefinition(
|
|||
);
|
||||
}
|
||||
|
||||
return itr->second(normalized, definition, isCreation);
|
||||
return factory.normalize(normalized, definition, isCreation);
|
||||
} catch (basics::Exception const& ex) {
|
||||
return ex.code();
|
||||
} catch (std::exception const&) {
|
||||
|
@ -155,6 +149,15 @@ Result IndexFactory::enhanceIndexDefinition(
|
|||
}
|
||||
}
|
||||
|
||||
const IndexTypeFactory& IndexFactory::factory(
|
||||
std::string const& type
|
||||
) const noexcept {
|
||||
auto itr = _factories.find(type);
|
||||
TRI_ASSERT(itr == _factories.end() || false == !(itr->second)); // IndexFactory::emplace(...) inserts non-nullptr
|
||||
|
||||
return itr == _factories.end() ? INVALID : *(itr->second);
|
||||
}
|
||||
|
||||
std::shared_ptr<Index> IndexFactory::prepareIndexFromSlice(
|
||||
velocypack::Slice definition,
|
||||
bool generateKey,
|
||||
|
@ -170,17 +173,29 @@ std::shared_ptr<Index> IndexFactory::prepareIndexFromSlice(
|
|||
);
|
||||
}
|
||||
|
||||
auto typeString = type.copyString();
|
||||
auto itr = _factories.find(typeString);
|
||||
auto& factory = IndexFactory::factory(type.copyString());
|
||||
std::shared_ptr<Index> index;
|
||||
auto res = factory.instantiate(
|
||||
index, collection, definition, id, isClusterConstructor
|
||||
);
|
||||
|
||||
if (itr == _factories.end()) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_NOT_IMPLEMENTED,
|
||||
std::string("invalid or unsupported index type '") + typeString + "'"
|
||||
);
|
||||
if (!res.ok()) {
|
||||
TRI_set_errno(res.errorNumber());
|
||||
LOG_TOPIC(ERR, arangodb::Logger::ENGINES)
|
||||
<< "failed to instantiate index, error: " << res.errorNumber() << " " << res.errorMessage();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return itr->second(collection, definition, id, isClusterConstructor);
|
||||
if (!index) {
|
||||
TRI_set_errno(TRI_ERROR_INTERNAL);
|
||||
LOG_TOPIC(ERR, arangodb::Logger::ENGINES)
|
||||
<< "failed to instantiate index, factory returned null instance";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/// same for both storage engines
|
||||
|
|
|
@ -37,54 +37,49 @@ class Builder;
|
|||
class Slice;
|
||||
}
|
||||
|
||||
class IndexFactory {
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief typedef for a Index factory function
|
||||
/// This typedef is used when registering the factory function for any index
|
||||
/// type. The factory function is called when a index is first created or
|
||||
/// re-opened after a server restart. The VelocyPack Slice will contain all
|
||||
/// information about the indexs' general and implementation-specific
|
||||
/// properties.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
typedef std::function<std::shared_ptr<Index>(
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition, // index definition
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)> IndexTypeFactory;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief factory for comparing/instantiating/normalizing a definition for a
|
||||
/// specific Index type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
struct IndexTypeFactory {
|
||||
virtual ~IndexTypeFactory() = default; // define to silence warning
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief typedef for a Index definition normalizer function
|
||||
/// This typedef is used when registering the normalizer function for any
|
||||
/// index type. The normalizer function is called when a index definition
|
||||
/// needs to be normalized before using it to create the index. The resulting
|
||||
/// VelocyBuilder will contain the 'type' that should be used for index
|
||||
/// factory lookup (if no normalizer is registered then use the original type)
|
||||
/// @brief determine if the two Index definitions will result in the same
|
||||
/// index once instantiated
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
typedef std::function<Result(
|
||||
virtual bool equal(
|
||||
velocypack::Slice const& lhs,
|
||||
velocypack::Slice const& rhs
|
||||
) const = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief instantiate an Index definition
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
virtual Result instantiate(
|
||||
std::shared_ptr<Index>& index,
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief normalize an Index definition prior to instantiation/persistence
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
virtual Result normalize(
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)> IndexNormalizer;
|
||||
|
||||
IndexFactory() = default;
|
||||
IndexFactory(IndexFactory const&) = delete;
|
||||
IndexFactory& operator=(IndexFactory const&) = delete;
|
||||
) const = 0;
|
||||
};
|
||||
|
||||
class IndexFactory {
|
||||
public:
|
||||
virtual ~IndexFactory() = default;
|
||||
|
||||
/// @return 'factory' for 'type' was added successfully
|
||||
Result emplaceFactory(
|
||||
std::string const& type,
|
||||
IndexTypeFactory const& factory
|
||||
);
|
||||
|
||||
/// @return 'normalizer' for 'type' was added successfully
|
||||
Result emplaceNormalizer(
|
||||
std::string const& type,
|
||||
IndexNormalizer const& normalizer
|
||||
);
|
||||
Result emplace(std::string const& type, IndexTypeFactory const& factory);
|
||||
|
||||
virtual Result enhanceIndexDefinition(
|
||||
velocypack::Slice const definition,
|
||||
|
@ -93,6 +88,9 @@ class IndexFactory {
|
|||
bool isCoordinator
|
||||
) const;
|
||||
|
||||
/// @return factory for the specified type or a failing placeholder if no such type
|
||||
IndexTypeFactory const& factory(std::string const& type) const noexcept;
|
||||
|
||||
std::shared_ptr<Index> prepareIndexFromSlice(
|
||||
velocypack::Slice definition,
|
||||
bool generateKey,
|
||||
|
@ -125,10 +123,9 @@ class IndexFactory {
|
|||
bool isClusterConstructor);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, IndexTypeFactory> _factories;
|
||||
std::unordered_map<std::string, IndexNormalizer> _normalizers;
|
||||
std::unordered_map<std::string, IndexTypeFactory const*> _factories;
|
||||
};
|
||||
|
||||
} // namespace arangodb
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -319,107 +319,128 @@ static int EnhanceJsonIndexFulltext(VPackSlice const definition,
|
|||
return res;
|
||||
}
|
||||
|
||||
MMFilesIndexFactory::MMFilesIndexFactory() {
|
||||
emplaceFactory("edge", [](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_INTERNAL, "cannot create edge index"
|
||||
);
|
||||
namespace {
|
||||
|
||||
struct DefaultIndexFactory: public arangodb::IndexTypeFactory {
|
||||
std::string const _type;
|
||||
|
||||
DefaultIndexFactory(std::string const& type): _type(type) {}
|
||||
|
||||
virtual bool equal(
|
||||
arangodb::velocypack::Slice const& lhs,
|
||||
arangodb::velocypack::Slice const& rhs
|
||||
) const override {
|
||||
// unique must be identical if present
|
||||
auto value = lhs.get(arangodb::StaticStrings::IndexUnique);
|
||||
|
||||
if (value.isBoolean()) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get(arangodb::StaticStrings::IndexUnique), false
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_shared<MMFilesEdgeIndex>(id, collection);
|
||||
});
|
||||
// sparse must be identical if present
|
||||
value = lhs.get(arangodb::StaticStrings::IndexSparse);
|
||||
|
||||
emplaceFactory("fulltext", [](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
return std::make_shared<MMFilesFulltextIndex>(id, collection, definition);
|
||||
});
|
||||
|
||||
emplaceFactory("geo1", [](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
return std::make_shared<MMFilesGeoIndex>(id, collection, definition, "geo1");
|
||||
});
|
||||
|
||||
emplaceFactory("geo2", [](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
return std::make_shared<MMFilesGeoIndex>(id, collection, definition, "geo2");
|
||||
});
|
||||
|
||||
emplaceFactory("geo", [](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
return std::make_shared<MMFilesGeoIndex>(id, collection, definition, "geo");
|
||||
});
|
||||
|
||||
emplaceFactory("hash", [](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
return std::make_shared<MMFilesHashIndex>(id, collection, definition);
|
||||
});
|
||||
|
||||
emplaceFactory("persistent", [](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
return std::make_shared<MMFilesPersistentIndex>(id, collection, definition);
|
||||
});
|
||||
|
||||
emplaceFactory("primary", [](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_INTERNAL, "cannot create primary index"
|
||||
);
|
||||
if (value.isBoolean()) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get(arangodb::StaticStrings::IndexSparse), false
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_shared<MMFilesPrimaryIndex>(collection);
|
||||
});
|
||||
auto type = Index::type(_type);
|
||||
|
||||
emplaceFactory("skiplist", [](
|
||||
LogicalCollection& collection,
|
||||
velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
)->std::shared_ptr<Index> {
|
||||
return std::make_shared<MMFilesSkiplistIndex>(id, collection, definition);
|
||||
});
|
||||
if (arangodb::Index::IndexType::TRI_IDX_TYPE_GEO1_INDEX == type||
|
||||
arangodb::Index::IndexType::TRI_IDX_TYPE_GEO_INDEX == type) {
|
||||
// geoJson must be identical if present
|
||||
value = lhs.get("geoJson");
|
||||
|
||||
emplaceNormalizer("edge", [](
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)->arangodb::Result {
|
||||
if (value.isBoolean()
|
||||
&& arangodb::basics::VelocyPackHelper::compare(value, rhs.get("geoJson"), false)) {
|
||||
return false;
|
||||
}
|
||||
} else if (arangodb::Index::IndexType::TRI_IDX_TYPE_FULLTEXT_INDEX == type) {
|
||||
// minLength
|
||||
value = lhs.get("minLength");
|
||||
|
||||
if (value.isNumber()
|
||||
&& arangodb::basics::VelocyPackHelper::compare(value, rhs.get("minLength"), false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// other index types: fields must be identical if present
|
||||
value = lhs.get(arangodb::StaticStrings::IndexFields);
|
||||
|
||||
if (value.isArray()) {
|
||||
if (arangodb::Index::IndexType::TRI_IDX_TYPE_HASH_INDEX == type) {
|
||||
arangodb::velocypack::ValueLength const nv = value.length();
|
||||
|
||||
// compare fields in arbitrary order
|
||||
auto r = rhs.get(arangodb::StaticStrings::IndexFields);
|
||||
|
||||
if (!r.isArray() || nv != r.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nv; ++i) {
|
||||
arangodb::velocypack::Slice const v = value.at(i);
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto const& vr : VPackArrayIterator(r)) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(v, vr, false) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get(arangodb::StaticStrings::IndexFields), false
|
||||
) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct EdgeIndexFactory: public DefaultIndexFactory {
|
||||
EdgeIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
return arangodb::Result(TRI_ERROR_INTERNAL, "cannot create edge index");
|
||||
}
|
||||
|
||||
index = std::make_shared<arangodb::MMFilesEdgeIndex>(id, collection);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
if (isCreation) {
|
||||
// creating these indexes yourself is forbidden
|
||||
return TRI_ERROR_FORBIDDEN;
|
||||
|
@ -434,13 +455,31 @@ MMFilesIndexFactory::MMFilesIndexFactory() {
|
|||
);
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
emplaceNormalizer("fulltext", [](
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)->arangodb::Result {
|
||||
struct FulltextIndexFactory: public DefaultIndexFactory {
|
||||
FulltextIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::MMFilesFulltextIndex>(
|
||||
id, collection, definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
|
@ -450,13 +489,31 @@ MMFilesIndexFactory::MMFilesIndexFactory() {
|
|||
);
|
||||
|
||||
return EnhanceJsonIndexFulltext(definition, normalized, isCreation);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
emplaceNormalizer("geo", [](
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)->arangodb::Result {
|
||||
struct GeoIndexFactory: public DefaultIndexFactory {
|
||||
GeoIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::MMFilesGeoIndex>(
|
||||
id, collection, definition, "geo"
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
|
@ -466,13 +523,31 @@ MMFilesIndexFactory::MMFilesIndexFactory() {
|
|||
);
|
||||
|
||||
return EnhanceJsonIndexGeo(definition, normalized, isCreation);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
emplaceNormalizer("geo1", [](
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)->arangodb::Result {
|
||||
struct Geo1IndexFactory: public DefaultIndexFactory {
|
||||
Geo1IndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::MMFilesGeoIndex>(
|
||||
id, collection, definition, "geo1"
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
|
@ -482,13 +557,31 @@ MMFilesIndexFactory::MMFilesIndexFactory() {
|
|||
);
|
||||
|
||||
return EnhanceJsonIndexGeo1(definition, normalized, isCreation);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
emplaceNormalizer("geo2", [](
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)->arangodb::Result {
|
||||
struct Geo2IndexFactory: public DefaultIndexFactory {
|
||||
Geo2IndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::MMFilesGeoIndex>(
|
||||
id, collection, definition, "geo2"
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
|
@ -498,13 +591,31 @@ MMFilesIndexFactory::MMFilesIndexFactory() {
|
|||
);
|
||||
|
||||
return EnhanceJsonIndexGeo2(definition, normalized, isCreation);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
emplaceNormalizer("hash", [](
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)->arangodb::Result {
|
||||
struct HashIndexFactory: public DefaultIndexFactory {
|
||||
HashIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::MMFilesHashIndex>(
|
||||
id, collection, definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
|
@ -514,13 +625,71 @@ MMFilesIndexFactory::MMFilesIndexFactory() {
|
|||
);
|
||||
|
||||
return EnhanceJsonIndexHash(definition, normalized, isCreation);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
emplaceNormalizer("primary", [](
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)->arangodb::Result {
|
||||
struct PersistentIndexFactory: public DefaultIndexFactory {
|
||||
PersistentIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::MMFilesPersistentIndex>(
|
||||
id, collection, definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_PERSISTENT_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
return EnhanceJsonIndexPersistent(definition, normalized, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
struct PrimaryIndexFactory: public DefaultIndexFactory {
|
||||
PrimaryIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"cannot create primary index"
|
||||
);
|
||||
}
|
||||
|
||||
index = std::make_shared<MMFilesPrimaryIndex>(collection);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
if (isCreation) {
|
||||
// creating these indexes yourself is forbidden
|
||||
return TRI_ERROR_FORBIDDEN;
|
||||
|
@ -535,45 +704,31 @@ MMFilesIndexFactory::MMFilesIndexFactory() {
|
|||
);
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
emplaceNormalizer("persistent", [](
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)->arangodb::Result {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_PERSISTENT_INDEX)
|
||||
)
|
||||
struct SkiplistIndexFactory: public DefaultIndexFactory {
|
||||
SkiplistIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::MMFilesSkiplistIndex>(
|
||||
id, collection, definition
|
||||
);
|
||||
|
||||
return EnhanceJsonIndexPersistent(definition, normalized, isCreation);
|
||||
});
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
emplaceNormalizer("rocksdb", [](
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)->arangodb::Result {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_PERSISTENT_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
return EnhanceJsonIndexPersistent(definition, normalized, isCreation);
|
||||
});
|
||||
|
||||
emplaceNormalizer("skiplist", [](
|
||||
velocypack::Builder& normalized,
|
||||
velocypack::Slice definition,
|
||||
bool isCreation
|
||||
)->arangodb::Result {
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
|
@ -583,7 +738,32 @@ MMFilesIndexFactory::MMFilesIndexFactory() {
|
|||
);
|
||||
|
||||
return EnhanceJsonIndexSkiplist(definition, normalized, isCreation);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
MMFilesIndexFactory::MMFilesIndexFactory() {
|
||||
static const EdgeIndexFactory edgeIndexFactory("edge");
|
||||
static const FulltextIndexFactory fulltextIndexFactory("fulltext");
|
||||
static const GeoIndexFactory geoIndexFactory("geo");
|
||||
static const Geo1IndexFactory geo1IndexFactory("geo1");
|
||||
static const Geo2IndexFactory geo2IndexFactory("geo2");
|
||||
static const HashIndexFactory hashIndexFactory("hash");
|
||||
static const PersistentIndexFactory persistentIndexFactory("persistent");
|
||||
static const PrimaryIndexFactory primaryIndexFactory("primary");
|
||||
static const SkiplistIndexFactory skiplistIndexFactory("skiplist");
|
||||
|
||||
emplace("edge", edgeIndexFactory);
|
||||
emplace("fulltext", fulltextIndexFactory);
|
||||
emplace("geo", geoIndexFactory);
|
||||
emplace("geo1", geo1IndexFactory);
|
||||
emplace("geo2", geo2IndexFactory);
|
||||
emplace("hash", hashIndexFactory);
|
||||
emplace("persistent", persistentIndexFactory);
|
||||
emplace("primary", primaryIndexFactory);
|
||||
emplace("rocksdb", persistentIndexFactory);
|
||||
emplace("skiplist", skiplistIndexFactory);
|
||||
}
|
||||
|
||||
void MMFilesIndexFactory::fillSystemIndexes(
|
||||
|
|
|
@ -68,7 +68,7 @@ ViewTypesFeature::ViewTypesFeature(
|
|||
startsAfter("BasicsPhase");
|
||||
}
|
||||
|
||||
arangodb::Result ViewTypesFeature::emplace(
|
||||
Result ViewTypesFeature::emplace(
|
||||
LogicalDataSource::Type const& type,
|
||||
ViewFactory const& factory
|
||||
) {
|
||||
|
|
|
@ -61,12 +61,12 @@ class ViewTypesFeature final: public application_features::ApplicationFeature {
|
|||
explicit ViewTypesFeature(application_features::ApplicationServer& server);
|
||||
|
||||
/// @return 'factory' for 'type' was added successfully
|
||||
arangodb::Result emplace(
|
||||
Result emplace(
|
||||
LogicalDataSource::Type const& type,
|
||||
ViewFactory const& factory
|
||||
);
|
||||
|
||||
/// @return factory for the specified type or false if no such type
|
||||
/// @return factory for the specified type or a failing placeholder if no such type
|
||||
ViewFactory const& factory(
|
||||
LogicalDataSource::Type const& type
|
||||
) const noexcept;
|
||||
|
|
|
@ -288,300 +288,524 @@ static int EnhanceJsonIndexFulltext(VPackSlice const definition,
|
|||
return res;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct DefaultIndexFactory: public arangodb::IndexTypeFactory {
|
||||
std::string const _type;
|
||||
|
||||
DefaultIndexFactory(std::string const& type): _type(type) {}
|
||||
|
||||
virtual bool equal(
|
||||
arangodb::velocypack::Slice const& lhs,
|
||||
arangodb::velocypack::Slice const& rhs
|
||||
) const override {
|
||||
// unique must be identical if present
|
||||
auto value = lhs.get(arangodb::StaticStrings::IndexUnique);
|
||||
|
||||
if (value.isBoolean()) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get(arangodb::StaticStrings::IndexUnique), false
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// sparse must be identical if present
|
||||
value = lhs.get(arangodb::StaticStrings::IndexSparse);
|
||||
|
||||
if (value.isBoolean()) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get(arangodb::StaticStrings::IndexSparse), false
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto type = Index::type(_type);
|
||||
|
||||
if (arangodb::Index::IndexType::TRI_IDX_TYPE_GEO1_INDEX == type||
|
||||
arangodb::Index::IndexType::TRI_IDX_TYPE_GEO_INDEX == type) {
|
||||
// geoJson must be identical if present
|
||||
value = lhs.get("geoJson");
|
||||
|
||||
if (value.isBoolean()
|
||||
&& arangodb::basics::VelocyPackHelper::compare(value, rhs.get("geoJson"), false)) {
|
||||
return false;
|
||||
}
|
||||
} else if (arangodb::Index::IndexType::TRI_IDX_TYPE_FULLTEXT_INDEX == type) {
|
||||
// minLength
|
||||
value = lhs.get("minLength");
|
||||
|
||||
if (value.isNumber()
|
||||
&& arangodb::basics::VelocyPackHelper::compare(value, rhs.get("minLength"), false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// other index types: fields must be identical if present
|
||||
value = lhs.get(arangodb::StaticStrings::IndexFields);
|
||||
|
||||
if (value.isArray()) {
|
||||
if (arangodb::Index::IndexType::TRI_IDX_TYPE_HASH_INDEX == type) {
|
||||
arangodb::velocypack::ValueLength const nv = value.length();
|
||||
|
||||
// compare fields in arbitrary order
|
||||
auto r = rhs.get(arangodb::StaticStrings::IndexFields);
|
||||
|
||||
if (!r.isArray() || nv != r.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nv; ++i) {
|
||||
arangodb::velocypack::Slice const v = value.at(i);
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto const& vr : VPackArrayIterator(r)) {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(v, vr, false) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (arangodb::basics::VelocyPackHelper::compare(
|
||||
value, rhs.get(arangodb::StaticStrings::IndexFields), false
|
||||
) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct EdgeIndexFactory: public DefaultIndexFactory {
|
||||
EdgeIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
return arangodb::Result(TRI_ERROR_INTERNAL, "cannot create edge index");
|
||||
}
|
||||
|
||||
auto fields = definition.get(arangodb::StaticStrings::IndexFields);
|
||||
TRI_ASSERT(fields.isArray() && fields.length() == 1);
|
||||
auto direction = fields.at(0).copyString();
|
||||
TRI_ASSERT(direction == StaticStrings::FromString ||
|
||||
direction == StaticStrings::ToString);
|
||||
|
||||
index = std::make_shared<arangodb::RocksDBEdgeIndex>(
|
||||
id, collection, definition, direction
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
if (isCreation) {
|
||||
// creating these indexes yourself is forbidden
|
||||
return TRI_ERROR_FORBIDDEN;
|
||||
}
|
||||
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
arangodb::Index::oldtypeName(arangodb::Index::TRI_IDX_TYPE_EDGE_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
};
|
||||
|
||||
struct FulltextIndexFactory: public DefaultIndexFactory {
|
||||
FulltextIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::RocksDBFulltextIndex>(
|
||||
id, collection, definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(arangodb::Index::oldtypeName(
|
||||
arangodb::Index::TRI_IDX_TYPE_FULLTEXT_INDEX
|
||||
))
|
||||
);
|
||||
|
||||
if (isCreation
|
||||
&& !ServerState::instance()->isCoordinator()
|
||||
&& !definition.hasKey("objectId")) {
|
||||
normalized.add(
|
||||
"objectId",
|
||||
arangodb::velocypack::Value(std::to_string(TRI_NewTickServer()))
|
||||
);
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexFulltext(definition, normalized, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
struct GeoIndexFactory: public DefaultIndexFactory {
|
||||
GeoIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::RocksDBGeoIndex>(
|
||||
id, collection, definition, "geo"
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
arangodb::Index::oldtypeName(arangodb::Index::TRI_IDX_TYPE_GEO_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation
|
||||
&& !ServerState::instance()->isCoordinator()
|
||||
&& !definition.hasKey("objectId")) {
|
||||
normalized.add(
|
||||
"objectId",
|
||||
arangodb::velocypack::Value(std::to_string(TRI_NewTickServer()))
|
||||
);
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexGeo(definition, normalized, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
struct Geo1IndexFactory: public DefaultIndexFactory {
|
||||
Geo1IndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::RocksDBGeoIndex>(
|
||||
id, collection, definition, "geo1"
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
arangodb::Index::oldtypeName(arangodb::Index::TRI_IDX_TYPE_GEO_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation
|
||||
&& !ServerState::instance()->isCoordinator()
|
||||
&& !definition.hasKey("objectId")) {
|
||||
normalized.add(
|
||||
"objectId",
|
||||
arangodb::velocypack::Value(std::to_string(TRI_NewTickServer()))
|
||||
);
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexGeo1(definition, normalized, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
struct Geo2IndexFactory: public DefaultIndexFactory {
|
||||
Geo2IndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::RocksDBGeoIndex>(
|
||||
id, collection, definition, "geo2"
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
arangodb::Index::oldtypeName(arangodb::Index::TRI_IDX_TYPE_GEO_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation
|
||||
&& !ServerState::instance()->isCoordinator()
|
||||
&& !definition.hasKey("objectId")) {
|
||||
normalized.add(
|
||||
"objectId",
|
||||
arangodb::velocypack::Value(std::to_string(TRI_NewTickServer()))
|
||||
);
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexGeo2(definition, normalized, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
struct HashIndexFactory: public DefaultIndexFactory {
|
||||
HashIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::RocksDBHashIndex>(
|
||||
id, collection, definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
arangodb::Index::oldtypeName(arangodb::Index::TRI_IDX_TYPE_HASH_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation
|
||||
&& !ServerState::instance()->isCoordinator()
|
||||
&& !definition.hasKey("objectId")) {
|
||||
normalized.add(
|
||||
"objectId",
|
||||
arangodb::velocypack::Value(std::to_string(TRI_NewTickServer()))
|
||||
);
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexVPack(definition, normalized, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
struct PersistentIndexFactory: public DefaultIndexFactory {
|
||||
PersistentIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::RocksDBPersistentIndex>(
|
||||
id, collection, definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(arangodb::Index::oldtypeName(
|
||||
arangodb::Index::TRI_IDX_TYPE_PERSISTENT_INDEX
|
||||
))
|
||||
);
|
||||
|
||||
if (isCreation
|
||||
&& !ServerState::instance()->isCoordinator()
|
||||
&& !definition.hasKey("objectId")) {
|
||||
normalized.add(
|
||||
"objectId",
|
||||
arangodb::velocypack::Value(std::to_string(TRI_NewTickServer()))
|
||||
);
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexVPack(definition, normalized, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
struct PrimaryIndexFactory: public DefaultIndexFactory {
|
||||
PrimaryIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"cannot create primary index"
|
||||
);
|
||||
}
|
||||
|
||||
index = std::make_shared<arangodb::RocksDBPrimaryIndex>(
|
||||
collection, definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
if (isCreation) {
|
||||
// creating these indexes yourself is forbidden
|
||||
return TRI_ERROR_FORBIDDEN;
|
||||
}
|
||||
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(arangodb::Index::oldtypeName(
|
||||
arangodb::Index::TRI_IDX_TYPE_PRIMARY_INDEX
|
||||
))
|
||||
);
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
};
|
||||
|
||||
struct SkiplistIndexFactory: public DefaultIndexFactory {
|
||||
SkiplistIndexFactory(std::string const& type): DefaultIndexFactory(type) {}
|
||||
|
||||
virtual arangodb::Result instantiate(
|
||||
std::shared_ptr<arangodb::Index>& index,
|
||||
arangodb::LogicalCollection& collection,
|
||||
arangodb::velocypack::Slice const& definition,
|
||||
TRI_idx_iid_t id,
|
||||
bool isClusterConstructor
|
||||
) const override {
|
||||
index = std::make_shared<arangodb::RocksDBSkiplistIndex>(
|
||||
id, collection, definition
|
||||
);
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
virtual arangodb::Result normalize(
|
||||
arangodb::velocypack::Builder& normalized,
|
||||
arangodb::velocypack::Slice definition,
|
||||
bool isCreation
|
||||
) const override {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(arangodb::Index::oldtypeName(
|
||||
arangodb::Index::TRI_IDX_TYPE_SKIPLIST_INDEX
|
||||
))
|
||||
);
|
||||
|
||||
if (isCreation
|
||||
&& !ServerState::instance()->isCoordinator()
|
||||
&& !definition.hasKey("objectId")) {
|
||||
normalized.add(
|
||||
"objectId",
|
||||
arangodb::velocypack::Value(std::to_string(TRI_NewTickServer()))
|
||||
);
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexVPack(definition, normalized, isCreation);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
RocksDBIndexFactory::RocksDBIndexFactory() {
|
||||
emplaceFactory("edge",
|
||||
[](LogicalCollection& collection,
|
||||
velocypack::Slice const& definition, TRI_idx_iid_t id,
|
||||
bool isClusterConstructor) -> std::shared_ptr<Index> {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
||||
"cannot create edge index");
|
||||
}
|
||||
static const EdgeIndexFactory edgeIndexFactory("edge");
|
||||
static const FulltextIndexFactory fulltextIndexFactory("fulltext");
|
||||
static const GeoIndexFactory geoIndexFactory("geo");
|
||||
static const Geo1IndexFactory geo1IndexFactory("geo1");
|
||||
static const Geo2IndexFactory geo2IndexFactory("geo2");
|
||||
static const HashIndexFactory hashIndexFactory("hash");
|
||||
static const PersistentIndexFactory persistentIndexFactory("persistent");
|
||||
static const PrimaryIndexFactory primaryIndexFactory("primary");
|
||||
static const SkiplistIndexFactory skiplistIndexFactory("skiplist");
|
||||
|
||||
auto fields =
|
||||
definition.get(arangodb::StaticStrings::IndexFields);
|
||||
TRI_ASSERT(fields.isArray() && fields.length() == 1);
|
||||
auto direction = fields.at(0).copyString();
|
||||
TRI_ASSERT(direction == StaticStrings::FromString ||
|
||||
direction == StaticStrings::ToString);
|
||||
|
||||
return std::make_shared<RocksDBEdgeIndex>(
|
||||
id, collection, definition, direction);
|
||||
});
|
||||
|
||||
emplaceFactory("fulltext",
|
||||
[](LogicalCollection& collection,
|
||||
velocypack::Slice const& definition, TRI_idx_iid_t id,
|
||||
bool isClusterConstructor) -> std::shared_ptr<Index> {
|
||||
return std::make_shared<RocksDBFulltextIndex>(id, collection,
|
||||
definition);
|
||||
});
|
||||
|
||||
emplaceFactory("geo1",
|
||||
[](LogicalCollection& collection,
|
||||
velocypack::Slice const& definition, TRI_idx_iid_t id,
|
||||
bool isClusterConstructor) -> std::shared_ptr<Index> {
|
||||
return std::make_shared<RocksDBGeoIndex>(id, collection,
|
||||
definition, "geo1");
|
||||
});
|
||||
|
||||
emplaceFactory("geo2",
|
||||
[](LogicalCollection& collection,
|
||||
velocypack::Slice const& definition, TRI_idx_iid_t id,
|
||||
bool isClusterConstructor) -> std::shared_ptr<Index> {
|
||||
return std::make_shared<RocksDBGeoIndex>(id, collection,
|
||||
definition, "geo2");
|
||||
});
|
||||
|
||||
emplaceFactory("geo",
|
||||
[](LogicalCollection& collection,
|
||||
velocypack::Slice const& definition, TRI_idx_iid_t id,
|
||||
bool isClusterConstructor) -> std::shared_ptr<Index> {
|
||||
return std::make_shared<RocksDBGeoIndex>(id, collection,
|
||||
definition, "geo");
|
||||
});
|
||||
|
||||
emplaceFactory("hash",
|
||||
[](LogicalCollection& collection,
|
||||
velocypack::Slice const& definition, TRI_idx_iid_t id,
|
||||
bool isClusterConstructor) -> std::shared_ptr<Index> {
|
||||
return std::make_shared<RocksDBHashIndex>(id, collection,
|
||||
definition);
|
||||
});
|
||||
|
||||
emplaceFactory("persistent",
|
||||
[](LogicalCollection& collection,
|
||||
velocypack::Slice const& definition, TRI_idx_iid_t id,
|
||||
bool isClusterConstructor) -> std::shared_ptr<Index> {
|
||||
return std::make_shared<RocksDBPersistentIndex>(
|
||||
id, collection, definition);
|
||||
});
|
||||
|
||||
emplaceFactory("primary",
|
||||
[](LogicalCollection& collection,
|
||||
velocypack::Slice const& definition, TRI_idx_iid_t id,
|
||||
bool isClusterConstructor) -> std::shared_ptr<Index> {
|
||||
if (!isClusterConstructor) {
|
||||
// this indexes cannot be created directly
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_INTERNAL, "cannot create primary index");
|
||||
}
|
||||
|
||||
return std::make_shared<RocksDBPrimaryIndex>(collection,
|
||||
definition);
|
||||
});
|
||||
|
||||
emplaceFactory("skiplist",
|
||||
[](LogicalCollection& collection,
|
||||
velocypack::Slice const& definition, TRI_idx_iid_t id,
|
||||
bool isClusterConstructor) -> std::shared_ptr<Index> {
|
||||
return std::make_shared<RocksDBSkiplistIndex>(id, collection,
|
||||
definition);
|
||||
});
|
||||
|
||||
emplaceNormalizer(
|
||||
"edge",
|
||||
[](velocypack::Builder& normalized, velocypack::Slice definition,
|
||||
bool isCreation) -> arangodb::Result {
|
||||
if (isCreation) {
|
||||
// creating these indexes yourself is forbidden
|
||||
return TRI_ERROR_FORBIDDEN;
|
||||
}
|
||||
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_EDGE_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
});
|
||||
|
||||
emplaceNormalizer(
|
||||
"fulltext",
|
||||
[](velocypack::Builder& normalized, velocypack::Slice definition,
|
||||
bool isCreation) -> arangodb::Result {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
VPackValue(Index::oldtypeName(Index::TRI_IDX_TYPE_FULLTEXT_INDEX)));
|
||||
|
||||
if (isCreation && !ServerState::instance()->isCoordinator() &&
|
||||
!definition.hasKey("objectId")) {
|
||||
normalized.add("objectId", velocypack::Value(
|
||||
std::to_string(TRI_NewTickServer())));
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexFulltext(definition, normalized, isCreation);
|
||||
});
|
||||
|
||||
emplaceNormalizer("geo", [](velocypack::Builder& normalized, velocypack::Slice definition,
|
||||
bool isCreation) -> arangodb::Result {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_GEO_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation && !ServerState::instance()->isCoordinator() &&
|
||||
!definition.hasKey("objectId")) {
|
||||
normalized.add("objectId", velocypack::Value(
|
||||
std::to_string(TRI_NewTickServer())));
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexGeo(definition, normalized, isCreation);
|
||||
});
|
||||
|
||||
emplaceNormalizer(
|
||||
"geo1",
|
||||
[](velocypack::Builder& normalized, velocypack::Slice definition,
|
||||
bool isCreation) -> arangodb::Result {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_GEO_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation && !ServerState::instance()->isCoordinator() &&
|
||||
!definition.hasKey("objectId")) {
|
||||
normalized.add("objectId", velocypack::Value(
|
||||
std::to_string(TRI_NewTickServer())));
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexGeo1(definition, normalized, isCreation);
|
||||
});
|
||||
|
||||
emplaceNormalizer(
|
||||
"geo2",
|
||||
[](velocypack::Builder& normalized, velocypack::Slice definition,
|
||||
bool isCreation) -> arangodb::Result {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_GEO_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation && !ServerState::instance()->isCoordinator() &&
|
||||
!definition.hasKey("objectId")) {
|
||||
normalized.add("objectId", velocypack::Value(
|
||||
std::to_string(TRI_NewTickServer())));
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexGeo2(definition, normalized, isCreation);
|
||||
});
|
||||
|
||||
emplaceNormalizer(
|
||||
"hash",
|
||||
[](velocypack::Builder& normalized, velocypack::Slice definition,
|
||||
bool isCreation) -> arangodb::Result {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_HASH_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation && !ServerState::instance()->isCoordinator() &&
|
||||
!definition.hasKey("objectId")) {
|
||||
normalized.add("objectId", velocypack::Value(
|
||||
std::to_string(TRI_NewTickServer())));
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexVPack(definition, normalized, isCreation);
|
||||
});
|
||||
|
||||
emplaceNormalizer(
|
||||
"primary",
|
||||
[](velocypack::Builder& normalized, velocypack::Slice definition,
|
||||
bool isCreation) -> arangodb::Result {
|
||||
if (isCreation) {
|
||||
// creating these indexes yourself is forbidden
|
||||
return TRI_ERROR_FORBIDDEN;
|
||||
}
|
||||
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_PRIMARY_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
return TRI_ERROR_INTERNAL;
|
||||
});
|
||||
|
||||
emplaceNormalizer(
|
||||
"persistent",
|
||||
[](velocypack::Builder& normalized, velocypack::Slice definition,
|
||||
bool isCreation) -> arangodb::Result {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_PERSISTENT_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation && !ServerState::instance()->isCoordinator() &&
|
||||
!definition.hasKey("objectId")) {
|
||||
normalized.add("objectId", velocypack::Value(
|
||||
std::to_string(TRI_NewTickServer())));
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexVPack(definition, normalized, isCreation);
|
||||
});
|
||||
|
||||
emplaceNormalizer(
|
||||
"rocksdb",
|
||||
[](velocypack::Builder& normalized, velocypack::Slice definition,
|
||||
bool isCreation) -> arangodb::Result {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_PERSISTENT_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation && !ServerState::instance()->isCoordinator() &&
|
||||
!definition.hasKey("objectId")) {
|
||||
normalized.add("objectId", velocypack::Value(
|
||||
std::to_string(TRI_NewTickServer())));
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexVPack(definition, normalized, isCreation);
|
||||
});
|
||||
|
||||
emplaceNormalizer(
|
||||
"skiplist",
|
||||
[](velocypack::Builder& normalized, velocypack::Slice definition,
|
||||
bool isCreation) -> arangodb::Result {
|
||||
TRI_ASSERT(normalized.isOpenObject());
|
||||
normalized.add(
|
||||
arangodb::StaticStrings::IndexType,
|
||||
arangodb::velocypack::Value(
|
||||
Index::oldtypeName(Index::TRI_IDX_TYPE_SKIPLIST_INDEX)
|
||||
)
|
||||
);
|
||||
|
||||
if (isCreation && !ServerState::instance()->isCoordinator() &&
|
||||
!definition.hasKey("objectId")) {
|
||||
normalized.add("objectId", velocypack::Value(
|
||||
std::to_string(TRI_NewTickServer())));
|
||||
}
|
||||
|
||||
return EnhanceJsonIndexVPack(definition, normalized, isCreation);
|
||||
});
|
||||
emplace("edge", edgeIndexFactory);
|
||||
emplace("fulltext", fulltextIndexFactory);
|
||||
emplace("geo", geoIndexFactory);
|
||||
emplace("geo1", geo1IndexFactory);
|
||||
emplace("geo2", geo2IndexFactory);
|
||||
emplace("hash", hashIndexFactory);
|
||||
emplace("persistent", persistentIndexFactory);
|
||||
emplace("primary", primaryIndexFactory);
|
||||
emplace("rocksdb", persistentIndexFactory);
|
||||
emplace("skiplist", skiplistIndexFactory);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -172,7 +172,8 @@ SECTION("test_defaults") {
|
|||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
REQUIRE((nullptr != logicalCollection));
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{}");
|
||||
auto link = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, json->slice(), 1, false);
|
||||
std::shared_ptr<arangodb::Index> link;
|
||||
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link, *logicalCollection, json->slice(), 1, false).errorNumber()));
|
||||
CHECK((true == !link));
|
||||
}
|
||||
|
||||
|
@ -183,8 +184,9 @@ SECTION("test_defaults") {
|
|||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
REQUIRE((nullptr != logicalCollection));
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"view\": 42 }");
|
||||
auto link = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, json->slice(), 1, false);
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"view\": \"42\" }");
|
||||
std::shared_ptr<arangodb::Index> link;
|
||||
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link, *logicalCollection, json->slice(), 1, false).errorNumber()));
|
||||
CHECK((true == !link));
|
||||
}
|
||||
|
||||
|
@ -192,7 +194,7 @@ SECTION("test_defaults") {
|
|||
{
|
||||
s.engine.views.clear();
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": 42 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": \"42\" }");
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": 42, \"type\": \"arangosearch\" }");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
|
@ -244,7 +246,7 @@ SECTION("test_defaults") {
|
|||
{
|
||||
s.engine.views.clear();
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": 42 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": \"42\" }");
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": 42, \"type\": \"arangosearch\" }");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
|
@ -314,7 +316,7 @@ SECTION("test_init") {
|
|||
// collection registered with view (collection initially not in view)
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\", \"id\": 100 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": 42 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": \"42\" }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": 42, \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
|
@ -336,7 +338,8 @@ SECTION("test_init") {
|
|||
CHECK((actual.empty()));
|
||||
}
|
||||
|
||||
auto link = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, linkJson->slice(), 1, false);
|
||||
std::shared_ptr<arangodb::Index> link;
|
||||
CHECK((arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link, *logicalCollection, linkJson->slice(), 1, false).ok()));
|
||||
CHECK((false == !link));
|
||||
|
||||
// collection in view after
|
||||
|
@ -373,7 +376,7 @@ SECTION("test_init") {
|
|||
// collection registered with view (collection initially is in view)
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\", \"id\": 101 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": 43 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": \"43\" }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": 43, \"type\": \"arangosearch\", \"collections\": [ 101 ] }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
|
@ -395,7 +398,8 @@ SECTION("test_init") {
|
|||
CHECK((actual.empty()));
|
||||
}
|
||||
|
||||
auto link = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, linkJson->slice(), 1, false);
|
||||
std::shared_ptr<arangodb::Index> link;
|
||||
CHECK((arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link, *logicalCollection, linkJson->slice(), 1, false).ok()));
|
||||
CHECK((false == !link));
|
||||
|
||||
// collection in view after
|
||||
|
@ -434,7 +438,7 @@ SECTION("test_drop") {
|
|||
// collection drop (removes collection from view) subsequent destroy does not touch view
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\", \"id\": 100 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": 42 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": \"42\" }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": 42, \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
|
@ -442,7 +446,8 @@ SECTION("test_drop") {
|
|||
auto logicalView = vocbase.createView(viewJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
|
||||
auto link0 = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, linkJson->slice(), 1, false);
|
||||
std::shared_ptr<arangodb::Index> link0;
|
||||
CHECK((arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link0, *logicalCollection, linkJson->slice(), 1, false).ok()));
|
||||
CHECK((false == !link0));
|
||||
|
||||
// collection in view before
|
||||
|
@ -477,7 +482,8 @@ SECTION("test_drop") {
|
|||
CHECK((actual.empty()));
|
||||
}
|
||||
|
||||
auto link1 = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, linkJson->slice(), 1, false);
|
||||
std::shared_ptr<arangodb::Index> link1;
|
||||
CHECK((arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link1, *logicalCollection, linkJson->slice(), 1, false).ok()));
|
||||
CHECK((false == !link1));
|
||||
|
||||
// collection in view before (new link)
|
||||
|
@ -516,7 +522,7 @@ SECTION("test_unload") {
|
|||
// index unload does not touch the view (subsequent destroy)
|
||||
{
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\", \"id\": 100 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": 42 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": \"42\" }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": 42, \"type\": \"arangosearch\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
auto logicalCollection = vocbase.createCollection(collectionJson->slice());
|
||||
|
@ -524,7 +530,8 @@ SECTION("test_unload") {
|
|||
auto logicalView = vocbase.createView(viewJson->slice());
|
||||
REQUIRE((false == !logicalView));
|
||||
|
||||
auto link = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, linkJson->slice(), 1, false);
|
||||
std::shared_ptr<arangodb::Index> link;
|
||||
CHECK((arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link, *logicalCollection, linkJson->slice(), 1, false).ok()));
|
||||
CHECK((false == !link));
|
||||
|
||||
// collection in view before
|
||||
|
@ -583,7 +590,7 @@ SECTION("test_write") {
|
|||
auto doc1 = arangodb::velocypack::Parser::fromJson("{ \"ghi\": \"jkl\" }");
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
|
||||
std::string dataPath = ((((irs::utf8_path()/=s.testFilesystemPath)/=std::string("databases"))/=(std::string("database-") + std::to_string(vocbase.id())))/=std::string("arangosearch-42")).utf8();
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": 42, \"includeAllFields\": true }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"type\": \"arangosearch\", \"view\": \"42\", \"includeAllFields\": true }");
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \
|
||||
\"id\": 42, \
|
||||
|
@ -672,4 +679,4 @@ SECTION("test_write") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -113,13 +113,9 @@ struct IResearchLinkCoordinatorSetup {
|
|||
|
||||
// register factories & normalizers
|
||||
auto& indexFactory = const_cast<arangodb::IndexFactory&>(engine.indexFactory());
|
||||
indexFactory.emplaceFactory(
|
||||
indexFactory.emplace(
|
||||
arangodb::iresearch::DATA_SOURCE_TYPE.name(),
|
||||
arangodb::iresearch::IResearchLinkCoordinator::make
|
||||
);
|
||||
indexFactory.emplaceNormalizer(
|
||||
arangodb::iresearch::DATA_SOURCE_TYPE.name(),
|
||||
arangodb::iresearch::IResearchLinkHelper::normalize
|
||||
arangodb::iresearch::IResearchLinkCoordinator::factory()
|
||||
);
|
||||
|
||||
arangodb::tests::init();
|
||||
|
@ -293,18 +289,16 @@ SECTION("test_create_drop") {
|
|||
// no view specified
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{}");
|
||||
auto link = arangodb::iresearch::IResearchLinkCoordinator::make(
|
||||
*logicalCollection.get(), json->slice(), 1, true
|
||||
);
|
||||
std::shared_ptr<arangodb::Index> link;
|
||||
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == arangodb::iresearch::IResearchLinkCoordinator::factory().instantiate(link, *logicalCollection.get(), json->slice(), 1, true).errorNumber()));
|
||||
CHECK(!link);
|
||||
}
|
||||
|
||||
// no view can be found
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"view\": 42 }");
|
||||
auto link = arangodb::iresearch::IResearchLinkCoordinator::make(
|
||||
*logicalCollection.get(), json->slice(), 1, true
|
||||
);
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"view\": \"42\" }");
|
||||
std::shared_ptr<arangodb::Index> link;
|
||||
CHECK((TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND == arangodb::iresearch::IResearchLinkCoordinator::factory().instantiate(link, *logicalCollection.get(), json->slice(), 1, true).errorNumber()));
|
||||
CHECK(!link);
|
||||
}
|
||||
|
||||
|
@ -313,7 +307,7 @@ SECTION("test_create_drop") {
|
|||
|
||||
// valid link creation
|
||||
{
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"id\" : \"42\", \"type\": \"arangosearch\", \"view\": 42 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"id\" : \"42\", \"type\": \"arangosearch\", \"view\": \"42\" }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
REQUIRE((arangodb::LogicalView::create(logicalView, *vocbase, viewJson->slice()).ok()));
|
||||
|
@ -420,7 +414,7 @@ SECTION("test_create_drop") {
|
|||
|
||||
// ensure jSON is still valid after unload()
|
||||
{
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"id\":\"42\", \"type\": \"arangosearch\", \"view\": 42 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"id\":\"42\", \"type\": \"arangosearch\", \"view\": \"42\" }");
|
||||
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"id\": \"42\", \"type\": \"arangosearch\" }");
|
||||
arangodb::LogicalView::ptr logicalView;
|
||||
REQUIRE((arangodb::LogicalView::create(logicalView, *vocbase, viewJson->slice()).ok()));
|
||||
|
@ -515,4 +509,4 @@ SECTION("test_create_drop") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -2071,7 +2071,7 @@ SECTION("test_register_link") {
|
|||
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\", \"id\": 100 }");
|
||||
auto viewJson0 = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": 101 }");
|
||||
auto viewJson1 = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": 101, \"collections\": [ 100 ] }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"view\": 101 }");
|
||||
auto linkJson = arangodb::velocypack::Parser::fromJson("{ \"view\": \"101\" }");
|
||||
|
||||
// new link in recovery
|
||||
{
|
||||
|
@ -2110,7 +2110,8 @@ SECTION("test_register_link") {
|
|||
StorageEngineMock::inRecoveryResult = true;
|
||||
auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; });
|
||||
persisted = false;
|
||||
auto link = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, linkJson->slice(), 1, false);
|
||||
std::shared_ptr<arangodb::Index> link;
|
||||
CHECK((arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link, *logicalCollection, linkJson->slice(), 1, false).ok()));
|
||||
CHECK((false == persisted));
|
||||
CHECK((false == !link));
|
||||
|
||||
|
@ -2180,7 +2181,8 @@ SECTION("test_register_link") {
|
|||
}
|
||||
|
||||
persisted = false;
|
||||
auto link = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, linkJson->slice(), 1, false);
|
||||
std::shared_ptr<arangodb::Index> link;
|
||||
CHECK((arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link, *logicalCollection, linkJson->slice(), 1, false).ok()));
|
||||
CHECK((true == persisted)); // link instantiation does modify and persist view meta
|
||||
CHECK((false == !link));
|
||||
std::unordered_set<TRI_voc_cid_t> cids;
|
||||
|
@ -2249,7 +2251,8 @@ SECTION("test_register_link") {
|
|||
}
|
||||
|
||||
persisted = false;
|
||||
auto link0 = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, linkJson->slice(), 1, false);
|
||||
std::shared_ptr<arangodb::Index> link0;
|
||||
CHECK((arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link0, *logicalCollection, linkJson->slice(), 1, false).ok()));
|
||||
CHECK((false == persisted));
|
||||
CHECK((false == !link0));
|
||||
|
||||
|
@ -2281,7 +2284,8 @@ SECTION("test_register_link") {
|
|||
}
|
||||
|
||||
persisted = false;
|
||||
auto link1 = arangodb::iresearch::IResearchMMFilesLink::make(*logicalCollection, linkJson->slice(), 1, false);
|
||||
std::shared_ptr<arangodb::Index> link1;
|
||||
CHECK((arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(link1, *logicalCollection, linkJson->slice(), 1, false).ok()));
|
||||
CHECK((false == persisted));
|
||||
CHECK((false == !link1)); // duplicate link creation is allowed
|
||||
std::unordered_set<TRI_voc_cid_t> cids;
|
||||
|
|
|
@ -116,13 +116,9 @@ struct IResearchViewCoordinatorSetup {
|
|||
arangodb::EngineSelectorFeature::ENGINE = &engine;
|
||||
// register factories & normalizers
|
||||
auto& indexFactory = const_cast<arangodb::IndexFactory&>(engine.indexFactory());
|
||||
indexFactory.emplaceFactory(
|
||||
indexFactory.emplace(
|
||||
arangodb::iresearch::DATA_SOURCE_TYPE.name(),
|
||||
arangodb::iresearch::IResearchLinkCoordinator::make
|
||||
);
|
||||
indexFactory.emplaceNormalizer(
|
||||
arangodb::iresearch::DATA_SOURCE_TYPE.name(),
|
||||
arangodb::iresearch::IResearchLinkHelper::normalize
|
||||
arangodb::iresearch::IResearchLinkCoordinator::factory()
|
||||
);
|
||||
|
||||
arangodb::tests::init();
|
||||
|
|
|
@ -557,12 +557,12 @@ std::shared_ptr<arangodb::Index> PhysicalCollectionMock::createIndex(arangodb::v
|
|||
} else if (0 == type.compare(arangodb::iresearch::DATA_SOURCE_TYPE.name())) {
|
||||
|
||||
if (arangodb::ServerState::instance()->isCoordinator()) {
|
||||
index = arangodb::iresearch::IResearchLinkCoordinator::make(
|
||||
_logicalCollection, info, ++lastId, false
|
||||
arangodb::iresearch::IResearchLinkCoordinator::factory().instantiate(
|
||||
index, _logicalCollection, info, ++lastId, false
|
||||
);
|
||||
} else {
|
||||
index = arangodb::iresearch::IResearchMMFilesLink::make(
|
||||
_logicalCollection, info, ++lastId, false
|
||||
arangodb::iresearch::IResearchMMFilesLink::factory().instantiate(
|
||||
index, _logicalCollection, info, ++lastId, false
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
@ -1599,4 +1599,4 @@ bool TransactionStateMock::hasFailedOperations() const {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -29,6 +29,8 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include "Cluster/Maintenance.h"
|
||||
#include "MMFiles/MMFilesEngine.h"
|
||||
#include "StorageEngine/EngineSelectorFeature.h"
|
||||
|
||||
#include <velocypack/Iterator.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
@ -412,7 +414,6 @@ TEST_CASE("ActionDescription", "[cluster][maintenance]") {
|
|||
}
|
||||
|
||||
TEST_CASE("ActionPhaseOne", "[cluster][maintenance]") {
|
||||
|
||||
std::shared_ptr<arangodb::options::ProgramOptions> po =
|
||||
std::make_shared<arangodb::options::ProgramOptions>(
|
||||
"test", std::string(), std::string(), "path");
|
||||
|
@ -425,6 +426,11 @@ TEST_CASE("ActionPhaseOne", "[cluster][maintenance]") {
|
|||
{dbsIds[shortNames[1]], createNode(dbs1Str)},
|
||||
{dbsIds[shortNames[2]], createNode(dbs2Str)}};
|
||||
|
||||
arangodb::MMFilesEngine engine(as); // arbitrary implementation that has index types registered
|
||||
auto* origStorageEngine = arangodb::EngineSelectorFeature::ENGINE;
|
||||
arangodb::EngineSelectorFeature::ENGINE = &engine;
|
||||
auto resetStorageEngine = std::shared_ptr<void>(&engine, [origStorageEngine](void*)->void { arangodb::EngineSelectorFeature::ENGINE = origStorageEngine; });
|
||||
|
||||
SECTION("In sync should have 0 effects") {
|
||||
|
||||
std::vector<ActionDescription> actions;
|
||||
|
@ -893,5 +899,4 @@ TEST_CASE("ActionPhaseTwo", "[cluster][maintenance]") {
|
|||
*/
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
Loading…
Reference in New Issue