From b641cf9b13c907ffd7e367e6ef2a85b467534336 Mon Sep 17 00:00:00 2001 From: Andrey Abramov Date: Mon, 26 Mar 2018 23:18:08 +0300 Subject: [PATCH 1/5] remove view implementation part 1 --- arangod/CMakeLists.txt | 1 + arangod/IResearch/IResearchFeature.cpp | 16 +- arangod/IResearch/IResearchLink.cpp | 6 +- arangod/IResearch/IResearchLink.h | 8 +- .../IResearchRocksDBRecoveryHelper.cpp | 10 +- arangod/IResearch/IResearchView.cpp | 643 ++++++++++-------- arangod/IResearch/IResearchView.h | 64 +- .../IResearch/IResearchViewCoordinator.cpp | 17 + arangod/IResearch/IResearchViewCoordinator.h | 81 +++ arangod/IResearch/IResearchViewNode.cpp | 4 +- arangod/MMFiles/MMFilesEngine.cpp | 32 +- arangod/RestHandler/RestViewHandler.cpp | 16 +- arangod/RestServer/ViewTypesFeature.cpp | 13 +- arangod/RestServer/ViewTypesFeature.h | 10 +- arangod/RocksDBEngine/RocksDBEngine.cpp | 25 +- arangod/V8Server/v8-views.cpp | 2 +- arangod/VocBase/LogicalView.cpp | 175 +++-- arangod/VocBase/LogicalView.h | 125 +++- arangod/VocBase/ViewImplementation.h | 115 ---- arangod/VocBase/vocbase.cpp | 35 +- arangod/VocBase/vocbase.h | 3 +- tests/IResearch/ExpressionFilter-test.cpp | 6 +- tests/IResearch/IResearchIndex-test.cpp | 14 +- tests/IResearch/IResearchLink-test.cpp | 6 +- .../IResearchQueryAggregate-test.cpp | 4 +- tests/IResearch/IResearchQueryAnd-test.cpp | 4 +- .../IResearchQueryBooleanTerm-test.cpp | 4 +- .../IResearchQueryComplexBoolean-test.cpp | 4 +- tests/IResearch/IResearchQueryExists-test.cpp | 2 +- tests/IResearch/IResearchQueryIn-test.cpp | 4 +- tests/IResearch/IResearchQueryJoin-test.cpp | 16 +- .../IResearch/IResearchQueryNullTerm-test.cpp | 4 +- .../IResearchQueryNumericTerm-test.cpp | 10 +- tests/IResearch/IResearchQueryOr-test.cpp | 10 +- tests/IResearch/IResearchQueryPhrase-test.cpp | 4 +- .../IResearchQuerySelectAll-test.cpp | 10 +- .../IResearchQueryStartsWith-test.cpp | 10 +- .../IResearchQueryStringTerm-test.cpp | 10 +- tests/IResearch/IResearchQueryTokens-test.cpp | 4 +- .../IResearchQueryTraversal-test.cpp | 4 +- tests/IResearch/IResearchQueryValue-test.cpp | 4 +- tests/IResearch/IResearchView-test.cpp | 568 +++++++--------- tests/Utils/CollectionNameResolver-test.cpp | 19 +- tests/VocBase/LogicalDataSource-test.cpp | 10 +- tests/VocBase/vocbase-test.cpp | 21 +- 45 files changed, 1106 insertions(+), 1047 deletions(-) create mode 100644 arangod/IResearch/IResearchViewCoordinator.cpp create mode 100644 arangod/IResearch/IResearchViewCoordinator.h delete mode 100644 arangod/VocBase/ViewImplementation.h diff --git a/arangod/CMakeLists.txt b/arangod/CMakeLists.txt index e1e4e921c4..4647e0f2a6 100644 --- a/arangod/CMakeLists.txt +++ b/arangod/CMakeLists.txt @@ -59,6 +59,7 @@ if (USE_IRESEARCH) IResearch/IResearchRocksDBRecoveryHelper.cpp IResearch/IResearchRocksDBRecoveryHelper.h IResearch/IResearchView.cpp IResearch/IResearchView.h + IResearch/IResearchViewCoordinator.cpp IResearch/IResearchViewCoordinator.h IResearch/IResearchViewOptimizerRules.cpp IResearch/IResearchViewOptimizerRules.h IResearch/IResearchViewNode.cpp IResearch/IResearchViewNode.h IResearch/IResearchViewBlock.cpp IResearch/IResearchViewBlock.h diff --git a/arangod/IResearch/IResearchFeature.cpp b/arangod/IResearch/IResearchFeature.cpp index 7066cf160b..55a26891a4 100644 --- a/arangod/IResearch/IResearchFeature.cpp +++ b/arangod/IResearch/IResearchFeature.cpp @@ -27,6 +27,7 @@ #include "IResearchFeature.h" #include "IResearchRocksDBRecoveryHelper.h" #include "IResearchView.h" +#include "IResearchViewCoordinator.h" #include "ApplicationServerHelper.h" #include "RestServer/ViewTypesFeature.h" @@ -36,6 +37,7 @@ #include "StorageEngine/TransactionState.h" #include "Transaction/Methods.h" #include "VocBase/LogicalView.h" +#include "Cluster/ServerState.h" #include "Aql/AqlValue.h" #include "Aql/AqlFunctionFeature.h" @@ -186,9 +188,9 @@ arangodb::Result transactionStateRegistrationCallback( // TODO FIXME find a better way to look up an IResearch View #ifdef ARANGODB_ENABLE_MAINTAINER_MODE - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); #else - auto* impl = static_cast(view->getImplementation()); + auto* impl = static_cast(view); #endif if (!impl) { @@ -269,7 +271,13 @@ void IResearchFeature::prepare() { } // register 'arangosearch' view - viewTypes->emplace(IResearchView::type(), IResearchView::make); + if (arangodb::ServerState::instance()->isCoordinator()) { + viewTypes->emplace(IResearchView::type(), IResearchViewCoordinator::make); + } else { + // DB server in custer or single-server + viewTypes->emplace(IResearchView::type(), IResearchView::make); + } + // register 'arangosearch' TransactionState state-change callback factory arangodb::transaction::Methods::addStateRegistrationCallback( @@ -326,4 +334,4 @@ NS_END // arangodb // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/arangod/IResearch/IResearchLink.cpp b/arangod/IResearch/IResearchLink.cpp index b5e2cb38ee..dfa9e8ff82 100644 --- a/arangod/IResearch/IResearchLink.cpp +++ b/arangod/IResearch/IResearchLink.cpp @@ -231,9 +231,9 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) { // TODO FIXME find a better way to look up an iResearch View #ifdef ARANGODB_ENABLE_MAINTAINER_MODE - auto* view = dynamic_cast(logicalView->getImplementation()); + auto* view = dynamic_cast(logicalView.get()); #else - auto* view = static_cast(logicalView->getImplementation()); + auto* view = static_cast(logicalView.get()); #endif if (!view) { @@ -589,4 +589,4 @@ NS_END // arangodb // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/arangod/IResearch/IResearchLink.h b/arangod/IResearch/IResearchLink.h index 34d444d472..0333012eda 100644 --- a/arangod/IResearch/IResearchLink.h +++ b/arangod/IResearch/IResearchLink.h @@ -205,7 +205,11 @@ class IResearchLink { // FIXME TODO remove once View::updateProperties(...) will be fixed to write // the update delta into the WAL marker instead of the full persisted state // FIXME TODO remove #include "IResearchView.h" - friend arangodb::Result IResearchView::updateProperties(arangodb::velocypack::Slice const&, bool, bool); +// friend arangodb::Result IResearchView::updatePropertiesImpl( +// arangodb::velocypack::Slice const&, bool, bool +// ); + friend class IResearchView; + LogicalCollection* _collection; // the linked collection TRI_voc_cid_t _defaultId; // the identifier of the desired view (iff _view == nullptr) @@ -228,4 +232,4 @@ int EnhanceJsonIResearchLink( NS_END // iresearch NS_END // arangodb -#endif \ No newline at end of file +#endif diff --git a/arangod/IResearch/IResearchRocksDBRecoveryHelper.cpp b/arangod/IResearch/IResearchRocksDBRecoveryHelper.cpp index 1cda5fd814..15329f751b 100644 --- a/arangod/IResearch/IResearchRocksDBRecoveryHelper.cpp +++ b/arangod/IResearch/IResearchRocksDBRecoveryHelper.cpp @@ -218,9 +218,9 @@ void dropCollectionFromAllViews( } #ifdef ARANGODB_ENABLE_MAINTAINER_MODE - auto* view = dynamic_cast(logicalView->getImplementation()); + auto* view = dynamic_cast(logicalView.get()); #else - auto* view = static_cast(logicalView->getImplementation()); + auto* view = static_cast(logicalView.get()); #endif if (!view) { @@ -276,9 +276,9 @@ void dropCollectionFromView( } #ifdef ARANGODB_ENABLE_MAINTAINER_MODE - auto* view = dynamic_cast(logicalView->getImplementation()); + auto* view = dynamic_cast(logicalView.get()); #else - auto* view = static_cast(logicalView->getImplementation()); + auto* view = static_cast(logicalView.get()); #endif if (!view) { @@ -433,4 +433,4 @@ void IResearchRocksDBRecoveryHelper::LogData(const rocksdb::Slice& blob) { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/arangod/IResearch/IResearchView.cpp b/arangod/IResearch/IResearchView.cpp index 111f307260..e364c55ce2 100644 --- a/arangod/IResearch/IResearchView.cpp +++ b/arangod/IResearch/IResearchView.cpp @@ -48,6 +48,7 @@ #include "Aql/SortCondition.h" #include "Basics/Result.h" #include "Basics/files.h" +#include "Basics/WriteLocker.h" #include "Logger/Logger.h" #include "Logger/LogMacros.h" #include "StorageEngine/EngineSelectorFeature.h" @@ -764,10 +765,10 @@ IResearchView::PersistedStore::PersistedStore(irs::utf8_path&& path) } IResearchView::IResearchView( - arangodb::LogicalView* view, + TRI_vocbase_t* vocbase, arangodb::velocypack::Slice const& info, irs::utf8_path&& persistedPath -) : ViewImplementation(view, info), +) : DBServerLogicalView(vocbase, info), FlushTransaction(toString(*this)), _asyncMetaRevision(1), _asyncSelf(irs::memory::make_unique(this)), @@ -1007,13 +1008,25 @@ IResearchView::~IResearchView() { SCOPED_LOCK(mutex); if (_storePersisted) { - _storePersisted._writer->commit(); - _storePersisted._writer->close(); - _storePersisted._writer.reset(); - _storePersisted._directory->close(); - _storePersisted._directory.reset(); + try { + _storePersisted._writer->commit(); + _storePersisted._writer->close(); + _storePersisted._writer.reset(); + _storePersisted._directory->close(); + _storePersisted._directory.reset(); + } catch (...) { + // FIXME add logging + // must not propagate exception out of destructor + } } } + + // noexcept below + if (deleted()) { + StorageEngine* engine = EngineSelectorFeature::ENGINE; + TRI_ASSERT(engine); + engine->destroyView(vocbase(), this); + } } IResearchView::MemoryStore& IResearchView::activeMemoryStore() const { @@ -1025,101 +1038,8 @@ void IResearchView::apply(arangodb::TransactionState& state) { } void IResearchView::drop() { - std::unordered_set collections; - - // drop all known links - if (_logicalView && _logicalView->vocbase()) { - arangodb::velocypack::Builder builder; - - { - ReadMutex mutex(_mutex); - SCOPED_LOCK(mutex); // '_meta' and '_trackedCids' can be asynchronously updated - - builder.openObject(); - - if (!appendLinkRemoval(builder, _meta)) { - throw std::runtime_error(std::string("failed to construct link removal directive while removing iResearch view '") + std::to_string(id()) + "'"); - } - - builder.close(); - } - - if (!updateLinks(collections, *(_logicalView->vocbase()), *this, builder.slice()).ok()) { - throw std::runtime_error(std::string("failed to remove links while removing iResearch view '") + std::to_string(id()) + "'"); - } - } - - { - WriteMutex mutex(_asyncSelf->_mutex); - SCOPED_LOCK(mutex); // wait for all the view users to finish - _asyncSelf->_value.store(nullptr); // the view data-stores are being deallocated, view use is no longer valid - } - - _asyncTerminate.store(true); // mark long-running async jobs for terminatation - - { - SCOPED_LOCK(_asyncMutex); - _asyncCondition.notify_all(); // trigger reload of settings for async jobs - } - - _threadPool.stop(); - - WriteMutex mutex(_mutex); // members can be asynchronously updated - SCOPED_LOCK(mutex); - - collections.insert(_meta._collections.begin(), _meta._collections.end()); - - if (_logicalView->vocbase()) { - validateLinks(collections, *(_logicalView->vocbase()), *this); - } - - // ArangoDB global consistency check, no known dangling links - if (!collections.empty()) { - throw std::runtime_error(std::string("links still present while removing iResearch view '") + std::to_string(id()) + "'"); - } - - // ........................................................................... - // if an exception occurs below than a drop retry would most likely happen - // ........................................................................... - try { - _storeByTid.clear(); - - for (size_t i = 0, count = IRESEARCH_COUNTOF(_memoryNodes); i < count; ++i) { - auto& memoryStore = _memoryNodes[i]._store; - - memoryStore._writer->close(); - memoryStore._writer.reset(); - memoryStore._directory->close(); - memoryStore._directory.reset(); - } - - if (_storePersisted) { - _storePersisted._writer->close(); - _storePersisted._writer.reset(); - _storePersisted._directory->close(); - _storePersisted._directory.reset(); - } - - bool exists; - - // remove persisted data store directory if present - if (_storePersisted._path.exists_directory(exists) - && (!exists || _storePersisted._path.remove())) { - return; // success - } - } catch (std::exception const& e) { - LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) - << "caught exception while removing iResearch view '" << id() << "': " << e.what(); - IR_LOG_EXCEPTION(); - throw; - } catch (...) { - LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) - << "caught exception while removing iResearch view '" << id() << "'"; - IR_LOG_EXCEPTION(); - throw; - } - - throw std::runtime_error(std::string("failed to remove iResearch view '") + arangodb::basics::StringUtils::itoa(id()) + "'"); + dropImpl(); + DBServerLogicalView::drop(); } int IResearchView::drop(TRI_voc_cid_t cid) { @@ -1279,6 +1199,271 @@ arangodb::Result IResearchView::commit() { return {TRI_ERROR_INTERNAL}; } +void IResearchView::dropImpl() { + deleted(true); + + std::unordered_set collections; + + // drop all known links + if (vocbase()) { + arangodb::velocypack::Builder builder; + + { + ReadMutex mutex(_mutex); + SCOPED_LOCK(mutex); // '_meta' and '_trackedCids' can be asynchronously updated + + builder.openObject(); + + if (!appendLinkRemoval(builder, _meta)) { + throw std::runtime_error(std::string("failed to construct link removal directive while removing iResearch view '") + std::to_string(id()) + "'"); + } + + builder.close(); + } + + if (!updateLinks(collections, *(vocbase()), *this, builder.slice()).ok()) { + throw std::runtime_error(std::string("failed to remove links while removing iResearch view '") + std::to_string(id()) + "'"); + } + } + + { + WriteMutex mutex(_asyncSelf->_mutex); + SCOPED_LOCK(mutex); // wait for all the view users to finish + _asyncSelf->_value.store(nullptr); // the view data-stores are being deallocated, view use is no longer valid + } + + _asyncTerminate.store(true); // mark long-running async jobs for terminatation + + { + SCOPED_LOCK(_asyncMutex); + _asyncCondition.notify_all(); // trigger reload of settings for async jobs + } + + _threadPool.stop(); + + WriteMutex mutex(_mutex); // members can be asynchronously updated + SCOPED_LOCK(mutex); + + collections.insert(_meta._collections.begin(), _meta._collections.end()); + + if (vocbase()) { + validateLinks(collections, *(vocbase()), *this); + } + + // ArangoDB global consistency check, no known dangling links + if (!collections.empty()) { + throw std::runtime_error(std::string("links still present while removing iResearch view '") + std::to_string(id()) + "'"); + } + + // ........................................................................... + // if an exception occurs below than a drop retry would most likely happen + // ........................................................................... + try { + _storeByTid.clear(); + + for (size_t i = 0, count = IRESEARCH_COUNTOF(_memoryNodes); i < count; ++i) { + auto& memoryStore = _memoryNodes[i]._store; + + memoryStore._writer->close(); + memoryStore._writer.reset(); + memoryStore._directory->close(); + memoryStore._directory.reset(); + } + + if (_storePersisted) { + _storePersisted._writer->close(); + _storePersisted._writer.reset(); + _storePersisted._directory->close(); + _storePersisted._directory.reset(); + } + + bool exists; + + // remove persisted data store directory if present + if (_storePersisted._path.exists_directory(exists) + && (!exists || _storePersisted._path.remove())) { + return; // success + } + } catch (std::exception const& e) { + LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) + << "caught exception while removing iResearch view '" << id() << "': " << e.what(); + IR_LOG_EXCEPTION(); + throw; + } catch (...) { + LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) + << "caught exception while removing iResearch view '" << id() << "'"; + IR_LOG_EXCEPTION(); + throw; + } + + throw std::runtime_error(std::string("failed to remove iResearch view '") + arangodb::basics::StringUtils::itoa(id()) + "'"); +} + +arangodb::Result IResearchView::updatePropertiesImpl( + const velocypack::Slice &slice, + bool partialUpdate, + bool doSync +) { + auto* vocbase = this->vocbase(); + + if (!vocbase) { + return arangodb::Result( + TRI_ERROR_INTERNAL, + std::string("failed to find vocbase while updating links for iResearch view '") + std::to_string(id()) + "'" + ); + } + + std::string error; + IResearchViewMeta meta; + IResearchViewMeta::Mask mask; + WriteMutex mutex(_mutex); // '_meta' can be asynchronously read + arangodb::Result res = arangodb::Result(/*TRI_ERROR_NO_ERROR*/); + + { + SCOPED_LOCK(mutex); + + arangodb::velocypack::Builder originalMetaJson; // required for reverting links on failure + + if (!_meta.json(arangodb::velocypack::ObjectBuilder(&originalMetaJson))) { + return arangodb::Result( + TRI_ERROR_INTERNAL, + std::string("failed to generate json definition while updating iResearch view '") + std::to_string(id()) + "'" + ); + } + + auto& initialMeta = partialUpdate ? _meta : IResearchViewMeta::DEFAULT(); + + if (!meta.init(slice, error, initialMeta, &mask)) { + return arangodb::Result(TRI_ERROR_BAD_PARAMETER, std::move(error)); + } + + // FIXME TODO remove once View::updateProperties(...) will be fixed to write + // the update delta into the WAL marker instead of the full persisted state + // below is a very dangerous hack as it allows multiple links from the same + // collection to point to the same view, thus breaking view data consistency + { + auto* engine = arangodb::EngineSelectorFeature::ENGINE; + + if (engine && engine->inRecovery()) { + arangodb::velocypack::Builder linksBuilder; + + linksBuilder.openObject(); + + // remove links no longer present in incming update + for (auto& cid: _meta._collections) { + if (meta._collections.find(cid) == meta._collections.end()) { + linksBuilder.add( + std::to_string(cid), + arangodb::velocypack::Value(arangodb::velocypack::ValueType::Null) + ); + } + } + + for (auto& cid: meta._collections) { + auto collection = vocbase->lookupCollection(cid); + + if (collection) { + _meta._collections.emplace(cid); + + for (auto& index: collection->getIndexes()) { + if (index && arangodb::Index::TRI_IDX_TYPE_IRESEARCH_LINK == index->type()) { + auto* link = dynamic_cast(index.get()); + + if (link && link->_defaultId == id() && !link->view()) { + arangodb::velocypack::Builder linkBuilder; + bool valid; + + linkBuilder.openObject(); + valid = link->json(linkBuilder, true); + linkBuilder.close(); + + linksBuilder.add( + std::to_string(cid), + arangodb::velocypack::Value(arangodb::velocypack::ValueType::Null) + ); + + if (valid) { + linksBuilder.add(std::to_string(cid), linkBuilder.slice()); + } + } + } + } + } + } + + std::unordered_set collections; + + linksBuilder.close(); + updateLinks(collections, *vocbase, *this, linksBuilder.slice()); + collections.insert(_meta._collections.begin(), _meta._collections.end()); + validateLinks(collections, *vocbase, *this); // remove invalid cids (no such collection or no such link) + _meta._collections = std::move(collections); + } + } + + // reset non-updatable values to match current meta + meta._collections = _meta._collections; + + if (mask._threadsMaxIdle) { + _threadPool.max_idle(meta._threadsMaxIdle); + } + + if (mask._threadsMaxTotal) { + _threadPool.max_threads(meta._threadsMaxTotal); + } + + { + SCOPED_LOCK(_asyncMutex); + _asyncCondition.notify_all(); // trigger reload of timeout settings for async jobs + } + + _meta = std::move(meta); + } + + std::unordered_set collections; + + // update links if requested (on a best-effort basis) + // indexing of collections is done in different threads so no locks can be held and rollback is not possible + // as a result it's also possible for links to be simultaneously modified via a different callflow (e.g. from collections) + if (slice.hasKey(LINKS_FIELD)) { + if (partialUpdate) { + res = updateLinks(collections, *vocbase, *this, slice.get(LINKS_FIELD)); + } else { + arangodb::velocypack::Builder builder; + + builder.openObject(); + + if (!appendLinkRemoval(builder, _meta) + || !mergeSlice(builder, slice.get(LINKS_FIELD))) { + return arangodb::Result( + TRI_ERROR_INTERNAL, + std::string("failed to construct link update directive while updating iResearch view '") + std::to_string(id()) + "'" + ); + } + + builder.close(); + res = updateLinks(collections, *vocbase, *this, builder.slice()); + } + } + + // ........................................................................... + // if an exception occurs below then it would only affect collection linking + // consistency and an update retry would most likely happen + // always re-validate '_collections' because may have had externally triggered + // collection/link drops + // ........................................................................... + { + SCOPED_LOCK(mutex); // '_meta' can be asynchronously read + collections.insert(_meta._collections.begin(), _meta._collections.end()); + validateLinks(collections, *vocbase, *this); // remove invalid cids (no such collection or no such link) + _meta._collections = std::move(collections); + } + + // FIXME TODO to ensure valid recovery remove the original datapath only if the entire, but under lock to prevent double rename + + return res; +} + void IResearchView::getPropertiesVPack( arangodb::velocypack::Builder& builder, bool forPersistence ) const { @@ -1287,7 +1472,7 @@ void IResearchView::getPropertiesVPack( _meta.json(builder); - if (!_logicalView || !_logicalView->vocbase() || forPersistence) { + if (!vocbase() || forPersistence) { return; // nothing more to output (persistent configuration does not need links) } @@ -1296,7 +1481,7 @@ void IResearchView::getPropertiesVPack( // add CIDs of known collections to list for (auto& entry: _meta._collections) { // skip collections missing from vocbase or UserTransaction constructor will throw an exception - if (nullptr != _logicalView->vocbase()->lookupCollection(entry)) { + if (nullptr != vocbase()->lookupCollection(entry)) { collections.emplace_back(std::to_string(entry)); } } @@ -1312,7 +1497,7 @@ void IResearchView::getPropertiesVPack( try { arangodb::transaction::UserTransaction trx( - transaction::StandaloneContext::Create(_logicalView->vocbase()), + transaction::StandaloneContext::Create(vocbase()), collections, // readCollections EMPTY, // writeCollections EMPTY, // exclusiveCollections @@ -1375,10 +1560,6 @@ void IResearchView::getPropertiesVPack( builder.add(LINKS_FIELD, linksBuilder.slice()); } -TRI_voc_cid_t IResearchView::id() const noexcept { - return _logicalView ? _logicalView->id() : 0; // 0 is an invalid view id -} - int IResearchView::insert( transaction::Methods& trx, TRI_voc_cid_t cid, @@ -1537,14 +1718,7 @@ arangodb::Result IResearchView::link( TRI_voc_cid_t cid, arangodb::velocypack::Slice const link ) { - if (!_logicalView) { - return arangodb::Result( - TRI_ERROR_INTERNAL, - std::string("failed to find logical view while linking IResearch view '") + std::to_string(id()) + "'" - ); - } - - auto* vocbase = _logicalView->vocbase(); + auto* vocbase = this->vocbase(); if (!vocbase) { return arangodb::Result( @@ -1582,14 +1756,17 @@ arangodb::Result IResearchView::link( return result; } -/*static*/ IResearchView::ptr IResearchView::make( - arangodb::LogicalView* view, +/*static*/ std::shared_ptr IResearchView::make( + TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& info, bool isNew ) { - if (!view) { + auto const id = readViewId(info); + + if (0 == id) { + // invalid ID LOG_TOPIC(WARN, IResearchFeature::IRESEARCH) - << "invalid LogicalView argument while constructing IResearch view"; + << "got invalid view identifier while constructing IResearch view"; return nullptr; } @@ -1598,7 +1775,8 @@ arangodb::Result IResearchView::link( if (!feature) { LOG_TOPIC(WARN, IResearchFeature::IRESEARCH) - << "failure to find feature 'DatabasePath' while constructing IResearch view '" << view->id() << "'"; + << "failure to find feature 'DatabasePath' while constructing IResearch view '" + << id << "' in database '" << vocbase.id() << "'"; return nullptr; } @@ -1613,21 +1791,23 @@ arangodb::Result IResearchView::link( dataPath /= subPath; dataPath /= arangodb::iresearch::IResearchView::type().name(); dataPath += "-"; - dataPath += std::to_string(view->id()); + dataPath += std::to_string(id); + + auto ptr = std::unique_ptr( + new IResearchView(&vocbase, info, std::move(dataPath)) + ); - PTR_NAMED(IResearchView, ptr, view, info, std::move(dataPath)); - auto& impl = reinterpret_cast(*ptr); auto& json = info.isNone() ? emptyObjectSlice() : info; // if no 'info' then assume defaults std::string error; - if (!impl._meta.init(json, error)) { + if (!ptr->_meta.init(json, error)) { LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) << "failed to initialize iResearch view from definition, error: " << error; return nullptr; } - return std::move(ptr); + return std::shared_ptr(std::move(ptr)); } size_t IResearchView::memory() const { @@ -1940,10 +2120,34 @@ arangodb::Result IResearchView::updateLogicalProperties( bool partialUpdate, bool doSync ) { - return _logicalView - ? _logicalView->updateProperties(slice, partialUpdate, doSync) - : arangodb::Result(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND) - ; + // FIXME remove + return updateProperties(slice, partialUpdate, doSync); +} + +void IResearchView::toVelocyPack( + velocypack::Builder& result, + bool includeProperties, + bool includeSystem +) const { + // We write into an open object + TRI_ASSERT(result.isOpenObject()); + + DBServerLogicalView::toVelocyPack(result, includeProperties, includeSystem); + + // Object is still open + TRI_ASSERT(result.isOpenObject()); + + if (includeProperties) { + // implementation Information + result.add("properties", VPackValue(VPackValueType::Object)); + // note: includeSystem and forPersistence are not 100% synonymous, + // however, for our purposes this is an okay mapping; we only set + // includeSystem if we are persisting the properties + getPropertiesVPack(result, includeSystem); + result.close(); + } + + TRI_ASSERT(result.isOpenObject()); // We leave the object open } arangodb::Result IResearchView::updateProperties( @@ -1951,170 +2155,15 @@ arangodb::Result IResearchView::updateProperties( bool partialUpdate, bool doSync ) { - if (!_logicalView) { - return arangodb::Result( - TRI_ERROR_INTERNAL, - std::string("failed to find logical view while updating IResearch view '") + std::to_string(id()) + "'" - ); + WRITE_LOCKER(writeLocker, _infoLock); + + // the implementation may filter/change/react to the changes + auto res = updatePropertiesImpl(slice, partialUpdate, doSync); + + if (res.ok()) { + res = DBServerLogicalView::updateProperties(slice, partialUpdate, doSync); } - auto* vocbase = _logicalView->vocbase(); - - if (!vocbase) { - return arangodb::Result( - TRI_ERROR_INTERNAL, - std::string("failed to find vocbase while updating links for iResearch view '") + std::to_string(id()) + "'" - ); - } - - std::string error; - IResearchViewMeta meta; - IResearchViewMeta::Mask mask; - WriteMutex mutex(_mutex); // '_meta' can be asynchronously read - arangodb::Result res = arangodb::Result(/*TRI_ERROR_NO_ERROR*/); - - { - SCOPED_LOCK(mutex); - - arangodb::velocypack::Builder originalMetaJson; // required for reverting links on failure - - if (!_meta.json(arangodb::velocypack::ObjectBuilder(&originalMetaJson))) { - return arangodb::Result( - TRI_ERROR_INTERNAL, - std::string("failed to generate json definition while updating iResearch view '") + std::to_string(id()) + "'" - ); - } - - auto& initialMeta = partialUpdate ? _meta : IResearchViewMeta::DEFAULT(); - - if (!meta.init(slice, error, initialMeta, &mask)) { - return arangodb::Result(TRI_ERROR_BAD_PARAMETER, std::move(error)); - } - - // FIXME TODO remove once View::updateProperties(...) will be fixed to write - // the update delta into the WAL marker instead of the full persisted state - // below is a very dangerous hack as it allows multiple links from the same - // collection to point to the same view, thus breaking view data consistency - { - auto* engine = arangodb::EngineSelectorFeature::ENGINE; - - if (engine && engine->inRecovery()) { - arangodb::velocypack::Builder linksBuilder; - - linksBuilder.openObject(); - - // remove links no longer present in incming update - for (auto& cid: _meta._collections) { - if (meta._collections.find(cid) == meta._collections.end()) { - linksBuilder.add( - std::to_string(cid), - arangodb::velocypack::Value(arangodb::velocypack::ValueType::Null) - ); - } - } - - for (auto& cid: meta._collections) { - auto collection = vocbase->lookupCollection(cid); - - if (collection) { - _meta._collections.emplace(cid); - - for (auto& index: collection->getIndexes()) { - if (index && arangodb::Index::TRI_IDX_TYPE_IRESEARCH_LINK == index->type()) { - auto* link = dynamic_cast(index.get()); - - if (link && link->_defaultId == id() && !link->view()) { - arangodb::velocypack::Builder linkBuilder; - bool valid; - - linkBuilder.openObject(); - valid = link->json(linkBuilder, true); - linkBuilder.close(); - - linksBuilder.add( - std::to_string(cid), - arangodb::velocypack::Value(arangodb::velocypack::ValueType::Null) - ); - - if (valid) { - linksBuilder.add(std::to_string(cid), linkBuilder.slice()); - } - } - } - } - } - } - - std::unordered_set collections; - - linksBuilder.close(); - updateLinks(collections, *vocbase, *this, linksBuilder.slice()); - collections.insert(_meta._collections.begin(), _meta._collections.end()); - validateLinks(collections, *vocbase, *this); // remove invalid cids (no such collection or no such link) - _meta._collections = std::move(collections); - } - } - - // reset non-updatable values to match current meta - meta._collections = _meta._collections; - - if (mask._threadsMaxIdle) { - _threadPool.max_idle(meta._threadsMaxIdle); - } - - if (mask._threadsMaxTotal) { - _threadPool.max_threads(meta._threadsMaxTotal); - } - - { - SCOPED_LOCK(_asyncMutex); - _asyncCondition.notify_all(); // trigger reload of timeout settings for async jobs - } - - _meta = std::move(meta); - } - - std::unordered_set collections; - - // update links if requested (on a best-effort basis) - // indexing of collections is done in different threads so no locks can be held and rollback is not possible - // as a result it's also possible for links to be simultaneously modified via a different callflow (e.g. from collections) - if (slice.hasKey(LINKS_FIELD)) { - if (partialUpdate) { - res = updateLinks(collections, *vocbase, *this, slice.get(LINKS_FIELD)); - } else { - arangodb::velocypack::Builder builder; - - builder.openObject(); - - if (!appendLinkRemoval(builder, _meta) - || !mergeSlice(builder, slice.get(LINKS_FIELD))) { - return arangodb::Result( - TRI_ERROR_INTERNAL, - std::string("failed to construct link update directive while updating iResearch view '") + std::to_string(id()) + "'" - ); - } - - builder.close(); - res = updateLinks(collections, *vocbase, *this, builder.slice()); - } - } - - // ........................................................................... - // if an exception occurs below then it would only affect collection linking - // consistency and an update retry would most likely happen - // always re-validate '_collections' because may have had externally triggered - // collection/link drops - // ........................................................................... - { - SCOPED_LOCK(mutex); // '_meta' can be asynchronously read - collections.insert(_meta._collections.begin(), _meta._collections.end()); - validateLinks(collections, *vocbase, *this); // remove invalid cids (no such collection or no such link) - _meta._collections = std::move(collections); - } - - // FIXME TODO to ensure valid recovery remove the original datapath only if the entire, but under lock to prevent double rename - return res; } @@ -2151,7 +2200,7 @@ void IResearchView::registerFlushCallback() { } bool IResearchView::visitCollections( - std::function const& visitor + LogicalView::CollectionVisitor const& visitor ) const { ReadMutex mutex(_mutex); SCOPED_LOCK(mutex); @@ -2209,14 +2258,14 @@ void IResearchView::verifyKnownCollections() { } for (auto cid : cids) { - auto collection = _logicalView->vocbase()->lookupCollection(cid); + auto collection = vocbase()->lookupCollection(cid); if (!collection) { // collection no longer exists, drop it and move on LOG_TOPIC(TRACE, arangodb::iresearch::IResearchFeature::IRESEARCH) << "collection '" << cid << "' no longer exists! removing from IResearch view '" - << _logicalView->id() << "'"; + << id() << "'"; drop(cid); } else { // see if the link still exists, otherwise drop and move on @@ -2225,7 +2274,7 @@ void IResearchView::verifyKnownCollections() { LOG_TOPIC(TRACE, arangodb::iresearch::IResearchFeature::IRESEARCH) << "collection '" << cid << "' no longer linked! removing from IResearch view '" - << _logicalView->id() << "'"; + << id() << "'"; drop(cid); } } diff --git a/arangod/IResearch/IResearchView.h b/arangod/IResearch/IResearchView.h index f419c9e920..3de7af8cbe 100644 --- a/arangod/IResearch/IResearchView.h +++ b/arangod/IResearch/IResearchView.h @@ -26,9 +26,11 @@ #include "Containers.h" #include "IResearchViewMeta.h" +#include "Basics/ReadWriteLock.h" +#include "Basics/WriteLocker.h" #include "VocBase/LogicalDataSource.h" #include "VocBase/LocalDocumentId.h" -#include "VocBase/ViewImplementation.h" +#include "VocBase/LogicalView.h" #include "Utils/FlushTransaction.h" #include "store/directory.hpp" @@ -98,7 +100,7 @@ class PrimaryKeyIndexReader: public irs::index_reader { /////////////////////////////////////////////////////////////////////////////// /// @brief an abstraction over the IResearch index implementing the -/// ViewImplementation interface +/// LogicalView interface /// @note the responsibility of the IResearchView API is to only manage the /// IResearch data store, i.e. insert/remove/query /// the IResearchView API does not manage which and how the data gets @@ -107,12 +109,9 @@ class PrimaryKeyIndexReader: public irs::index_reader { /// which may be, but are not explicitly required to be, triggered via /// the IResearchLink or IResearchViewBlock /////////////////////////////////////////////////////////////////////////////// -class IResearchView final: public arangodb::ViewImplementation, +class IResearchView final: public arangodb::DBServerLogicalView, public arangodb::FlushTransaction { public: - typedef std::unique_ptr ptr; - typedef std::shared_ptr sptr; - /////////////////////////////////////////////////////////////////////////////// /// @brief AsyncValue holding the view itself, modifiable by IResearchView /////////////////////////////////////////////////////////////////////////////// @@ -128,6 +127,8 @@ class IResearchView final: public arangodb::ViewImplementation, /////////////////////////////////////////////////////////////////////////////// virtual ~IResearchView(); + using arangodb::LogicalView::name; + /////////////////////////////////////////////////////////////////////////////// /// @brief apply any changes to 'state' required by this view /////////////////////////////////////////////////////////////////////////////// @@ -150,20 +151,6 @@ class IResearchView final: public arangodb::ViewImplementation, //////////////////////////////////////////////////////////////////////////////// int drop(TRI_voc_cid_t cid); - /////////////////////////////////////////////////////////////////////////////// - /// @brief fill and return a JSON description of a IResearchView object - /// only fields describing the view itself, not 'link' descriptions - //////////////////////////////////////////////////////////////////////////////// - void getPropertiesVPack( - arangodb::velocypack::Builder& builder, - bool forPersistence - ) const override; - - //////////////////////////////////////////////////////////////////////////////// - /// @brief the id identifying the current iResearch View or '0' if unknown - //////////////////////////////////////////////////////////////////////////////// - TRI_voc_cid_t id() const noexcept; - //////////////////////////////////////////////////////////////////////////////// /// @brief insert a document into this IResearch View and the underlying /// IResearch stores @@ -205,8 +192,8 @@ class IResearchView final: public arangodb::ViewImplementation, /// @brief view factory /// @returns initialized view object /////////////////////////////////////////////////////////////////////////////// - static ptr make( - arangodb::LogicalView* view, + static std::shared_ptr make( + TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& info, bool isNew ); @@ -269,6 +256,12 @@ class IResearchView final: public arangodb::ViewImplementation, bool doSync ); + void toVelocyPack( + velocypack::Builder& result, + bool includeProperties, + bool includeSystem + ) const override; + /////////////////////////////////////////////////////////////////////////////// /// @brief called when a view's properties are updated (i.e. delta-modified) /////////////////////////////////////////////////////////////////////////////// @@ -282,9 +275,7 @@ class IResearchView final: public arangodb::ViewImplementation, /// @brief visit all collection IDs that were added to the view /// @return 'visitor' success /////////////////////////////////////////////////////////////////////////////// - bool visitCollections( - std::function const& visitor - ) const override; + bool visitCollections(CollectionVisitor const& visitor) const override; private: struct DataStore { @@ -334,11 +325,28 @@ class IResearchView final: public arangodb::ViewImplementation, > FlushTransactionPtr; IResearchView( - arangodb::LogicalView*, + TRI_vocbase_t* vocbase, arangodb::velocypack::Slice const& info, irs::utf8_path&& persistedPath ); + // FIXME remove + void dropImpl(); + arangodb::Result updatePropertiesImpl( + arangodb::velocypack::Slice const& slice, + bool partialUpdate, + bool doSync + ); + + /////////////////////////////////////////////////////////////////////////////// + /// @brief fill and return a JSON description of a IResearchView object + /// only fields describing the view itself, not 'link' descriptions + //////////////////////////////////////////////////////////////////////////////// + void getPropertiesVPack( + arangodb::velocypack::Builder& builder, + bool forPersistence + ) const; + ////////////////////////////////////////////////////////////////////////////// /// @brief Called in post-recovery to remove any dangling documents old links ////////////////////////////////////////////////////////////////////////////// @@ -374,8 +382,10 @@ class IResearchView final: public arangodb::ViewImplementation, std::function _trxReadCallback; // for snapshot(...) std::function _trxWriteCallback; // for insert(...)/remove(...) std::atomic _inRecovery; + + mutable basics::ReadWriteLock _infoLock; // lock protecting the properties }; NS_END // iresearch NS_END // arangodb -#endif \ No newline at end of file +#endif diff --git a/arangod/IResearch/IResearchViewCoordinator.cpp b/arangod/IResearch/IResearchViewCoordinator.cpp new file mode 100644 index 0000000000..df858b9ce9 --- /dev/null +++ b/arangod/IResearch/IResearchViewCoordinator.cpp @@ -0,0 +1,17 @@ +#include "IResearchViewCoordinator.h" + +namespace arangodb { +namespace iresearch { + +/*static*/ std::shared_ptr IResearchViewCoordinator::make( + TRI_vocbase_t& vocbase, + arangodb::velocypack::Slice const& info, + bool isNew +) { + // FIXME implement + return nullptr; +} + + +} // iresearch +} // arangodb diff --git a/arangod/IResearch/IResearchViewCoordinator.h b/arangod/IResearch/IResearchViewCoordinator.h new file mode 100644 index 0000000000..b1a4bd4a76 --- /dev/null +++ b/arangod/IResearch/IResearchViewCoordinator.h @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////////////////////////// +/// DISCLAIMER +/// +/// Copyright 2018 ArangoDB GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is ArangoDB GmbH, Cologne, Germany +/// +/// @author Andrey Abramov +/// @author Vasiliy Nabatchikov +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ARANGODB_IRESEARCH__IRESEARCH_VIEW_COORDINATOR_H +#define ARANGODB_IRESEARCH__IRESEARCH_VIEW_COORDINATOR_H 1 + +#include "VocBase/LogicalView.h" + +namespace arangodb { +namespace iresearch { + +/////////////////////////////////////////////////////////////////////////////// +/// @class IResearchViewCoordinator +/// @brief an abstraction over the distributed IResearch index implementing the +/// LogicalView interface +/////////////////////////////////////////////////////////////////////////////// +class IResearchViewCoordinator final: public arangodb::LogicalView { + public: + /////////////////////////////////////////////////////////////////////////////// + /// @brief view factory + /// @returns initialized view object + /////////////////////////////////////////////////////////////////////////////// + static std::shared_ptr make( + TRI_vocbase_t& vocbase, + arangodb::velocypack::Slice const& info, + bool isNew + ); + + bool visitCollections(CollectionVisitor const& visitor) const override { + return false; + } + + void open() override { } + + void drop() override { } + + virtual Result rename(std::string&& newName, bool doSync) { + return { TRI_ERROR_NOT_IMPLEMENTED }; + } + + virtual void toVelocyPack( + arangodb::velocypack::Builder& result, + bool includeProperties = false, + bool includeSystem = false + ) const { + // FIXME: implement + } + + virtual arangodb::Result updateProperties( + arangodb::velocypack::Slice const& properties, + bool partialUpdate, + bool doSync + ) { + return { TRI_ERROR_NOT_IMPLEMENTED }; + } +}; // IResearchViewCoordinator + +} // iresearch +} // arangodb + +#endif // ARANGODB_IRESEARCH__IRESEARCH_VIEW_COORDINATOR_H diff --git a/arangod/IResearch/IResearchViewNode.cpp b/arangod/IResearch/IResearchViewNode.cpp index 5f9f39e8ba..bae345ab79 100644 --- a/arangod/IResearch/IResearchViewNode.cpp +++ b/arangod/IResearch/IResearchViewNode.cpp @@ -279,9 +279,9 @@ std::unique_ptr IResearchViewNode::createBlock( std::unordered_set const& ) const { #ifdef ARANGODB_ENABLE_MAINTAINER_MODE - auto* impl = dynamic_cast(view()->getImplementation()); + auto* impl = dynamic_cast(view().get()); #else - auto* impl = static_cast(view()->getImplementation()); + auto* impl = static_cast(view().get()); #endif if (!impl) { diff --git a/arangod/MMFiles/MMFilesEngine.cpp b/arangod/MMFiles/MMFilesEngine.cpp index 0ed355239c..6159bd6758 100644 --- a/arangod/MMFiles/MMFilesEngine.cpp +++ b/arangod/MMFiles/MMFilesEngine.cpp @@ -2040,8 +2040,9 @@ TRI_vocbase_t* MMFilesEngine::openExistingDatabase(TRI_voc_tick_t id, std::string const& name, bool wasCleanShutdown, bool isUpgrade) { - auto vocbase = - std::make_unique(TRI_VOCBASE_TYPE_NORMAL, id, name); + auto vocbase = std::make_unique( + TRI_VOCBASE_TYPE_NORMAL, id, name + ); // scan the database path for views try { @@ -2055,7 +2056,7 @@ TRI_vocbase_t* MMFilesEngine::openExistingDatabase(TRI_voc_tick_t id, VPackSlice slice = builder.slice(); TRI_ASSERT(slice.isArray()); - ViewTypesFeature* viewTypesFeature = + auto const* viewTypes = application_features::ApplicationServer::getFeature( "ViewTypes"); @@ -2063,11 +2064,11 @@ TRI_vocbase_t* MMFilesEngine::openExistingDatabase(TRI_voc_tick_t id, // we found a view that is still active LOG_TOPIC(TRACE, Logger::FIXME) << "processing view: " << it.toJson(); - arangodb::velocypack::StringRef type(it.get("type")); - auto& dataSourceType = arangodb::LogicalDataSource::Type::emplace(type); - auto& creator = viewTypesFeature->factory(dataSourceType); + arangodb::velocypack::StringRef const type(it.get("type")); + auto const& dataSourceType = arangodb::LogicalDataSource::Type::emplace(type); + auto const& viewFactory = viewTypes->factory(dataSourceType); - if (!creator) { + if (!viewFactory) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "no handler found for view type" @@ -2085,18 +2086,21 @@ TRI_vocbase_t* MMFilesEngine::openExistingDatabase(TRI_voc_tick_t id, ); } - auto view = std::make_shared(vocbase.get(), it); + auto view = viewFactory(*vocbase, it, false); + + if (!view) { + auto const message = + "failed to instantiate view of type " + + dataSourceType.name(); + + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message.c_str()); + } StorageEngine::registerView(vocbase.get(), view); registerViewPath(vocbase->id(), view->id(), viewPath); - view->spawnImplementation(creator, it, false); - - if (view->getImplementation() == nullptr) { - THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "unable to spawn view implementation"); - } - view->getImplementation()->open(); + view->open(); } } catch (std::exception const& ex) { LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error while opening database views: " diff --git a/arangod/RestHandler/RestViewHandler.cpp b/arangod/RestHandler/RestViewHandler.cpp index 1ca3458f78..e35b5b9895 100644 --- a/arangod/RestHandler/RestViewHandler.cpp +++ b/arangod/RestHandler/RestViewHandler.cpp @@ -124,7 +124,7 @@ void RestViewHandler::createView() { if (view != nullptr) { VPackBuilder props; props.openObject(); - view->toVelocyPack(props); + view->toVelocyPack(props, false, false); props.close(); generateResult(rest::ResponseCode::CREATED, props.slice()); } else { @@ -194,12 +194,14 @@ void RestViewHandler::modifyView(bool partialUpdate) { return; } - auto result = view->updateProperties(body, partialUpdate, - true); // TODO: not force sync? + auto const result = view->updateProperties( + body, partialUpdate, true + ); // TODO: not force sync? + if (result.ok()) { VPackBuilder updated; updated.openObject(); - view->getImplementation()->getPropertiesVPack(updated, false); + view->toVelocyPack(updated, false, false); updated.close(); generateResult(rest::ResponseCode::OK, updated.slice()); return; @@ -283,7 +285,7 @@ void RestViewHandler::getListOfViews() { for (std::shared_ptr view : views) { if (view.get() != nullptr) { props.openObject(); - view->toVelocyPack(props, true); + view->toVelocyPack(props, true, false); props.close(); } } @@ -297,7 +299,7 @@ void RestViewHandler::getSingleView(std::string const& name) { if (view.get() != nullptr) { VPackBuilder props; props.openObject(); - view->toVelocyPack(props, true); + view->toVelocyPack(props, true, false); props.close(); generateResult(rest::ResponseCode::OK, props.slice()); } else { @@ -312,7 +314,7 @@ void RestViewHandler::getViewProperties(std::string const& name) { if (view.get() != nullptr) { VPackBuilder props; props.openObject(); - view->getImplementation()->getPropertiesVPack(props, false); + view->toVelocyPack(props, false, false); props.close(); generateResult(rest::ResponseCode::OK, props.slice()); } else { diff --git a/arangod/RestServer/ViewTypesFeature.cpp b/arangod/RestServer/ViewTypesFeature.cpp index 95cb57be69..08a9e385d2 100644 --- a/arangod/RestServer/ViewTypesFeature.cpp +++ b/arangod/RestServer/ViewTypesFeature.cpp @@ -29,7 +29,7 @@ namespace { std::string const FEATURE_NAME("ViewTypes"); -arangodb::ViewCreator const INVALID{}; +arangodb::ViewFactory const INVALID{}; } // namespace @@ -45,12 +45,12 @@ ViewTypesFeature::ViewTypesFeature( bool ViewTypesFeature::emplace( LogicalDataSource::Type const& type, - ViewCreator creator + ViewFactory const& creator ) { return _factories.emplace(&type, creator).second; } -ViewCreator const& ViewTypesFeature::factory( +ViewFactory const& ViewTypesFeature::factory( LogicalDataSource::Type const& type ) const noexcept { auto itr = _factories.find(&type); @@ -62,10 +62,11 @@ ViewCreator const& ViewTypesFeature::factory( return FEATURE_NAME; } -void ViewTypesFeature::prepare() { -} +void ViewTypesFeature::prepare() { } -void ViewTypesFeature::unprepare() { _factories.clear(); } +void ViewTypesFeature::unprepare() { + _factories.clear(); +} } // arangodb diff --git a/arangod/RestServer/ViewTypesFeature.h b/arangod/RestServer/ViewTypesFeature.h index 357aa1a112..31740720c0 100644 --- a/arangod/RestServer/ViewTypesFeature.h +++ b/arangod/RestServer/ViewTypesFeature.h @@ -25,7 +25,7 @@ #include "ApplicationFeatures/ApplicationFeature.h" #include "VocBase/LogicalDataSource.h" -#include "VocBase/ViewImplementation.h" +#include "VocBase/LogicalView.h" namespace arangodb { @@ -35,10 +35,10 @@ class ViewTypesFeature final: public application_features::ApplicationFeature { public: /// @return 'factory' for 'type' was added successfully - bool emplace(LogicalDataSource::Type const& type, ViewCreator factory); + bool emplace(LogicalDataSource::Type const& type, ViewFactory const& factory); /// @return factory for the specified type or false if no such type - ViewCreator const& factory( + ViewFactory const& factory( LogicalDataSource::Type const& type ) const noexcept; @@ -47,9 +47,9 @@ class ViewTypesFeature final: public application_features::ApplicationFeature { void unprepare() override final; private: - std::unordered_map _factories; + std::unordered_map _factories; }; } -#endif \ No newline at end of file +#endif diff --git a/arangod/RocksDBEngine/RocksDBEngine.cpp b/arangod/RocksDBEngine/RocksDBEngine.cpp index 4a2ae7d3c3..10a44ac2c6 100644 --- a/arangod/RocksDBEngine/RocksDBEngine.cpp +++ b/arangod/RocksDBEngine/RocksDBEngine.cpp @@ -1687,20 +1687,20 @@ TRI_vocbase_t* RocksDBEngine::openExistingDatabase(TRI_voc_tick_t id, THROW_ARANGO_EXCEPTION(res); } - VPackSlice slice = builder.slice(); + VPackSlice const slice = builder.slice(); TRI_ASSERT(slice.isArray()); - ViewTypesFeature* viewTypesFeature = + auto const* viewTypes = application_features::ApplicationServer::getFeature( "ViewTypes"); for (auto const& it : VPackArrayIterator(slice)) { // we found a view that is still active - arangodb::velocypack::StringRef type(it.get("type")); - auto& dataSourceType = arangodb::LogicalDataSource::Type::emplace(type); - auto& creator = viewTypesFeature->factory(dataSourceType); + arangodb::velocypack::StringRef const type(it.get("type")); + auto const& dataSourceType = arangodb::LogicalDataSource::Type::emplace(type); + auto const& viewFactory = viewTypes->factory(dataSourceType); - if (!creator) { + if (!viewFactory) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "no handler found for view type" @@ -1709,12 +1709,19 @@ TRI_vocbase_t* RocksDBEngine::openExistingDatabase(TRI_voc_tick_t id, TRI_ASSERT(!it.get("id").isNone()); - auto view = std::make_shared(vocbase.get(), it); + auto view = viewFactory(*vocbase, it, false); + + if (!view) { + auto const message = + "failed to instantiate view of type " + + dataSourceType.name(); + + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message.c_str()); + } StorageEngine::registerView(vocbase.get(), view); - view->spawnImplementation(creator, it, false); - view->getImplementation()->open(); + view->open(); } } catch (std::exception const& ex) { LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error while opening database: " diff --git a/arangod/V8Server/v8-views.cpp b/arangod/V8Server/v8-views.cpp index deb2973f82..fbf6ce0ca9 100644 --- a/arangod/V8Server/v8-views.cpp +++ b/arangod/V8Server/v8-views.cpp @@ -435,7 +435,7 @@ static void JS_PropertiesViewVocbase( VPackBuilder vpackProperties; vpackProperties.openObject(); - view->toVelocyPack(vpackProperties, true); + view->toVelocyPack(vpackProperties, true, false); vpackProperties.close(); // return the current parameter set diff --git a/arangod/VocBase/LogicalView.cpp b/arangod/VocBase/LogicalView.cpp index 37dea70fa0..f0b3c82bb6 100644 --- a/arangod/VocBase/LogicalView.cpp +++ b/arangod/VocBase/LogicalView.cpp @@ -26,7 +26,7 @@ #include "Basics/ReadLocker.h" #include "Basics/Result.h" #include "Basics/VelocyPackHelper.h" -#include "Basics/WriteLocker.h" +#include "Basics/Exceptions.h" #include "Cluster/ClusterInfo.h" #include "Cluster/ServerState.h" #include "StorageEngine/EngineSelectorFeature.h" @@ -38,27 +38,6 @@ using Helper = arangodb::basics::VelocyPackHelper; namespace { -TRI_voc_cid_t ReadId(VPackSlice info) { - if (!info.isObject()) { - // ERROR CASE - return 0; - } - - // Somehow the id is now propagated to dbservers - TRI_voc_cid_t id = Helper::extractIdValue(info); - - if (id == 0) { - if (ServerState::instance()->isDBServer()) { - id = ClusterInfo::instance()->uniqid(1); - } else if (ServerState::instance()->isCoordinator()) { - id = ClusterInfo::instance()->uniqid(1); - } else { - id = TRI_NewTickServer(); - } - } - return id; -} - TRI_voc_cid_t ReadPlanId(VPackSlice info, TRI_voc_cid_t vid) { if (!info.isObject()) { // ERROR CASE @@ -82,6 +61,31 @@ TRI_voc_cid_t ReadPlanId(VPackSlice info, TRI_voc_cid_t vid) { } // namespace +/*static*/ TRI_voc_cid_t LogicalView::readViewId(VPackSlice info) { + if (!info.isObject()) { + // ERROR CASE + return 0; + } + + // Somehow the id is now propagated to dbservers + TRI_voc_cid_t id = Helper::extractIdValue(info); + + if (id == 0) { + if (ServerState::instance()->isDBServer()) { + id = ClusterInfo::instance()->uniqid(1); + } else if (ServerState::instance()->isCoordinator()) { + id = ClusterInfo::instance()->uniqid(1); + } else { + id = TRI_NewTickServer(); + } + } + return id; +} + +// ----------------------------------------------------------------------------- +// --SECTION-- LogicalView +// ----------------------------------------------------------------------------- + /*static*/ LogicalDataSource::Category const& LogicalView::category() noexcept { static const Category category; @@ -98,7 +102,7 @@ LogicalView::LogicalView(TRI_vocbase_t* vocbase, VPackSlice const& info) arangodb::basics::VelocyPackHelper::getStringRef(info, "type", "") ), vocbase, - ReadId(info), + LogicalView::readViewId(info), ReadPlanId(info, 0), arangodb::basics::VelocyPackHelper::getStringValue(info, "name", ""), Helper::readBooleanValue(info, "deleted", false) @@ -111,7 +115,29 @@ LogicalView::LogicalView(TRI_vocbase_t* vocbase, VPackSlice const& info) TRI_UpdateTickServer(static_cast(id())); } -LogicalView::~LogicalView() { +/// @brief Persist the connected physical view +/// This should be called AFTER the view is successfully +/// created and only on Single/DBServer +void LogicalView::persistPhysicalView() { + // Coordinators are not allowed to have local views! + TRI_ASSERT(!ServerState::instance()->isCoordinator()); + + // We have not yet persisted this view + StorageEngine* engine = EngineSelectorFeature::ENGINE; + engine->createView(vocbase(), id(), this); +} + +// ----------------------------------------------------------------------------- +// --SECTION-- DBServerLogicalView +// ----------------------------------------------------------------------------- + +DBServerLogicalView::DBServerLogicalView( + TRI_vocbase_t* vocbase, + VPackSlice const& info +) : LogicalView(vocbase, info) { +} + +DBServerLogicalView::~DBServerLogicalView() { if (deleted()) { StorageEngine* engine = EngineSelectorFeature::ENGINE; TRI_ASSERT(engine); @@ -119,7 +145,14 @@ LogicalView::~LogicalView() { } } -Result LogicalView::rename(std::string&& newName, bool doSync) { +void DBServerLogicalView::drop() { + TRI_ASSERT(!ServerState::instance()->isCoordinator()); + StorageEngine* engine = EngineSelectorFeature::ENGINE; + TRI_ASSERT(engine); + engine->dropView(vocbase(), this); +} + +Result DBServerLogicalView::rename(std::string&& newName, bool doSync) { auto oldName = name(); try { @@ -144,22 +177,9 @@ Result LogicalView::rename(std::string&& newName, bool doSync) { return TRI_ERROR_NO_ERROR; } -void LogicalView::drop() { - deleted(true); - - if (getImplementation() != nullptr) { - getImplementation()->drop(); - } - - TRI_ASSERT(!ServerState::instance()->isCoordinator()); - StorageEngine* engine = EngineSelectorFeature::ENGINE; - TRI_ASSERT(engine); - engine->dropView(vocbase(), this); -} - -void LogicalView::toVelocyPack( - VPackBuilder& result, - bool includeProperties, +void DBServerLogicalView::toVelocyPack( + velocypack::Builder &result, + bool /*includeProperties*/, bool includeSystem ) const { // We write into an open object @@ -177,64 +197,31 @@ void LogicalView::toVelocyPack( // Cluster Specific result.add("planId", VPackValue(std::to_string(planId()))); - if (includeSystem) { - // storage engine related properties - StorageEngine* engine = EngineSelectorFeature::ENGINE; - TRI_ASSERT(engine ); - engine->getViewProperties(vocbase(), this, result); - } - } - - if (includeProperties && (getImplementation() != nullptr)) { - // implementation Information - result.add("properties", VPackValue(VPackValueType::Object)); - // note: includeSystem and forPersistence are not 100% synonymous, - // however, for our purposes this is an okay mapping; we only set - // includeSystem if we are persisting the properties - getImplementation()->getPropertiesVPack(result, includeSystem); - result.close(); - } - - TRI_ASSERT(result.isOpenObject()); // We leave the object open -} - -arangodb::Result LogicalView::updateProperties(VPackSlice const& slice, - bool partialUpdate, - bool doSync) { - WRITE_LOCKER(writeLocker, _lock); - - TRI_ASSERT(getImplementation() != nullptr); - - // the implementation may filter/change/react to the changes - arangodb::Result implResult = - getImplementation()->updateProperties(slice, partialUpdate, doSync); - - if (implResult.ok()) { - // after this call the properties are stored + // storage engine related properties StorageEngine* engine = EngineSelectorFeature::ENGINE; TRI_ASSERT(engine ); + engine->getViewProperties(vocbase(), this, result); + } +} + +arangodb::Result DBServerLogicalView::updateProperties( + VPackSlice const& /*slice*/, + bool /*partialUpdate*/, + bool doSync +) { + // after this call the properties are stored + StorageEngine* engine = EngineSelectorFeature::ENGINE; + TRI_ASSERT(engine); + + try { engine->changeView(vocbase(), id(), this, doSync); + } catch (arangodb::basics::Exception const& e) { + return { e.code() }; + } catch (...) { + return { TRI_ERROR_INTERNAL }; } - return implResult; -} - -/// @brief Persist the connected physical view -/// This should be called AFTER the view is successfully -/// created and only on Single/DBServer -void LogicalView::persistPhysicalView() { - // Coordinators are not allowed to have local views! - TRI_ASSERT(!ServerState::instance()->isCoordinator()); - - // We have not yet persisted this view - StorageEngine* engine = EngineSelectorFeature::ENGINE; - engine->createView(vocbase(), id(), this); -} - -void LogicalView::spawnImplementation( - ViewCreator creator, arangodb::velocypack::Slice const& parameters, - bool isNew) { - _implementation = creator(this, parameters.get("properties"), isNew); + return {}; } // ----------------------------------------------------------------------------- diff --git a/arangod/VocBase/LogicalView.h b/arangod/VocBase/LogicalView.h index 23990a4b42..1c98664554 100644 --- a/arangod/VocBase/LogicalView.h +++ b/arangod/VocBase/LogicalView.h @@ -26,9 +26,8 @@ #include "LogicalDataSource.h" #include "Basics/Common.h" -#include "Basics/ReadWriteLock.h" #include "Basics/Result.h" -#include "VocBase/ViewImplementation.h" +#include "Basics/ReadWriteLock.h" #include "VocBase/voc-types.h" #include @@ -37,72 +36,124 @@ namespace arangodb { namespace velocypack { class Slice; +class Builder; } -namespace aql { -class ExecutionPlan; -struct ExecutionContext; -} - -class PhysicalView; - -class LogicalView final: public LogicalDataSource { +//////////////////////////////////////////////////////////////////////////////// +/// @class LogicalView +//////////////////////////////////////////////////////////////////////////////// +class LogicalView : public LogicalDataSource { public: + typedef std::function CollectionVisitor; + ////////////////////////////////////////////////////////////////////////////// /// @brief the category representing a logical view ////////////////////////////////////////////////////////////////////////////// static Category const& category() noexcept; - LogicalView(TRI_vocbase_t* vocbase, velocypack::Slice const& definition); - - ~LogicalView() override; - ////////////////////////////////////////////////////////////////////////////// /// @brief invoke visitor on all collections that a view will return /// @return visitation was successful ////////////////////////////////////////////////////////////////////////////// - bool visitCollections( - std::function const& visitor - ) const { - return _implementation && _implementation->visitCollections(visitor); - } + virtual bool visitCollections(CollectionVisitor const& visitor) const = 0; - ViewImplementation* getImplementation() const { - return _implementation.get(); - } + ////////////////////////////////////////////////////////////////////////////// + /// @brief opens an existing view when the server is restarted + ////////////////////////////////////////////////////////////////////////////// + virtual void open() = 0; - virtual void drop() override; + ////////////////////////////////////////////////////////////////////////////// + /// @brief drop an existing view + ////////////////////////////////////////////////////////////////////////////// + virtual void drop() = 0; - virtual Result rename(std::string&& newName, bool doSync) override; + ////////////////////////////////////////////////////////////////////////////// + /// @brief renames an existing view + ////////////////////////////////////////////////////////////////////////////// + virtual Result rename( + std::string&& newName, + bool doSync + ) = 0; - void toVelocyPack( + ////////////////////////////////////////////////////////////////////////////// + /// @brief builds a VelocyPack representation of the node LogicalView + ////////////////////////////////////////////////////////////////////////////// + virtual void toVelocyPack( velocypack::Builder& result, - bool includeProperties = false, - bool includeSystem = false - ) const; + bool includeProperties, + bool includeSystem + ) const = 0; - arangodb::Result updateProperties( + ////////////////////////////////////////////////////////////////////////////// + /// @brief updates properties of an existing view + ////////////////////////////////////////////////////////////////////////////// + virtual arangodb::Result updateProperties( velocypack::Slice const& properties, bool partialUpdate, bool doSync - ); + ) = 0; + //FIXME remove /// @brief Persist the connected physical view. /// This should be called AFTER the view is successfully /// created and only on Sinlge/DBServer void persistPhysicalView(); - /// @brief Create implementation object using factory method - void spawnImplementation(ViewCreator creator, - arangodb::velocypack::Slice const& parameters, - bool isNew); + protected: + static TRI_voc_cid_t readViewId(velocypack::Slice slice); + + LogicalView(TRI_vocbase_t* vocbase, velocypack::Slice const& definition); private: friend struct ::TRI_vocbase_t; - std::unique_ptr _implementation; - mutable basics::ReadWriteLock _lock; // lock protecting the properties -}; + mutable basics::ReadWriteLock _lock; +}; // LogicalView + +////////////////////////////////////////////////////////////////////////////// +/// @brief typedef for a LogicalView factory function +/// This typedef is used when registering the creator function for any view +/// type. the creator function is called when a view is first created or +/// re-opened after a server restart. the VelocyPack Slice will contain all +/// information about the view's general and implementation-specific properties. +/// the isNew flag will be true if the view is first created, and false if a +/// view is re-opened on a server restart. +////////////////////////////////////////////////////////////////////////////// +typedef std::function( + TRI_vocbase_t& vocbase, // database + arangodb::velocypack::Slice const& properties, // view properties + bool isNew +)> ViewFactory; + +//////////////////////////////////////////////////////////////////////////////// +/// @class DBServerLogicalView +//////////////////////////////////////////////////////////////////////////////// +class DBServerLogicalView : public LogicalView { + public: + ~DBServerLogicalView() override; + + void drop() override; + + Result rename( + std::string&& newName, + bool doSync + ) override final; + + void toVelocyPack( + velocypack::Builder& result, + bool includeProperties, + bool includeSystem + ) const override; + + arangodb::Result updateProperties( + velocypack::Slice const& properties, + bool partialUpdate, + bool doSync + ) override; + + protected: + DBServerLogicalView(TRI_vocbase_t* vocbase, velocypack::Slice const& definition); +}; // LogicalView } // namespace arangodb diff --git a/arangod/VocBase/ViewImplementation.h b/arangod/VocBase/ViewImplementation.h deleted file mode 100644 index 03e8f0a245..0000000000 --- a/arangod/VocBase/ViewImplementation.h +++ /dev/null @@ -1,115 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// DISCLAIMER -/// -/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany -/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany -/// -/// Licensed under the Apache License, Version 2.0 (the "License"); -/// you may not use this file except in compliance with the License. -/// You may obtain a copy of the License at -/// -/// http://www.apache.org/licenses/LICENSE-2.0 -/// -/// Unless required by applicable law or agreed to in writing, software -/// distributed under the License is distributed on an "AS IS" BASIS, -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -/// See the License for the specific language governing permissions and -/// limitations under the License. -/// -/// Copyright holder is ArangoDB GmbH, Cologne, Germany -/// -/// @author Jan Steemann -//////////////////////////////////////////////////////////////////////////////// - -#ifndef ARANGOD_VOCBASE_VIEW_IMPLEMENTATION_H -#define ARANGOD_VOCBASE_VIEW_IMPLEMENTATION_H 1 - -#include "Basics/Common.h" -#include "VocBase/voc-types.h" - -#include -#include - -namespace arangodb { -class LogicalView; -class PhysicalView; -class Result; -class ViewIterator; - -namespace aql { - -class Ast; -struct AstNode; -class SortCondition; -class ExecutionPlan; -class ExpressionContext; -struct Variable; - -}; - -namespace transaction { - -class Methods; - -}; - -/// @brief interface for view implementation -class ViewImplementation { - protected: - ViewImplementation(LogicalView* logical, - arangodb::velocypack::Slice const& info) - : _logicalView(logical) {} - - public: - virtual ~ViewImplementation() = default; - - /// @brief called when a view's properties are updated - virtual arangodb::Result updateProperties( - arangodb::velocypack::Slice const& slice, bool partialUpdate, - bool doSync) = 0; - - ////////////////////////////////////////////////////////////////////////////// - /// @brief invoke visitor on all collections that a view will return - /// @return visitation was successful - ////////////////////////////////////////////////////////////////////////////// - virtual bool visitCollections( - std::function const& visitor - ) const = 0; - - ////////////////////////////////////////////////////////////////////////////// - /// @brief called when a view's properties are materialized into - /// the VelocyPack Builder passed into the method. the implementation - /// is supposed to fill in all its specific properties. The Builder - /// points into an open VelocyPack object. The method is supposed to - /// add all its own property attributes with their values, and must - /// not close the Builder - ////////////////////////////////////////////////////////////////////////////// - virtual void getPropertiesVPack(velocypack::Builder&, - bool forPersistence) const = 0; - - /// @brief opens an existing view when the server is restarted - virtual void open() = 0; - - /// @brief drops an existing view - virtual void drop() = 0; - - protected: - LogicalView* _logicalView; -}; - -////////////////////////////////////////////////////////////////////////////// -/// @brief typedef for a ViewImplementation creator function -/// This typedef is used when registering the creator function for any view -/// type. the creator function is called when a view is first created or -/// re-opened after a server restart. the VelocyPack Slice will contain all -/// information about the view's general and implementation-specific properties. -/// the isNew flag will be true if the view is first created, and false if a -/// view is re-opened on a server restart. -////////////////////////////////////////////////////////////////////////////// -typedef std::function( - LogicalView*, arangodb::velocypack::Slice const&, bool isNew)> - ViewCreator; - -} // namespace arangodb - -#endif \ No newline at end of file diff --git a/arangod/VocBase/vocbase.cpp b/arangod/VocBase/vocbase.cpp index 72120766a5..f78f6a245f 100644 --- a/arangod/VocBase/vocbase.cpp +++ b/arangod/VocBase/vocbase.cpp @@ -64,7 +64,6 @@ #include "V8Server/v8-user-structures.h" #include "VocBase/LogicalCollection.h" #include "VocBase/LogicalView.h" -#include "VocBase/ViewImplementation.h" #include "VocBase/ticks.h" #include @@ -1567,31 +1566,42 @@ std::shared_ptr TRI_vocbase_t::createViewWorker( THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_ILLEGAL_NAME); } - auto type = + auto const type = arangodb::basics::VelocyPackHelper::getStringRef(parameters, "type", ""); - ViewTypesFeature* viewTypesFeature = + auto const* viewTypes = application_features::ApplicationServer::getFeature( "ViewTypes"); - if (!viewTypesFeature) { + if (!viewTypes) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_INTERNAL, std::string("failed to find feature '") + arangodb::ViewTypesFeature::name() + "'" ); } - auto& dataSourceType = arangodb::LogicalDataSource::Type::emplace(type); - auto& creator = viewTypesFeature->factory(dataSourceType); + auto const& dataSourceType = arangodb::LogicalDataSource::Type::emplace(type); - if (!creator) { + auto const& viewFactory = viewTypes->factory(dataSourceType); + + if (!viewFactory) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "no handler found for view type" ); } + // FIXME first check for existence??? + // Try to create a new view. This is not registered yet - auto view = std::make_shared(this, parameters); + auto view = viewFactory(*this, parameters, true); + + if (!view) { + auto const message = + "failed to instantiate view of type " + + dataSourceType.name(); + + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, message.c_str()); + } RECURSIVE_WRITE_LOCKER(_dataSourceLock, _dataSourceLockWriteOwner); @@ -1608,18 +1618,11 @@ std::shared_ptr TRI_vocbase_t::createViewWorker( // id might have been assigned id = view->id(); - // now let's actually create the backing implementation - view->spawnImplementation(creator, parameters, true); - if (view->getImplementation() == nullptr) { - THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "could not spawn view " - "implementation"); - } - // Let's try to persist it. view->persistPhysicalView(); // And lets open it. - view->getImplementation()->open(); + view->open(); events::CreateView(name, TRI_ERROR_NO_ERROR); return view; diff --git a/arangod/VocBase/vocbase.h b/arangod/VocBase/vocbase.h index 02f9a4e890..6e51b89c83 100644 --- a/arangod/VocBase/vocbase.h +++ b/arangod/VocBase/vocbase.h @@ -31,7 +31,6 @@ #include "Basics/ReadWriteLock.h" #include "Basics/StringUtils.h" #include "Basics/voc-errors.h" -#include "VocBase/ViewImplementation.h" #include "VocBase/voc-types.h" #include "velocypack/Builder.h" @@ -455,4 +454,4 @@ void TRI_SanitizeObject(arangodb::velocypack::Slice const slice, void TRI_SanitizeObjectWithEdges(arangodb::velocypack::Slice const slice, arangodb::velocypack::Builder& builder); -#endif \ No newline at end of file +#endif diff --git a/tests/IResearch/ExpressionFilter-test.cpp b/tests/IResearch/ExpressionFilter-test.cpp index 10176c12d0..4b16702109 100644 --- a/tests/IResearch/ExpressionFilter-test.cpp +++ b/tests/IResearch/ExpressionFilter-test.cpp @@ -387,9 +387,9 @@ TEST_CASE("IResearchExpressionFilterTest", "[iresearch][iresearch-expression-fil }"); // add view - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); } diff --git a/tests/IResearch/IResearchIndex-test.cpp b/tests/IResearch/IResearchIndex-test.cpp index 20259edb2a..20646e7749 100644 --- a/tests/IResearch/IResearchIndex-test.cpp +++ b/tests/IResearch/IResearchIndex-test.cpp @@ -227,9 +227,7 @@ SECTION("test_analyzer") { REQUIRE((nullptr != collection0)); auto* collection1 = vocbase.createCollection(createCollection1->slice()); REQUIRE((nullptr != collection1)); - auto logicalView = vocbase.createView(createView->slice(), 0); - REQUIRE((false == !logicalView)); - auto* viewImpl = logicalView->getImplementation(); + auto viewImpl = vocbase.createView(createView->slice(), 0); REQUIRE((nullptr != viewImpl)); // populate collections @@ -346,9 +344,7 @@ SECTION("test_async_index") { REQUIRE((nullptr != collection0)); auto* collection1 = vocbase.createCollection(createCollection1->slice()); REQUIRE((nullptr != collection1)); - auto logicalView = vocbase.createView(createView->slice(), 0); - REQUIRE((false == !logicalView)); - auto* viewImpl = logicalView->getImplementation(); + auto viewImpl = vocbase.createView(createView->slice(), 0); REQUIRE((nullptr != viewImpl)); // link collections with view @@ -547,9 +543,7 @@ SECTION("test_fields") { REQUIRE((nullptr != collection0)); auto* collection1 = vocbase.createCollection(createCollection1->slice()); REQUIRE((nullptr != collection1)); - auto logicalView = vocbase.createView(createView->slice(), 0); - REQUIRE((false == !logicalView)); - auto* viewImpl = logicalView->getImplementation(); + auto viewImpl = vocbase.createView(createView->slice(), 0); REQUIRE((nullptr != viewImpl)); // populate collections @@ -641,4 +635,4 @@ SECTION("test_fields") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchLink-test.cpp b/tests/IResearch/IResearchLink-test.cpp index 94063f3a39..80109b6e6e 100644 --- a/tests/IResearch/IResearchLink-test.cpp +++ b/tests/IResearch/IResearchLink-test.cpp @@ -325,9 +325,9 @@ SECTION("test_write") { }"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); REQUIRE((false == !view)); view->open(); auto* flush = arangodb::iresearch::getFeature("Flush"); diff --git a/tests/IResearch/IResearchQueryAggregate-test.cpp b/tests/IResearch/IResearchQueryAggregate-test.cpp index 936cc04124..38a94e2bab 100644 --- a/tests/IResearch/IResearchQueryAggregate-test.cpp +++ b/tests/IResearch/IResearchQueryAggregate-test.cpp @@ -251,7 +251,7 @@ TEST_CASE("IResearchQueryTestAggregate", "[iresearch][iresearch-query]") { REQUIRE((false == !logicalView)); view = logicalView.get(); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -417,4 +417,4 @@ TEST_CASE("IResearchQueryTestAggregate", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryAnd-test.cpp b/tests/IResearch/IResearchQueryAnd-test.cpp index e548aca960..8df416d948 100644 --- a/tests/IResearch/IResearchQueryAnd-test.cpp +++ b/tests/IResearch/IResearchQueryAnd-test.cpp @@ -251,7 +251,7 @@ TEST_CASE("IResearchQueryTestAnd", "[iresearch][iresearch-query]") { REQUIRE((false == !logicalView)); view = logicalView.get(); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -669,4 +669,4 @@ TEST_CASE("IResearchQueryTestAnd", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryBooleanTerm-test.cpp b/tests/IResearch/IResearchQueryBooleanTerm-test.cpp index f97e74304f..f56e5663d0 100644 --- a/tests/IResearch/IResearchQueryBooleanTerm-test.cpp +++ b/tests/IResearch/IResearchQueryBooleanTerm-test.cpp @@ -258,7 +258,7 @@ TEST_CASE("IResearchQueryTestBooleanTerm", "[iresearch][iresearch-query]") { view = logicalView.get(); REQUIRE(nullptr != view); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -2429,4 +2429,4 @@ TEST_CASE("IResearchQueryTestBooleanTerm", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryComplexBoolean-test.cpp b/tests/IResearch/IResearchQueryComplexBoolean-test.cpp index b6a8a30297..b1fe834856 100644 --- a/tests/IResearch/IResearchQueryComplexBoolean-test.cpp +++ b/tests/IResearch/IResearchQueryComplexBoolean-test.cpp @@ -251,7 +251,7 @@ TEST_CASE("IResearchQueryTestComplexBoolean", "[iresearch][iresearch-query]") { REQUIRE((false == !logicalView)); view = logicalView.get(); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -477,4 +477,4 @@ TEST_CASE("IResearchQueryTestComplexBoolean", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryExists-test.cpp b/tests/IResearch/IResearchQueryExists-test.cpp index 2d254bb20c..771eb72799 100644 --- a/tests/IResearch/IResearchQueryExists-test.cpp +++ b/tests/IResearch/IResearchQueryExists-test.cpp @@ -259,7 +259,7 @@ TEST_CASE("IResearchQueryTestExists", "[iresearch][iresearch-query]") { REQUIRE((false == !logicalView)); view = logicalView.get(); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( diff --git a/tests/IResearch/IResearchQueryIn-test.cpp b/tests/IResearch/IResearchQueryIn-test.cpp index 6516ecf5a9..7e57636cae 100644 --- a/tests/IResearch/IResearchQueryIn-test.cpp +++ b/tests/IResearch/IResearchQueryIn-test.cpp @@ -250,7 +250,7 @@ TEST_CASE("IResearchQueryTestIn", "[iresearch][iresearch-query]") { REQUIRE((false == !logicalView)); view = logicalView.get(); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -523,4 +523,4 @@ TEST_CASE("IResearchQueryTestIn", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryJoin-test.cpp b/tests/IResearch/IResearchQueryJoin-test.cpp index fc03d0352b..1737ee3d1a 100644 --- a/tests/IResearch/IResearchQueryJoin-test.cpp +++ b/tests/IResearch/IResearchQueryJoin-test.cpp @@ -340,9 +340,9 @@ TEST_CASE("IResearchQueryTestJoinDuplicateDataSource", "[iresearch][iresearch-qu } // add view - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); // add logical collection with the same name as view @@ -365,7 +365,7 @@ TEST_CASE("IResearchQueryTestJoinDuplicateDataSource", "[iresearch][iresearch-qu arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -547,9 +547,9 @@ TEST_CASE("IResearchQueryTestJoin", "[iresearch][iresearch-query]") { } // add view - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); // add link to collection @@ -565,7 +565,7 @@ TEST_CASE("IResearchQueryTestJoin", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); diff --git a/tests/IResearch/IResearchQueryNullTerm-test.cpp b/tests/IResearch/IResearchQueryNullTerm-test.cpp index ee7f982d04..8f5e704b79 100644 --- a/tests/IResearch/IResearchQueryNullTerm-test.cpp +++ b/tests/IResearch/IResearchQueryNullTerm-test.cpp @@ -257,7 +257,7 @@ TEST_CASE("IResearchQueryTestNullTerm", "[iresearch][iresearch-query]") { view = logicalView.get(); REQUIRE(nullptr != view); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -1452,4 +1452,4 @@ TEST_CASE("IResearchQueryTestNullTerm", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryNumericTerm-test.cpp b/tests/IResearch/IResearchQueryNumericTerm-test.cpp index a0f4dd3c5b..50255c676e 100644 --- a/tests/IResearch/IResearchQueryNumericTerm-test.cpp +++ b/tests/IResearch/IResearchQueryNumericTerm-test.cpp @@ -210,9 +210,9 @@ TEST_CASE("IResearchQueryTestNumericTerm", "[iresearch][iresearch-query]") { } // add view - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); // add link to collection @@ -228,7 +228,7 @@ TEST_CASE("IResearchQueryTestNumericTerm", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -3136,4 +3136,4 @@ TEST_CASE("IResearchQueryTestNumericTerm", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryOr-test.cpp b/tests/IResearch/IResearchQueryOr-test.cpp index cbba31a3e8..5ba6a2cda4 100644 --- a/tests/IResearch/IResearchQueryOr-test.cpp +++ b/tests/IResearch/IResearchQueryOr-test.cpp @@ -201,9 +201,9 @@ TEST_CASE("IResearchQueryTestOr", "[iresearch][iresearch-query]") { } // add view - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); // add link to collection @@ -219,7 +219,7 @@ TEST_CASE("IResearchQueryTestOr", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -671,4 +671,4 @@ TEST_CASE("IResearchQueryTestOr", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryPhrase-test.cpp b/tests/IResearch/IResearchQueryPhrase-test.cpp index c5cbd29706..f0817be2c9 100644 --- a/tests/IResearch/IResearchQueryPhrase-test.cpp +++ b/tests/IResearch/IResearchQueryPhrase-test.cpp @@ -251,7 +251,7 @@ TEST_CASE("IResearchQueryTestPhrase", "[iresearch][iresearch-query]") { REQUIRE((false == !logicalView)); view = logicalView.get(); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -912,4 +912,4 @@ TEST_CASE("IResearchQueryTestPhrase", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQuerySelectAll-test.cpp b/tests/IResearch/IResearchQuerySelectAll-test.cpp index 2c1d1d89b5..ced874bbb3 100644 --- a/tests/IResearch/IResearchQuerySelectAll-test.cpp +++ b/tests/IResearch/IResearchQuerySelectAll-test.cpp @@ -201,9 +201,9 @@ TEST_CASE("IResearchQueryTestSelectAll", "[iresearch][iresearch-query]") { } // add view - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); // add link to collection @@ -219,7 +219,7 @@ TEST_CASE("IResearchQueryTestSelectAll", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -507,4 +507,4 @@ TEST_CASE("IResearchQueryTestSelectAll", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryStartsWith-test.cpp b/tests/IResearch/IResearchQueryStartsWith-test.cpp index 1124b44ca3..a58b85c6ec 100644 --- a/tests/IResearch/IResearchQueryStartsWith-test.cpp +++ b/tests/IResearch/IResearchQueryStartsWith-test.cpp @@ -201,9 +201,9 @@ TEST_CASE("IResearchQueryTestStartsWith", "[iresearch][iresearch-query]") { } // add view - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); // add link to collection @@ -219,7 +219,7 @@ TEST_CASE("IResearchQueryTestStartsWith", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -417,4 +417,4 @@ TEST_CASE("IResearchQueryTestStartsWith", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryStringTerm-test.cpp b/tests/IResearch/IResearchQueryStringTerm-test.cpp index 8af319364f..feed9adeb8 100644 --- a/tests/IResearch/IResearchQueryStringTerm-test.cpp +++ b/tests/IResearch/IResearchQueryStringTerm-test.cpp @@ -238,9 +238,9 @@ TEST_CASE("IResearchQueryTestStringTerm", "[iresearch][iresearch-query]") { } // add view - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); // add link to collection @@ -256,7 +256,7 @@ TEST_CASE("IResearchQueryTestStringTerm", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2764,4 +2764,4 @@ TEST_CASE("IResearchQueryTestStringTerm", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryTokens-test.cpp b/tests/IResearch/IResearchQueryTokens-test.cpp index 7f5d26b751..dc6779641d 100644 --- a/tests/IResearch/IResearchQueryTokens-test.cpp +++ b/tests/IResearch/IResearchQueryTokens-test.cpp @@ -258,7 +258,7 @@ TEST_CASE("IResearchQueryTestTokens", "[iresearch][iresearch-query]") { REQUIRE((false == !logicalView)); view = logicalView.get(); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -419,4 +419,4 @@ TEST_CASE("IResearchQueryTestTokens", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryTraversal-test.cpp b/tests/IResearch/IResearchQueryTraversal-test.cpp index 51fd414fdb..9090a92f42 100644 --- a/tests/IResearch/IResearchQueryTraversal-test.cpp +++ b/tests/IResearch/IResearchQueryTraversal-test.cpp @@ -292,7 +292,7 @@ TEST_CASE("IResearchQueryTestTraversal", "[iresearch][iresearch-query]") { REQUIRE((false == !logicalView)); view = logicalView.get(); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -376,4 +376,4 @@ TEST_CASE("IResearchQueryTestTraversal", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchQueryValue-test.cpp b/tests/IResearch/IResearchQueryValue-test.cpp index 4e2952fc1f..b61dca8e66 100644 --- a/tests/IResearch/IResearchQueryValue-test.cpp +++ b/tests/IResearch/IResearchQueryValue-test.cpp @@ -251,7 +251,7 @@ TEST_CASE("IResearchQueryTestValue", "[iresearch][iresearch-query]") { REQUIRE((false == !logicalView)); view = logicalView.get(); - auto* impl = dynamic_cast(view->getImplementation()); + auto* impl = dynamic_cast(view); REQUIRE((false == !impl)); auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -1000,4 +1000,4 @@ TEST_CASE("IResearchQueryTestValue", "[iresearch][iresearch-query]") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchView-test.cpp b/tests/IResearch/IResearchView-test.cpp index 05ecadfa33..7d7996755f 100644 --- a/tests/IResearch/IResearchView-test.cpp +++ b/tests/IResearch/IResearchView-test.cpp @@ -230,113 +230,114 @@ SECTION("test_type") { } SECTION("test_defaults") { - auto namedJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\" }"); - auto json = arangodb::velocypack::Parser::fromJson("{}"); - - // existing view definition - { - auto view = arangodb::iresearch::IResearchView::make(nullptr, json->slice(), false); - CHECK((true == !view)); - } + auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\" }"); // existing view definition with LogicalView (for persistence) { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(&vocbase, namedJson->slice()); - auto view = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); - CHECK((false == !view)); + auto view = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false); + CHECK(nullptr != view); arangodb::iresearch::IResearchViewMeta expectedMeta; arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, true); + view->toVelocyPack(builder, true, true); builder.close(); auto slice = builder.slice(); arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((5U == slice.length())); - CHECK((!slice.hasKey("links"))); // for persistence so no links - CHECK((meta.init(slice, error) && expectedMeta == meta)); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(false == slice.get("deleted").getBool()); + CHECK(6 == slice.length()); + + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((5U == propSlice.length())); + CHECK((!propSlice.hasKey("links"))); // for persistence so no links + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); } // existing view definition with LogicalView { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(&vocbase, namedJson->slice()); - auto view = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); + auto view = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false); CHECK((false == !view)); arangodb::iresearch::IResearchViewMeta expectedMeta; arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((slice.hasKey("links"))); - CHECK((meta.init(slice, error) && expectedMeta == meta)); - } + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + CHECK(4 == slice.length()); - // new view definition - { - auto view = arangodb::iresearch::IResearchView::make(nullptr, json->slice(), true); - CHECK((true == !view)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((propSlice.hasKey("links"))); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); } // new view definition with LogicalView (for persistence) { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(&vocbase, namedJson->slice()); - auto view = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), true); + auto view = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true); CHECK((false == !view)); arangodb::iresearch::IResearchViewMeta expectedMeta; arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, true); + view->toVelocyPack(builder, false, true); builder.close(); auto slice = builder.slice(); arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((5U == slice.length())); - CHECK((!slice.hasKey("links"))); // for persistence so no links - CHECK((meta.init(slice, error) && expectedMeta == meta)); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(false == slice.get("deleted").getBool()); + CHECK(5 == slice.length()); + + auto propSlice = slice.get("properties"); + CHECK(propSlice.isNone()); } // new view definition with LogicalView { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(&vocbase, namedJson->slice()); - auto view = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), true); + auto view = arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true); CHECK((false == !view)); arangodb::iresearch::IResearchViewMeta expectedMeta; arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); - - auto tmpSlice = slice.get("links"); - CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length())); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); + CHECK(slice.get("properties").isNone()); + CHECK(3 == slice.length()); } // new view definition with links (not supported for link creation) @@ -351,12 +352,8 @@ SECTION("test_defaults") { CHECK((true == logicalCollection->getIndexes().empty())); auto logicalView = vocbase.createView(viewJson->slice(), 0); REQUIRE((false == !logicalView)); - auto* view = logicalView->getImplementation(); - REQUIRE((false == !view)); - auto* viewImpl = dynamic_cast(view); - REQUIRE((nullptr != viewImpl)); std::set cids; - viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); + logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); CHECK((0 == cids.size())); CHECK((true == logicalCollection->getIndexes().empty())); } @@ -381,7 +378,7 @@ SECTION("test_drop") { CHECK((false == TRI_IsDirectory(dataPath.c_str()))); // createView(...) will call open() auto logicalView = vocbase.createView(json->slice(), 0); REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = &logicalView; REQUIRE((false == !view)); CHECK((true == logicalCollection->getIndexes().empty())); @@ -412,7 +409,7 @@ SECTION("test_drop_with_link") { CHECK((false == TRI_IsDirectory(dataPath.c_str()))); // createView(...) will call open() auto logicalView = vocbase.createView(json->slice(), 0); REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = &logicalView; REQUIRE((false == !view)); CHECK((true == logicalCollection->getIndexes().empty())); @@ -440,11 +437,10 @@ SECTION("test_drop_cid") { { auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\" }"); Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(nullptr, json->slice()); - auto viewImpl = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); - CHECK((false == !viewImpl)); - auto* view = dynamic_cast(viewImpl.get()); - CHECK((nullptr != view)); + auto view = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false) + ); + CHECK((false == !view)); // fill with test data { @@ -486,11 +482,10 @@ SECTION("test_drop_cid") { { auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"collections\": [ 42 ] }"); Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(nullptr, json->slice()); - auto viewImpl = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); - CHECK((false == !viewImpl)); - auto* view = dynamic_cast(viewImpl.get()); - CHECK((nullptr != view)); + auto view = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false) + ); + CHECK((false == !view)); // fill with test data { @@ -531,8 +526,7 @@ SECTION("test_drop_cid") { SECTION("test_insert") { static std::vector const EMPTY; - auto json = arangodb::velocypack::Parser::fromJson("{}"); - auto namedJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\" }"); + auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\":\"arangosearch\" }"); arangodb::aql::AstNode noop(arangodb::aql::AstNodeType::NODE_TYPE_FILTER); arangodb::aql::AstNode noopChild(true, arangodb::aql::AstNodeValueType::VALUE_TYPE_BOOL); // all @@ -544,11 +538,10 @@ SECTION("test_insert") { StorageEngineMock::inRecoveryResult = true; auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(nullptr, namedJson->slice()); - auto viewImpl = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); - CHECK((false == !viewImpl)); - auto* view = dynamic_cast(viewImpl.get()); - CHECK((nullptr != view)); + auto view = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false) + ); + CHECK((false == !view)); view->open(); { @@ -580,11 +573,10 @@ SECTION("test_insert") { StorageEngineMock::inRecoveryResult = true; auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(nullptr, namedJson->slice()); - auto viewImpl = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); - CHECK((false == !viewImpl)); - auto* view = dynamic_cast(viewImpl.get()); - CHECK((nullptr != view)); + auto view = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false) + ); + CHECK((false == !view)); view->open(); { @@ -616,11 +608,10 @@ SECTION("test_insert") { { StorageEngineMock::inRecoveryResult = false; Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(nullptr, namedJson->slice()); - auto viewImpl = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); - CHECK((false == !viewImpl)); - auto* view = dynamic_cast(viewImpl.get()); - CHECK((nullptr != view)); + auto view = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false) + ); + CHECK((false == !view)); // validate cid count { @@ -679,11 +670,12 @@ SECTION("test_insert") { { StorageEngineMock::inRecoveryResult = false; Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(nullptr, namedJson->slice()); - auto viewImpl = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); - CHECK((false == !viewImpl)); - auto* view = dynamic_cast(viewImpl.get()); - CHECK((nullptr != view)); + + auto view = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false) + ); + CHECK((false == !view)); + CHECK(view->category() == arangodb::LogicalView::category()); { auto docJson = arangodb::velocypack::Parser::fromJson("{\"abc\": \"def\"}"); @@ -713,11 +705,10 @@ SECTION("test_insert") { { StorageEngineMock::inRecoveryResult = false; Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(nullptr, namedJson->slice()); - auto viewImpl = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); - CHECK((false == !viewImpl)); - auto* view = dynamic_cast(viewImpl.get()); - CHECK((nullptr != view)); + auto view = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false) + ); + CHECK((false == !view)); { auto docJson = arangodb::velocypack::Parser::fromJson("{\"abc\": \"def\"}"); @@ -748,11 +739,10 @@ SECTION("test_insert") { { StorageEngineMock::inRecoveryResult = false; Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(nullptr, namedJson->slice()); - auto viewImpl = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); - CHECK((false == !viewImpl)); - auto* view = dynamic_cast(viewImpl.get()); - CHECK((nullptr != view)); + auto view = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false) + ); + CHECK((false == !view)); { auto docJson = arangodb::velocypack::Parser::fromJson("{\"abc\": \"def\"}"); @@ -788,12 +778,10 @@ SECTION("test_link") { // drop invalid collection { TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = logicalView->getImplementation(); - REQUIRE((false == !view)); - auto* viewImpl = dynamic_cast(view); - REQUIRE((nullptr != viewImpl)); + auto viewImpl = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); + REQUIRE((false == !viewImpl)); { std::set cids; @@ -814,12 +802,10 @@ SECTION("test_link") { TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); CHECK((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = logicalView->getImplementation(); - REQUIRE((false == !view)); - auto* viewImpl = dynamic_cast(view); - REQUIRE((nullptr != viewImpl)); + auto viewImpl = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); + REQUIRE((false == !viewImpl)); { std::set cids; @@ -840,17 +826,15 @@ SECTION("test_link") { TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); CHECK((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = logicalView->getImplementation(); - REQUIRE((false == !view)); - auto* viewImpl = dynamic_cast(view); - REQUIRE((nullptr != viewImpl)); + auto viewImpl = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); + REQUIRE((false == !viewImpl)); auto links = arangodb::velocypack::Parser::fromJson("{ \ \"links\": { \"testCollection\": {} } \ }"); - CHECK((true == logicalView->updateProperties(links->slice(), true, false).ok())); + CHECK((true == viewImpl->updateProperties(links->slice(), true, false).ok())); { std::set cids; @@ -870,51 +854,47 @@ SECTION("test_link") { // drop invalid collection + recreate { - TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(viewJson->slice(), 0); + Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); + auto logicalView = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); REQUIRE((false == !logicalView)); - auto* view = logicalView->getImplementation(); - REQUIRE((false == !view)); - auto* viewImpl = dynamic_cast(view); - REQUIRE((nullptr != viewImpl)); { std::set cids; - viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); + logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); CHECK((0 == cids.size())); } { - CHECK((false == viewImpl->link(100, arangodb::iresearch::emptyObjectSlice()).ok())); + CHECK((false == logicalView->link(100, arangodb::iresearch::emptyObjectSlice()).ok())); std::set cids; - viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); + logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); CHECK((0 == cids.size())); } } // drop non-existing + recreate { - TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); + Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); CHECK((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(viewJson->slice(), 0); + auto logicalView = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); REQUIRE((false == !logicalView)); - auto* view = logicalView->getImplementation(); - REQUIRE((false == !view)); - auto* viewImpl = dynamic_cast(view); - REQUIRE((nullptr != viewImpl)); { std::set cids; - viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); + logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); CHECK((0 == cids.size())); CHECK((true == logicalCollection->getIndexes().empty())); } { - CHECK((true == viewImpl->link(logicalCollection->id(), arangodb::iresearch::emptyObjectSlice()).ok())); + CHECK((true == logicalView->link(logicalCollection->id(), arangodb::iresearch::emptyObjectSlice()).ok())); std::set cids; - viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); + logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); std::unordered_set expected = { 100 }; for (auto& cid: expected) { @@ -928,15 +908,13 @@ SECTION("test_link") { // drop existing + recreate { - TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); + Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); CHECK((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(viewJson->slice(), 0); + auto logicalView = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); REQUIRE((false == !logicalView)); - auto* view = logicalView->getImplementation(); - REQUIRE((false == !view)); - auto* viewImpl = dynamic_cast(view); - REQUIRE((nullptr != viewImpl)); auto links = arangodb::velocypack::Parser::fromJson("{ \ \"links\": { \"testCollection\": { \"includeAllFields\": true } } \ @@ -945,7 +923,7 @@ SECTION("test_link") { { std::set cids; - viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); + logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); CHECK((1 == cids.size())); CHECK((1 == logicalCollection->getIndexes().size())); auto link = logicalCollection->getIndexes()[0]->toVelocyPack(true, false); @@ -955,9 +933,9 @@ SECTION("test_link") { } { - CHECK((true == viewImpl->link(logicalCollection->id(), arangodb::iresearch::emptyObjectSlice()).ok())); + CHECK((true == logicalView->link(logicalCollection->id(), arangodb::iresearch::emptyObjectSlice()).ok())); std::set cids; - viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); + logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); std::unordered_set expected = { 100 }; for (auto& cid: expected) { @@ -975,15 +953,13 @@ SECTION("test_link") { // drop existing + recreate invalid { - TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); + Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); CHECK((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(viewJson->slice(), 0); + auto logicalView = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); REQUIRE((false == !logicalView)); - auto* view = logicalView->getImplementation(); - REQUIRE((false == !view)); - auto* viewImpl = dynamic_cast(view); - REQUIRE((nullptr != viewImpl)); auto links = arangodb::velocypack::Parser::fromJson("{ \ \"links\": { \"testCollection\": { \"includeAllFields\": true } } \ @@ -992,7 +968,7 @@ SECTION("test_link") { { std::set cids; - viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); + logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); CHECK((1 == cids.size())); CHECK((1 == logicalCollection->getIndexes().size())); auto link = logicalCollection->getIndexes()[0]->toVelocyPack(true, false); @@ -1007,9 +983,9 @@ SECTION("test_link") { builder.add("includeAllFields", arangodb::velocypack::Value("abc")); builder.close(); auto slice = builder.slice(); - CHECK((false == viewImpl->link(logicalCollection->id(), slice).ok())); + CHECK((false == logicalView->link(logicalCollection->id(), slice).ok())); std::set cids; - viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); + logicalView->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); std::unordered_set expected = { 100 }; for (auto& cid: expected) { @@ -1029,13 +1005,12 @@ SECTION("test_link") { SECTION("test_open") { // default data path { + Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); std::string dataPath = (((irs::utf8_path()/=s.testFilesystemPath)/=std::string("databases"))/=std::string("arangosearch-123")).utf8(); auto namedJson = arangodb::velocypack::Parser::fromJson("{ \"id\": 123, \"name\": \"testView\", \"type\": \"testType\" }"); - auto json = arangodb::velocypack::Parser::fromJson("{}"); CHECK((false == TRI_IsDirectory(dataPath.c_str()))); - arangodb::LogicalView logicalView(nullptr, namedJson->slice()); - auto view = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); + auto view = arangodb::iresearch::IResearchView::make(vocbase, namedJson->slice(), false); CHECK((false == !view)); CHECK((false == TRI_IsDirectory(dataPath.c_str()))); view->open(); @@ -1057,9 +1032,9 @@ SECTION("test_query") { // no filter/order provided, means "RETURN *" { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); TrxStatePtr state(s.engine.createTransactionState(nullptr, arangodb::transaction::Options())); @@ -1070,9 +1045,9 @@ SECTION("test_query") { // ordered iterator { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(createJson->slice(), 0); - CHECK((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); CHECK((false == !view)); // fill with test data @@ -1109,11 +1084,11 @@ SECTION("test_query") { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); std::vector collections{ logicalCollection->name() }; - auto logicalView = vocbase.createView(createJson->slice(), 0); - CHECK((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); CHECK((false == !view)); - arangodb::Result res = logicalView->updateProperties(links->slice(), true, false); + arangodb::Result res = view->updateProperties(links->slice(), true, false); CHECK(true == res.ok()); CHECK((false == logicalCollection->getIndexes().empty())); @@ -1178,11 +1153,11 @@ SECTION("test_query") { REQUIRE(feature); Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); - auto logicalView = vocbase.createView(viewCreateJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(viewCreateJson->slice(), 0) + ); REQUIRE((false == !view)); - arangodb::Result res = logicalView->updateProperties(viewUpdateJson->slice(), true, false); + arangodb::Result res = view->updateProperties(viewUpdateJson->slice(), true, false); REQUIRE(true == res.ok()); // start flush thread @@ -1239,9 +1214,9 @@ SECTION("test_register_link") { { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); - auto logicalView = vocbase.createView(viewJson0->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(viewJson0->slice(), 0) + ); REQUIRE((false == !view)); { @@ -1264,9 +1239,9 @@ SECTION("test_register_link") { { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); - auto logicalView = vocbase.createView(viewJson0->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(viewJson0->slice(), 0) + ); REQUIRE((false == !view)); { @@ -1304,9 +1279,9 @@ SECTION("test_register_link") { { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); - auto logicalView = vocbase.createView(viewJson1->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(viewJson1->slice(), 0) + ); REQUIRE((false == !view)); { @@ -1361,9 +1336,9 @@ SECTION("test_unregister_link") { { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); REQUIRE((false == !view)); // add a document to the view @@ -1385,7 +1360,7 @@ SECTION("test_unregister_link") { \"links\": { \"testCollection\": {} } \ }"); - arangodb::Result res = logicalView->updateProperties(links->slice(), true, false); + arangodb::Result res = view->updateProperties(links->slice(), true, false); CHECK(true == res.ok()); CHECK((false == logicalCollection->getIndexes().empty())); @@ -1442,9 +1417,9 @@ SECTION("test_unregister_link") { { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); REQUIRE((false == !view)); // add a document to the view @@ -1466,7 +1441,7 @@ SECTION("test_unregister_link") { \"links\": { \"testCollection\": {} } \ }"); - arangodb::Result res = logicalView->updateProperties(links->slice(), true, false); + arangodb::Result res = view->updateProperties(links->slice(), true, false); CHECK(true == res.ok()); CHECK((false == logicalCollection->getIndexes().empty())); @@ -1519,16 +1494,16 @@ SECTION("test_unregister_link") { { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* view = dynamic_cast(logicalView->getImplementation()); + auto view = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); REQUIRE((false == !view)); auto links = arangodb::velocypack::Parser::fromJson("{ \ \"links\": { \"testCollection\": {} } \ }"); - arangodb::Result res = logicalView->updateProperties(links->slice(), true, false); + arangodb::Result res = view->updateProperties(links->slice(), true, false); CHECK(true == res.ok()); CHECK((false == logicalCollection->getIndexes().empty())); @@ -1549,11 +1524,8 @@ SECTION("test_unregister_link") { auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); { - auto createJson = arangodb::velocypack::Parser::fromJson("{}"); auto updateJson = arangodb::velocypack::Parser::fromJson("{ \"links\": { \"testCollection\": {} } }"); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* viewImpl = dynamic_cast(logicalView->getImplementation()); + auto viewImpl = vocbase.createView(viewJson->slice(), 0); REQUIRE((nullptr != viewImpl)); CHECK((viewImpl->updateProperties(updateJson->slice(), true, false).ok())); CHECK((false == logicalCollection->getIndexes().empty())); @@ -1561,27 +1533,24 @@ SECTION("test_unregister_link") { viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); CHECK((1 == cids.size())); - auto factory = [](arangodb::LogicalView*, arangodb::velocypack::Slice const&, bool isNew)->std::unique_ptr{ return nullptr; }; logicalCollection->getIndexes()[0]->unload(); // release view reference to prevent deadlock due to ~IResearchView() waiting for IResearchLink::unload() - logicalView->spawnImplementation(factory, createJson->slice(), true); // ensure destructor for ViewImplementation is called CHECK((false == logicalCollection->getIndexes().empty())); } // create a new view with same ID to validate links { - auto json = arangodb::velocypack::Parser::fromJson("{}"); - arangodb::LogicalView logicalView(&vocbase, viewJson->slice()); - auto view = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), true); + auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\":\"arangosearch\"}"); + auto view = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, json->slice(), true) + ); REQUIRE((false == !view)); - auto* viewImpl = dynamic_cast(view.get()); - REQUIRE((nullptr != viewImpl)); std::set cids; - viewImpl->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); + view->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); CHECK((0 == cids.size())); for (auto& index: logicalCollection->getIndexes()) { auto* link = dynamic_cast(index.get()); - REQUIRE((*link != *viewImpl)); // check that link is unregistred from view + REQUIRE((*link != *view)); // check that link is unregistred from view } } } @@ -1597,16 +1566,15 @@ SECTION("test_self_token") { arangodb::iresearch::IResearchView::AsyncSelf::ptr self; { - auto namedJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\" }"); - auto json = arangodb::velocypack::Parser::fromJson("{}"); - arangodb::LogicalView logicalView(nullptr, namedJson->slice()); - auto view = arangodb::iresearch::IResearchView::make(&logicalView, json->slice(), false); + auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\" }"); + Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); + auto view = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, json->slice(), false) + ); CHECK((false == !view)); - auto* viewImpl = dynamic_cast(view.get()); - REQUIRE((nullptr != viewImpl)); - self = viewImpl->self(); + self = view->self(); CHECK((false == !self)); - CHECK((viewImpl == self->get())); + CHECK((view.get() == self->get())); } CHECK((false == !self)); @@ -1620,14 +1588,11 @@ SECTION("test_tracked_cids") { // test empty before open (TRI_vocbase_t::createView(...) will call open()) { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - arangodb::LogicalView logicalView(&vocbase, viewJson->slice()); - auto view = arangodb::iresearch::IResearchView::make(&logicalView, viewJson->slice(), true); + auto view = arangodb::iresearch::IResearchView::make(vocbase, viewJson->slice(), true); CHECK((nullptr != view)); - auto* viewImpl = dynamic_cast(view.get()); - REQUIRE((nullptr != viewImpl)); std::set actual; - viewImpl->visitCollections([&actual](TRI_voc_cid_t cid)->bool { actual.emplace(cid); return true; }); + view->visitCollections([&actual](TRI_voc_cid_t cid)->bool { actual.emplace(cid); return true; }); CHECK((actual.empty())); } @@ -1637,17 +1602,15 @@ SECTION("test_tracked_cids") { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - arangodb::LogicalView logicalView(&vocbase, viewJson->slice()); - StorageEngineMock().registerView(&vocbase, std::shared_ptr(&logicalView, [](arangodb::LogicalView*)->void{})); // ensure link can find view - logicalView.spawnImplementation(arangodb::iresearch::IResearchView::make, viewJson->slice(), true); - auto* viewImpl = dynamic_cast(logicalView.getImplementation()); - REQUIRE((nullptr != viewImpl)); + auto view = arangodb::iresearch::IResearchView::make(vocbase, viewJson->slice(), true); + REQUIRE((nullptr != view)); + StorageEngineMock().registerView(&vocbase, std::shared_ptr(view.get(), [](arangodb::LogicalView*)->void{})); // ensure link can find view - CHECK((viewImpl->updateProperties(updateJson->slice(), false, false).ok())); + CHECK((view->updateProperties(updateJson->slice(), false, false).ok())); std::set actual; std::set expected = { 100 }; - viewImpl->visitCollections([&actual](TRI_voc_cid_t cid)->bool { actual.emplace(cid); return true; }); + view->visitCollections([&actual](TRI_voc_cid_t cid)->bool { actual.emplace(cid); return true; }); for (auto& cid: actual) { CHECK((1 == expected.erase(cid))); @@ -1664,11 +1627,11 @@ SECTION("test_tracked_cids") { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - arangodb::LogicalView logicalView(&vocbase, viewJson->slice()); - StorageEngineMock().registerView(&vocbase, std::shared_ptr(&logicalView, [](arangodb::LogicalView*)->void{})); // ensure link can find view - logicalView.spawnImplementation(arangodb::iresearch::IResearchView::make, viewJson->slice(), true); - auto* viewImpl = dynamic_cast(logicalView.getImplementation()); + auto viewImpl = std::dynamic_pointer_cast( + arangodb::iresearch::IResearchView::make(vocbase, viewJson->slice(), true) + ); REQUIRE((nullptr != viewImpl)); + StorageEngineMock().registerView(&vocbase, std::shared_ptr(viewImpl.get(), [](arangodb::LogicalView*)->void{})); // ensure link can find view // create link { @@ -1704,9 +1667,9 @@ SECTION("test_tracked_cids") { auto* feature = arangodb::iresearch::getFeature("Flush"); REQUIRE(feature); Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* viewImpl = dynamic_cast(logicalView->getImplementation()); + auto viewImpl = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((nullptr != viewImpl)); static std::vector const EMPTY; @@ -1727,9 +1690,7 @@ SECTION("test_tracked_cids") { { auto createJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": 102, \"properties\": { } }"); Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* viewImpl = dynamic_cast(logicalView->getImplementation()); + auto viewImpl = vocbase.createView(createJson->slice(), 0); REQUIRE((nullptr != viewImpl)); std::set actual; @@ -1744,9 +1705,7 @@ SECTION("test_tracked_cids") { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* viewImpl = dynamic_cast(logicalView->getImplementation()); + auto viewImpl = vocbase.createView(viewJson->slice(), 0); REQUIRE((nullptr != viewImpl)); CHECK((viewImpl->updateProperties(updateJson->slice(), false, false).ok())); @@ -1769,9 +1728,7 @@ SECTION("test_tracked_cids") { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* viewImpl = dynamic_cast(logicalView->getImplementation()); + auto viewImpl = vocbase.createView(viewJson->slice(), 0); REQUIRE((nullptr != viewImpl)); // create link @@ -1809,15 +1766,15 @@ SECTION("test_transaction_registration") { REQUIRE((nullptr != logicalCollection0)); auto* logicalCollection1 = vocbase.createCollection(collectionJson1->slice()); REQUIRE((nullptr != logicalCollection1)); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* viewImpl = dynamic_cast(logicalView->getImplementation()); - REQUIRE((nullptr != viewImpl)); + auto logicalView = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); + REQUIRE((nullptr != logicalView)); // link collection to view { auto updateJson = arangodb::velocypack::Parser::fromJson("{ \"links\": { \"testCollection0\": {}, \"testCollection1\": {} } }"); - CHECK((viewImpl->updateProperties(updateJson->slice(), false, false).ok())); + CHECK((logicalView->updateProperties(updateJson->slice(), false, false).ok())); } // read transaction (by id) @@ -2086,9 +2043,9 @@ SECTION("test_transaction_snapshot") { static std::vector const EMPTY; auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"commit\": { \"commitIntervalMsec\": 0 } }"); Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(viewJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto* viewImpl = dynamic_cast(logicalView->getImplementation()); + auto viewImpl = std::dynamic_pointer_cast( + vocbase.createView(viewJson->slice(), 0) + ); REQUIRE((nullptr != viewImpl)); // add a single document to view (do not sync) @@ -2225,9 +2182,9 @@ SECTION("test_update_overwrite") { // modify meta params { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); // initial update (overwrite) @@ -2247,7 +2204,7 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2274,7 +2231,7 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2298,10 +2255,11 @@ SECTION("test_update_overwrite") { REQUIRE((nullptr != logicalCollection0)); auto* logicalCollection1 = vocbase.createCollection(collectionJson1->slice()); REQUIRE((nullptr != logicalCollection1)); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); + REQUIRE(view->category() == arangodb::LogicalView::category()); CHECK((true == logicalCollection0->getIndexes().empty())); CHECK((true == logicalCollection1->getIndexes().empty())); @@ -2318,7 +2276,7 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2365,7 +2323,7 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2406,10 +2364,11 @@ SECTION("test_update_overwrite") { auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); + REQUIRE(view->category() == arangodb::LogicalView::category()); // initial add of link { @@ -2421,7 +2380,7 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2445,7 +2404,7 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2468,10 +2427,11 @@ SECTION("test_update_partial") { // modify meta params { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); + REQUIRE(view->category() == arangodb::LogicalView::category()); arangodb::iresearch::IResearchViewMeta expectedMeta; auto updateJson = arangodb::velocypack::Parser::fromJson("{ \ @@ -2488,7 +2448,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2505,10 +2465,11 @@ SECTION("test_update_partial") { // test rollback on meta modification failure (as an example invalid value for 'locale') { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); + REQUIRE(view->category() == arangodb::LogicalView::category()); arangodb::iresearch::IResearchViewMeta expectedMeta; auto updateJson = arangodb::velocypack::Parser::fromJson(std::string() + "{ \ @@ -2522,7 +2483,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2542,10 +2503,11 @@ SECTION("test_update_partial") { auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); + REQUIRE(view->category() == arangodb::LogicalView::category()); auto updateJson = arangodb::velocypack::Parser::fromJson( "{ \"links\": { \"testCollection\": {} } }" @@ -2559,7 +2521,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2576,10 +2538,11 @@ SECTION("test_update_partial") { auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); + REQUIRE(view->category() == arangodb::LogicalView::category()); arangodb::iresearch::IResearchViewMeta expectedMeta; std::unordered_map expectedLinkMeta; @@ -2595,7 +2558,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2633,10 +2596,11 @@ SECTION("test_update_partial") { auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); + REQUIRE(view->category() == arangodb::LogicalView::category()); { static std::vector const EMPTY; @@ -2665,7 +2629,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2700,10 +2664,11 @@ SECTION("test_update_partial") { // add new link to non-existant collection { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); + REQUIRE(view->category() == arangodb::LogicalView::category()); arangodb::iresearch::IResearchViewMeta expectedMeta; auto updateJson = arangodb::velocypack::Parser::fromJson("{ \ @@ -2716,7 +2681,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2736,10 +2701,11 @@ SECTION("test_update_partial") { auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = std::dynamic_pointer_cast( + vocbase.createView(createJson->slice(), 0) + ); REQUIRE((false == !view)); + REQUIRE(view->category() == arangodb::LogicalView::category()); { auto updateJson = arangodb::velocypack::Parser::fromJson( @@ -2750,7 +2716,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2774,7 +2740,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2792,9 +2758,7 @@ SECTION("test_update_partial") { auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = vocbase.createView(createJson->slice(), 0); REQUIRE((false == !view)); arangodb::iresearch::IResearchViewMeta expectedMeta; @@ -2812,7 +2776,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2838,7 +2802,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2856,9 +2820,7 @@ SECTION("test_update_partial") { // remove link from non-existant collection { Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = vocbase.createView(createJson->slice(), 0); REQUIRE((false == !view)); arangodb::iresearch::IResearchViewMeta expectedMeta; @@ -2872,7 +2834,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2892,9 +2854,7 @@ SECTION("test_update_partial") { auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = vocbase.createView(createJson->slice(), 0); REQUIRE((false == !view)); arangodb::iresearch::IResearchViewMeta expectedMeta; @@ -2908,7 +2868,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2928,9 +2888,7 @@ SECTION("test_update_partial") { auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = vocbase.createView(createJson->slice(), 0); REQUIRE((false == !view)); // initial add of link @@ -2943,7 +2901,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2967,7 +2925,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -2990,9 +2948,7 @@ SECTION("test_update_partial") { auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testCollection\" }"); auto* logicalCollection = vocbase.createCollection(collectionJson->slice()); REQUIRE((nullptr != logicalCollection)); - auto logicalView = vocbase.createView(createJson->slice(), 0); - REQUIRE((false == !logicalView)); - auto view = logicalView->getImplementation(); + auto view = vocbase.createView(createJson->slice(), 0); REQUIRE((false == !view)); // initial add of link @@ -3005,7 +2961,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); @@ -3029,7 +2985,7 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->getPropertiesVPack(builder, false); + view->toVelocyPack(builder, false, false); builder.close(); auto slice = builder.slice(); diff --git a/tests/Utils/CollectionNameResolver-test.cpp b/tests/Utils/CollectionNameResolver-test.cpp index 61e8b9145c..db0738422f 100644 --- a/tests/Utils/CollectionNameResolver-test.cpp +++ b/tests/Utils/CollectionNameResolver-test.cpp @@ -36,20 +36,23 @@ namespace { -std::unique_ptr makeTestView( - arangodb::LogicalView* view, +std::unique_ptr makeTestView( + TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& info, bool isNew ) { - struct Impl: public arangodb::ViewImplementation { - Impl(): ViewImplementation(nullptr, arangodb::velocypack::Slice::emptyObjectSlice()) { + struct Impl: public arangodb::LogicalView{ + Impl(): arangodb::LogicalView(nullptr, arangodb::velocypack::Slice::emptyObjectSlice()) { } virtual void drop() override {} - virtual void getPropertiesVPack( - arangodb::velocypack::Builder&, bool + virtual void toVelocyPack( + arangodb::velocypack::Builder&, bool, bool ) const override { } virtual void open() override {} + virtual arangodb::Result rename(std::string&& newName, bool doSync) { + return {}; + } virtual arangodb::Result updateProperties( arangodb::velocypack::Slice const&, bool, bool ) override { @@ -62,7 +65,7 @@ std::unique_ptr makeTestView( } }; - return std::unique_ptr(new Impl()); + return std::make_unique(); } } @@ -260,4 +263,4 @@ SECTION("test_getDataSource") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/VocBase/LogicalDataSource-test.cpp b/tests/VocBase/LogicalDataSource-test.cpp index d5981e046d..0c0a080345 100644 --- a/tests/VocBase/LogicalDataSource-test.cpp +++ b/tests/VocBase/LogicalDataSource-test.cpp @@ -64,14 +64,6 @@ SECTION("test_category") { CHECK((arangodb::LogicalCollection::category() == instance.category())); } - - // LogicalView - { - auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\" }"); - arangodb::LogicalView instance(nullptr, json->slice()); - - CHECK((arangodb::LogicalView::category() == instance.category())); - } } //////////////////////////////////////////////////////////////////////////////// @@ -82,4 +74,4 @@ SECTION("test_category") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/VocBase/vocbase-test.cpp b/tests/VocBase/vocbase-test.cpp index b7e26defac..df4d4ec0e3 100644 --- a/tests/VocBase/vocbase-test.cpp +++ b/tests/VocBase/vocbase-test.cpp @@ -33,22 +33,27 @@ #include "VocBase/LogicalView.h" #include "velocypack/Parser.h" +#include + namespace { -std::unique_ptr makeTestView( - arangodb::LogicalView* view, +std::unique_ptr makeTestView( + TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& info, bool isNew ) { - struct Impl: public arangodb::ViewImplementation { - Impl(): ViewImplementation(nullptr, arangodb::velocypack::Slice::emptyObjectSlice()) { + struct Impl: public arangodb::LogicalView{ + Impl(): LogicalView(nullptr, arangodb::velocypack::Slice::emptyObjectSlice()) { } virtual void drop() override {} - virtual void getPropertiesVPack( - arangodb::velocypack::Builder&, bool + virtual void toVelocyPack( + arangodb::velocypack::Builder&, bool, bool ) const override { } virtual void open() override {} + virtual arangodb::Result rename(std::string&& newName, bool doSync) { + return {}; + } virtual arangodb::Result updateProperties( arangodb::velocypack::Slice const&, bool, bool ) override { @@ -61,7 +66,7 @@ std::unique_ptr makeTestView( } }; - return std::unique_ptr(new Impl()); + return std::make_unique(); } } @@ -365,4 +370,4 @@ SECTION("test_lookupDataSource") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- From a7760cb3b713d3e655711f416c9c900f47415202 Mon Sep 17 00:00:00 2001 From: Andrey Abramov Date: Tue, 27 Mar 2018 14:44:10 +0300 Subject: [PATCH 2/5] fix tests --- arangod/IResearch/IResearchView.cpp | 10 +- tests/IResearch/IResearchQueryJoin-test.cpp | 16 +- .../IResearchQueryNumericTerm-test.cpp | 8 +- tests/IResearch/IResearchQueryOr-test.cpp | 8 +- .../IResearchQuerySelectAll-test.cpp | 8 +- .../IResearchQueryStartsWith-test.cpp | 8 +- .../IResearchQueryStringTerm-test.cpp | 8 +- tests/IResearch/IResearchView-test.cpp | 312 +++++++++++++----- tests/Utils/CollectionNameResolver-test.cpp | 9 +- tests/VocBase/vocbase-test.cpp | 9 +- 10 files changed, 292 insertions(+), 104 deletions(-) diff --git a/arangod/IResearch/IResearchView.cpp b/arangod/IResearch/IResearchView.cpp index e364c55ce2..4deaecce12 100644 --- a/arangod/IResearch/IResearchView.cpp +++ b/arangod/IResearch/IResearchView.cpp @@ -1797,10 +1797,16 @@ arangodb::Result IResearchView::link( new IResearchView(&vocbase, info, std::move(dataPath)) ); - auto& json = info.isNone() ? emptyObjectSlice() : info; // if no 'info' then assume defaults + auto props = info.get("properties"); + + if (props.isNone()) { + // if no 'properties' then assume defaults + props = emptyObjectSlice(); + } + std::string error; - if (!ptr->_meta.init(json, error)) { + if (!ptr->_meta.init(props, error)) { LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) << "failed to initialize iResearch view from definition, error: " << error; diff --git a/tests/IResearch/IResearchQueryJoin-test.cpp b/tests/IResearch/IResearchQueryJoin-test.cpp index 1737ee3d1a..95120fdc1f 100644 --- a/tests/IResearch/IResearchQueryJoin-test.cpp +++ b/tests/IResearch/IResearchQueryJoin-test.cpp @@ -365,11 +365,15 @@ TEST_CASE("IResearchQueryTestJoinDuplicateDataSource", "[iresearch][iresearch-qu arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 2 == tmpSlice.length())); } @@ -565,11 +569,15 @@ TEST_CASE("IResearchQueryTestJoin", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 2 == tmpSlice.length())); } diff --git a/tests/IResearch/IResearchQueryNumericTerm-test.cpp b/tests/IResearch/IResearchQueryNumericTerm-test.cpp index 50255c676e..248f654fe1 100644 --- a/tests/IResearch/IResearchQueryNumericTerm-test.cpp +++ b/tests/IResearch/IResearchQueryNumericTerm-test.cpp @@ -228,11 +228,15 @@ TEST_CASE("IResearchQueryTestNumericTerm", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 2 == tmpSlice.length())); } diff --git a/tests/IResearch/IResearchQueryOr-test.cpp b/tests/IResearch/IResearchQueryOr-test.cpp index 5ba6a2cda4..a4445c4f29 100644 --- a/tests/IResearch/IResearchQueryOr-test.cpp +++ b/tests/IResearch/IResearchQueryOr-test.cpp @@ -219,11 +219,15 @@ TEST_CASE("IResearchQueryTestOr", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 2 == tmpSlice.length())); } diff --git a/tests/IResearch/IResearchQuerySelectAll-test.cpp b/tests/IResearch/IResearchQuerySelectAll-test.cpp index ced874bbb3..cced2bcc5a 100644 --- a/tests/IResearch/IResearchQuerySelectAll-test.cpp +++ b/tests/IResearch/IResearchQuerySelectAll-test.cpp @@ -219,11 +219,15 @@ TEST_CASE("IResearchQueryTestSelectAll", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 2 == tmpSlice.length())); } diff --git a/tests/IResearch/IResearchQueryStartsWith-test.cpp b/tests/IResearch/IResearchQueryStartsWith-test.cpp index a58b85c6ec..42f1bfce13 100644 --- a/tests/IResearch/IResearchQueryStartsWith-test.cpp +++ b/tests/IResearch/IResearchQueryStartsWith-test.cpp @@ -219,11 +219,15 @@ TEST_CASE("IResearchQueryTestStartsWith", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 2 == tmpSlice.length())); } diff --git a/tests/IResearch/IResearchQueryStringTerm-test.cpp b/tests/IResearch/IResearchQueryStringTerm-test.cpp index feed9adeb8..7891c02184 100644 --- a/tests/IResearch/IResearchQueryStringTerm-test.cpp +++ b/tests/IResearch/IResearchQueryStringTerm-test.cpp @@ -256,11 +256,15 @@ TEST_CASE("IResearchQueryTestStringTerm", "[iresearch][iresearch-query]") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 2 == tmpSlice.length())); } diff --git a/tests/IResearch/IResearchView-test.cpp b/tests/IResearch/IResearchView-test.cpp index 7d7996755f..2c79d243ed 100644 --- a/tests/IResearch/IResearchView-test.cpp +++ b/tests/IResearch/IResearchView-test.cpp @@ -1217,8 +1217,24 @@ SECTION("test_register_link") { auto view = std::dynamic_pointer_cast( vocbase.createView(viewJson0->slice(), 0) ); + REQUIRE((false == !view)); + { + arangodb::velocypack::Builder builder; + builder.openObject(); + view->toVelocyPack(builder, false, false); + builder.close(); + + auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("id").copyString() == "101"); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + CHECK(3 == slice.length()); + } + { std::set cids; view->visitCollections([&cids](TRI_voc_cid_t cid)->bool { cids.emplace(cid); return true; }); @@ -1244,6 +1260,22 @@ SECTION("test_register_link") { ); REQUIRE((false == !view)); + { + arangodb::velocypack::Builder builder; + + builder.openObject(); + view->toVelocyPack(builder, false, false); + builder.close(); + + auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("id").copyString() == "101"); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + CHECK(3 == slice.length()); + } + { std::unordered_set cids; view->sync(); @@ -2204,17 +2236,24 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + CHECK(4 == slice.length()); arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length())); } @@ -2231,17 +2270,23 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length())); } } @@ -2276,17 +2321,23 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); for (arangodb::velocypack::ObjectIterator itr(tmpSlice); itr.valid(); ++itr) { @@ -2323,17 +2374,23 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); for (arangodb::velocypack::ObjectIterator itr(tmpSlice); itr.valid(); ++itr) { @@ -2380,13 +2437,18 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("collections"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + + auto tmpSlice = slice.get("properties").get("collections"); CHECK((true == tmpSlice.isArray() && 1 == tmpSlice.length())); - tmpSlice = slice.get("links"); + tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); tmpSlice = tmpSlice.get("testCollection"); CHECK((true == tmpSlice.isObject())); @@ -2404,11 +2466,14 @@ SECTION("test_update_overwrite") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); tmpSlice = tmpSlice.get("testCollection"); CHECK((true == tmpSlice.isObject())); @@ -2448,17 +2513,23 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length())); } @@ -2483,17 +2554,23 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length())); } @@ -2521,14 +2598,21 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); CHECK(( - true == slice.hasKey("links") - && slice.get("links").isObject() - && 1 == slice.get("links").length() + true == propSlice.hasKey("links") + && propSlice.get("links").isObject() + && 1 == propSlice.get("links").length() )); } @@ -2558,17 +2642,23 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); for (arangodb::velocypack::ObjectIterator itr(tmpSlice); itr.valid(); ++itr) { @@ -2629,17 +2719,22 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); for (arangodb::velocypack::ObjectIterator itr(tmpSlice); itr.valid(); ++itr) { @@ -2681,17 +2776,22 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length())); } @@ -2716,14 +2816,20 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + + auto propSlice = slice.get("properties"); CHECK(( - true == slice.hasKey("links") - && slice.get("links").isObject() - && 1 == slice.get("links").length() + true == propSlice.hasKey("links") + && propSlice.get("links").isObject() + && 1 == propSlice.get("links").length() )); } @@ -2740,14 +2846,20 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + + auto propSlice = slice.get("properties"); CHECK(( - true == slice.hasKey("links") - && slice.get("links").isObject() - && 0 == slice.get("links").length() + true == propSlice.hasKey("links") + && propSlice.get("links").isObject() + && 0 == propSlice.get("links").length() )); } } @@ -2776,17 +2888,23 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); } @@ -2802,17 +2920,23 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length())); } } @@ -2834,17 +2958,23 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length())); } @@ -2868,17 +2998,23 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties arangodb::iresearch::IResearchViewMeta meta; std::string error; - CHECK((6U == slice.length())); - CHECK((meta.init(slice, error) && expectedMeta == meta)); + auto propSlice = slice.get("properties"); + CHECK(propSlice.isObject()); + CHECK((6U == propSlice.length())); + CHECK((meta.init(propSlice, error) && expectedMeta == meta)); - auto tmpSlice = slice.get("links"); + auto tmpSlice = propSlice.get("links"); CHECK((true == tmpSlice.isObject() && 0 == tmpSlice.length())); } @@ -2901,11 +3037,15 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); } @@ -2925,11 +3065,15 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); std::unordered_set actual; @@ -2961,13 +3105,17 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("collections"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("collections"); CHECK((true == tmpSlice.isArray() && 1 == tmpSlice.length())); - tmpSlice = slice.get("links"); + tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); tmpSlice = tmpSlice.get("testCollection"); CHECK((true == tmpSlice.isObject())); @@ -2985,11 +3133,15 @@ SECTION("test_update_partial") { arangodb::velocypack::Builder builder; builder.openObject(); - view->toVelocyPack(builder, false, false); + view->toVelocyPack(builder, true, false); builder.close(); auto slice = builder.slice(); - auto tmpSlice = slice.get("links"); + CHECK(slice.isObject()); + CHECK(slice.get("name").copyString() == "testView"); + CHECK(slice.get("type").copyString() == arangodb::iresearch::IResearchView::type().name()); + CHECK(slice.get("deleted").isNone()); // no system properties + auto tmpSlice = slice.get("properties").get("links"); CHECK((true == tmpSlice.isObject() && 1 == tmpSlice.length())); tmpSlice = tmpSlice.get("testCollection"); CHECK((true == tmpSlice.isObject())); @@ -2999,10 +3151,6 @@ SECTION("test_update_partial") { } } -//////////////////////////////////////////////////////////////////////////////// -/// @brief generate tests -//////////////////////////////////////////////////////////////////////////////// - } // ----------------------------------------------------------------------------- diff --git a/tests/Utils/CollectionNameResolver-test.cpp b/tests/Utils/CollectionNameResolver-test.cpp index db0738422f..88267b3e99 100644 --- a/tests/Utils/CollectionNameResolver-test.cpp +++ b/tests/Utils/CollectionNameResolver-test.cpp @@ -42,9 +42,12 @@ std::unique_ptr makeTestView( bool isNew ) { struct Impl: public arangodb::LogicalView{ - Impl(): arangodb::LogicalView(nullptr, arangodb::velocypack::Slice::emptyObjectSlice()) { + Impl(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& info) + : arangodb::LogicalView(&vocbase, info) { + } + virtual void drop() override { + deleted(true); } - virtual void drop() override {} virtual void toVelocyPack( arangodb::velocypack::Builder&, bool, bool ) const override { @@ -65,7 +68,7 @@ std::unique_ptr makeTestView( } }; - return std::make_unique(); + return std::make_unique(vocbase, info); } } diff --git a/tests/VocBase/vocbase-test.cpp b/tests/VocBase/vocbase-test.cpp index df4d4ec0e3..456d81648e 100644 --- a/tests/VocBase/vocbase-test.cpp +++ b/tests/VocBase/vocbase-test.cpp @@ -43,9 +43,12 @@ std::unique_ptr makeTestView( bool isNew ) { struct Impl: public arangodb::LogicalView{ - Impl(): LogicalView(nullptr, arangodb::velocypack::Slice::emptyObjectSlice()) { + Impl(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& info) + : LogicalView(&vocbase, info) { + } + virtual void drop() override { + deleted(true); } - virtual void drop() override {} virtual void toVelocyPack( arangodb::velocypack::Builder&, bool, bool ) const override { @@ -66,7 +69,7 @@ std::unique_ptr makeTestView( } }; - return std::make_unique(); + return std::make_unique(vocbase, info); } } From 65ea2bfbb9259868e0e4a22764e97757ed1810e0 Mon Sep 17 00:00:00 2001 From: Andrey Abramov Date: Tue, 27 Mar 2018 18:39:59 +0300 Subject: [PATCH 3/5] code cleanup --- arangod/IResearch/IResearchLink.cpp | 3 +- arangod/IResearch/IResearchView.cpp | 562 +++++++++++++--------------- arangod/IResearch/IResearchView.h | 21 +- arangod/VocBase/LogicalView.cpp | 32 +- arangod/VocBase/LogicalView.h | 17 +- arangod/VocBase/vocbase.cpp | 23 +- 6 files changed, 313 insertions(+), 345 deletions(-) diff --git a/arangod/IResearch/IResearchLink.cpp b/arangod/IResearch/IResearchLink.cpp index dfa9e8ff82..1ad55abf1e 100644 --- a/arangod/IResearch/IResearchLink.cpp +++ b/arangod/IResearch/IResearchLink.cpp @@ -170,8 +170,7 @@ int IResearchLink::drop() { // if the collection is in the process of being removed then drop it from the view if (_collection->deleted()) { - auto result = - _view->updateLogicalProperties(emptyObjectSlice(), true, false); // revalidate all links + auto result = _view->updateProperties(emptyObjectSlice(), true, false); // revalidate all links if (!result.ok()) { LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) diff --git a/arangod/IResearch/IResearchView.cpp b/arangod/IResearch/IResearchView.cpp index 4deaecce12..a21cb4f195 100644 --- a/arangod/IResearch/IResearchView.cpp +++ b/arangod/IResearch/IResearchView.cpp @@ -765,10 +765,11 @@ IResearchView::PersistedStore::PersistedStore(irs::utf8_path&& path) } IResearchView::IResearchView( - TRI_vocbase_t* vocbase, - arangodb::velocypack::Slice const& info, - irs::utf8_path&& persistedPath -) : DBServerLogicalView(vocbase, info), + TRI_vocbase_t* vocbase, + arangodb::velocypack::Slice const& info, + irs::utf8_path&& persistedPath, + bool isNew +) : DBServerLogicalView(vocbase, info, isNew), FlushTransaction(toString(*this)), _asyncMetaRevision(1), _asyncSelf(irs::memory::make_unique(this)), @@ -1038,8 +1039,103 @@ void IResearchView::apply(arangodb::TransactionState& state) { } void IResearchView::drop() { - dropImpl(); - DBServerLogicalView::drop(); + std::unordered_set collections; + + // drop all known links + if (vocbase()) { + arangodb::velocypack::Builder builder; + + { + ReadMutex mutex(_mutex); + SCOPED_LOCK(mutex); // '_meta' and '_trackedCids' can be asynchronously updated + + builder.openObject(); + + if (!appendLinkRemoval(builder, _meta)) { + throw std::runtime_error(std::string("failed to construct link removal directive while removing iResearch view '") + std::to_string(id()) + "'"); + } + + builder.close(); + } + + if (!updateLinks(collections, *(vocbase()), *this, builder.slice()).ok()) { + throw std::runtime_error(std::string("failed to remove links while removing iResearch view '") + std::to_string(id()) + "'"); + } + } + + { + WriteMutex mutex(_asyncSelf->_mutex); + SCOPED_LOCK(mutex); // wait for all the view users to finish + _asyncSelf->_value.store(nullptr); // the view data-stores are being deallocated, view use is no longer valid + } + + _asyncTerminate.store(true); // mark long-running async jobs for terminatation + + { + SCOPED_LOCK(_asyncMutex); + _asyncCondition.notify_all(); // trigger reload of settings for async jobs + } + + _threadPool.stop(); + + WriteMutex mutex(_mutex); // members can be asynchronously updated + SCOPED_LOCK(mutex); + + collections.insert(_meta._collections.begin(), _meta._collections.end()); + + if (vocbase()) { + validateLinks(collections, *(vocbase()), *this); + } + + // ArangoDB global consistency check, no known dangling links + if (!collections.empty()) { + throw std::runtime_error(std::string("links still present while removing iResearch view '") + std::to_string(id()) + "'"); + } + + // ........................................................................... + // if an exception occurs below than a drop retry would most likely happen + // ........................................................................... + try { + _storeByTid.clear(); + + for (size_t i = 0, count = IRESEARCH_COUNTOF(_memoryNodes); i < count; ++i) { + auto& memoryStore = _memoryNodes[i]._store; + + memoryStore._writer->close(); + memoryStore._writer.reset(); + memoryStore._directory->close(); + memoryStore._directory.reset(); + } + + if (_storePersisted) { + _storePersisted._writer->close(); + _storePersisted._writer.reset(); + _storePersisted._directory->close(); + _storePersisted._directory.reset(); + } + + bool exists; + + // remove persisted data store directory if present + if (_storePersisted._path.exists_directory(exists) + && (!exists || _storePersisted._path.remove())) { + DBServerLogicalView::drop(); + deleted(true); + return; // success + } + } catch (std::exception const& e) { + LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) + << "caught exception while removing iResearch view '" << id() << "': " << e.what(); + IR_LOG_EXCEPTION(); + throw; + } catch (...) { + LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) + << "caught exception while removing iResearch view '" << id() << "'"; + IR_LOG_EXCEPTION(); + throw; + } + + throw std::runtime_error(std::string("failed to remove iResearch view '") + arangodb::basics::StringUtils::itoa(id()) + "'"); } int IResearchView::drop(TRI_voc_cid_t cid) { @@ -1199,271 +1295,6 @@ arangodb::Result IResearchView::commit() { return {TRI_ERROR_INTERNAL}; } -void IResearchView::dropImpl() { - deleted(true); - - std::unordered_set collections; - - // drop all known links - if (vocbase()) { - arangodb::velocypack::Builder builder; - - { - ReadMutex mutex(_mutex); - SCOPED_LOCK(mutex); // '_meta' and '_trackedCids' can be asynchronously updated - - builder.openObject(); - - if (!appendLinkRemoval(builder, _meta)) { - throw std::runtime_error(std::string("failed to construct link removal directive while removing iResearch view '") + std::to_string(id()) + "'"); - } - - builder.close(); - } - - if (!updateLinks(collections, *(vocbase()), *this, builder.slice()).ok()) { - throw std::runtime_error(std::string("failed to remove links while removing iResearch view '") + std::to_string(id()) + "'"); - } - } - - { - WriteMutex mutex(_asyncSelf->_mutex); - SCOPED_LOCK(mutex); // wait for all the view users to finish - _asyncSelf->_value.store(nullptr); // the view data-stores are being deallocated, view use is no longer valid - } - - _asyncTerminate.store(true); // mark long-running async jobs for terminatation - - { - SCOPED_LOCK(_asyncMutex); - _asyncCondition.notify_all(); // trigger reload of settings for async jobs - } - - _threadPool.stop(); - - WriteMutex mutex(_mutex); // members can be asynchronously updated - SCOPED_LOCK(mutex); - - collections.insert(_meta._collections.begin(), _meta._collections.end()); - - if (vocbase()) { - validateLinks(collections, *(vocbase()), *this); - } - - // ArangoDB global consistency check, no known dangling links - if (!collections.empty()) { - throw std::runtime_error(std::string("links still present while removing iResearch view '") + std::to_string(id()) + "'"); - } - - // ........................................................................... - // if an exception occurs below than a drop retry would most likely happen - // ........................................................................... - try { - _storeByTid.clear(); - - for (size_t i = 0, count = IRESEARCH_COUNTOF(_memoryNodes); i < count; ++i) { - auto& memoryStore = _memoryNodes[i]._store; - - memoryStore._writer->close(); - memoryStore._writer.reset(); - memoryStore._directory->close(); - memoryStore._directory.reset(); - } - - if (_storePersisted) { - _storePersisted._writer->close(); - _storePersisted._writer.reset(); - _storePersisted._directory->close(); - _storePersisted._directory.reset(); - } - - bool exists; - - // remove persisted data store directory if present - if (_storePersisted._path.exists_directory(exists) - && (!exists || _storePersisted._path.remove())) { - return; // success - } - } catch (std::exception const& e) { - LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) - << "caught exception while removing iResearch view '" << id() << "': " << e.what(); - IR_LOG_EXCEPTION(); - throw; - } catch (...) { - LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) - << "caught exception while removing iResearch view '" << id() << "'"; - IR_LOG_EXCEPTION(); - throw; - } - - throw std::runtime_error(std::string("failed to remove iResearch view '") + arangodb::basics::StringUtils::itoa(id()) + "'"); -} - -arangodb::Result IResearchView::updatePropertiesImpl( - const velocypack::Slice &slice, - bool partialUpdate, - bool doSync -) { - auto* vocbase = this->vocbase(); - - if (!vocbase) { - return arangodb::Result( - TRI_ERROR_INTERNAL, - std::string("failed to find vocbase while updating links for iResearch view '") + std::to_string(id()) + "'" - ); - } - - std::string error; - IResearchViewMeta meta; - IResearchViewMeta::Mask mask; - WriteMutex mutex(_mutex); // '_meta' can be asynchronously read - arangodb::Result res = arangodb::Result(/*TRI_ERROR_NO_ERROR*/); - - { - SCOPED_LOCK(mutex); - - arangodb::velocypack::Builder originalMetaJson; // required for reverting links on failure - - if (!_meta.json(arangodb::velocypack::ObjectBuilder(&originalMetaJson))) { - return arangodb::Result( - TRI_ERROR_INTERNAL, - std::string("failed to generate json definition while updating iResearch view '") + std::to_string(id()) + "'" - ); - } - - auto& initialMeta = partialUpdate ? _meta : IResearchViewMeta::DEFAULT(); - - if (!meta.init(slice, error, initialMeta, &mask)) { - return arangodb::Result(TRI_ERROR_BAD_PARAMETER, std::move(error)); - } - - // FIXME TODO remove once View::updateProperties(...) will be fixed to write - // the update delta into the WAL marker instead of the full persisted state - // below is a very dangerous hack as it allows multiple links from the same - // collection to point to the same view, thus breaking view data consistency - { - auto* engine = arangodb::EngineSelectorFeature::ENGINE; - - if (engine && engine->inRecovery()) { - arangodb::velocypack::Builder linksBuilder; - - linksBuilder.openObject(); - - // remove links no longer present in incming update - for (auto& cid: _meta._collections) { - if (meta._collections.find(cid) == meta._collections.end()) { - linksBuilder.add( - std::to_string(cid), - arangodb::velocypack::Value(arangodb::velocypack::ValueType::Null) - ); - } - } - - for (auto& cid: meta._collections) { - auto collection = vocbase->lookupCollection(cid); - - if (collection) { - _meta._collections.emplace(cid); - - for (auto& index: collection->getIndexes()) { - if (index && arangodb::Index::TRI_IDX_TYPE_IRESEARCH_LINK == index->type()) { - auto* link = dynamic_cast(index.get()); - - if (link && link->_defaultId == id() && !link->view()) { - arangodb::velocypack::Builder linkBuilder; - bool valid; - - linkBuilder.openObject(); - valid = link->json(linkBuilder, true); - linkBuilder.close(); - - linksBuilder.add( - std::to_string(cid), - arangodb::velocypack::Value(arangodb::velocypack::ValueType::Null) - ); - - if (valid) { - linksBuilder.add(std::to_string(cid), linkBuilder.slice()); - } - } - } - } - } - } - - std::unordered_set collections; - - linksBuilder.close(); - updateLinks(collections, *vocbase, *this, linksBuilder.slice()); - collections.insert(_meta._collections.begin(), _meta._collections.end()); - validateLinks(collections, *vocbase, *this); // remove invalid cids (no such collection or no such link) - _meta._collections = std::move(collections); - } - } - - // reset non-updatable values to match current meta - meta._collections = _meta._collections; - - if (mask._threadsMaxIdle) { - _threadPool.max_idle(meta._threadsMaxIdle); - } - - if (mask._threadsMaxTotal) { - _threadPool.max_threads(meta._threadsMaxTotal); - } - - { - SCOPED_LOCK(_asyncMutex); - _asyncCondition.notify_all(); // trigger reload of timeout settings for async jobs - } - - _meta = std::move(meta); - } - - std::unordered_set collections; - - // update links if requested (on a best-effort basis) - // indexing of collections is done in different threads so no locks can be held and rollback is not possible - // as a result it's also possible for links to be simultaneously modified via a different callflow (e.g. from collections) - if (slice.hasKey(LINKS_FIELD)) { - if (partialUpdate) { - res = updateLinks(collections, *vocbase, *this, slice.get(LINKS_FIELD)); - } else { - arangodb::velocypack::Builder builder; - - builder.openObject(); - - if (!appendLinkRemoval(builder, _meta) - || !mergeSlice(builder, slice.get(LINKS_FIELD))) { - return arangodb::Result( - TRI_ERROR_INTERNAL, - std::string("failed to construct link update directive while updating iResearch view '") + std::to_string(id()) + "'" - ); - } - - builder.close(); - res = updateLinks(collections, *vocbase, *this, builder.slice()); - } - } - - // ........................................................................... - // if an exception occurs below then it would only affect collection linking - // consistency and an update retry would most likely happen - // always re-validate '_collections' because may have had externally triggered - // collection/link drops - // ........................................................................... - { - SCOPED_LOCK(mutex); // '_meta' can be asynchronously read - collections.insert(_meta._collections.begin(), _meta._collections.end()); - validateLinks(collections, *vocbase, *this); // remove invalid cids (no such collection or no such link) - _meta._collections = std::move(collections); - } - - // FIXME TODO to ensure valid recovery remove the original datapath only if the entire, but under lock to prevent double rename - - return res; -} - void IResearchView::getPropertiesVPack( arangodb::velocypack::Builder& builder, bool forPersistence ) const { @@ -1757,9 +1588,9 @@ arangodb::Result IResearchView::link( } /*static*/ std::shared_ptr IResearchView::make( - TRI_vocbase_t& vocbase, - arangodb::velocypack::Slice const& info, - bool isNew + TRI_vocbase_t& vocbase, + arangodb::velocypack::Slice const& info, + bool isNew ) { auto const id = readViewId(info); @@ -1793,8 +1624,8 @@ arangodb::Result IResearchView::link( dataPath += "-"; dataPath += std::to_string(id); - auto ptr = std::unique_ptr( - new IResearchView(&vocbase, info, std::move(dataPath)) + auto view = std::unique_ptr( + new IResearchView(&vocbase, info, std::move(dataPath), isNew) ); auto props = info.get("properties"); @@ -1806,14 +1637,14 @@ arangodb::Result IResearchView::link( std::string error; - if (!ptr->_meta.init(props, error)) { + if (!view->_meta.init(props, error)) { LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) << "failed to initialize iResearch view from definition, error: " << error; return nullptr; } - return std::shared_ptr(std::move(ptr)); + return std::shared_ptr(std::move(view)); } size_t IResearchView::memory() const { @@ -1845,6 +1676,8 @@ size_t IResearchView::memory() const { } void IResearchView::open() { + DBServerLogicalView::open(); + auto* engine = arangodb::EngineSelectorFeature::ENGINE; if (engine) { @@ -2121,15 +1954,6 @@ bool IResearchView::sync(size_t maxMsec /*= 0*/) { return type; } -arangodb::Result IResearchView::updateLogicalProperties( - arangodb::velocypack::Slice const& slice, - bool partialUpdate, - bool doSync -) { - // FIXME remove - return updateProperties(slice, partialUpdate, doSync); -} - void IResearchView::toVelocyPack( velocypack::Builder& result, bool includeProperties, @@ -2157,14 +1981,168 @@ void IResearchView::toVelocyPack( } arangodb::Result IResearchView::updateProperties( - arangodb::velocypack::Slice const& slice, - bool partialUpdate, - bool doSync + const velocypack::Slice &slice, + bool partialUpdate, + bool doSync ) { WRITE_LOCKER(writeLocker, _infoLock); - // the implementation may filter/change/react to the changes - auto res = updatePropertiesImpl(slice, partialUpdate, doSync); + auto* vocbase = this->vocbase(); + + if (!vocbase) { + return arangodb::Result( + TRI_ERROR_INTERNAL, + std::string("failed to find vocbase while updating links for iResearch view '") + std::to_string(id()) + "'" + ); + } + + std::string error; + IResearchViewMeta meta; + IResearchViewMeta::Mask mask; + WriteMutex mutex(_mutex); // '_meta' can be asynchronously read + arangodb::Result res; + + { + SCOPED_LOCK(mutex); + + arangodb::velocypack::Builder originalMetaJson; // required for reverting links on failure + + if (!_meta.json(arangodb::velocypack::ObjectBuilder(&originalMetaJson))) { + return arangodb::Result( + TRI_ERROR_INTERNAL, + std::string("failed to generate json definition while updating iResearch view '") + std::to_string(id()) + "'" + ); + } + + auto& initialMeta = partialUpdate ? _meta : IResearchViewMeta::DEFAULT(); + + if (!meta.init(slice, error, initialMeta, &mask)) { + return arangodb::Result(TRI_ERROR_BAD_PARAMETER, std::move(error)); + } + + // FIXME TODO remove once View::updateProperties(...) will be fixed to write + // the update delta into the WAL marker instead of the full persisted state + // below is a very dangerous hack as it allows multiple links from the same + // collection to point to the same view, thus breaking view data consistency + { + auto* engine = arangodb::EngineSelectorFeature::ENGINE; + + if (engine && engine->inRecovery()) { + arangodb::velocypack::Builder linksBuilder; + + linksBuilder.openObject(); + + // remove links no longer present in incming update + for (auto& cid: _meta._collections) { + if (meta._collections.find(cid) == meta._collections.end()) { + linksBuilder.add( + std::to_string(cid), + arangodb::velocypack::Value(arangodb::velocypack::ValueType::Null) + ); + } + } + + for (auto& cid: meta._collections) { + auto collection = vocbase->lookupCollection(cid); + + if (collection) { + _meta._collections.emplace(cid); + + for (auto& index: collection->getIndexes()) { + if (index && arangodb::Index::TRI_IDX_TYPE_IRESEARCH_LINK == index->type()) { + auto* link = dynamic_cast(index.get()); + + if (link && link->_defaultId == id() && !link->view()) { + arangodb::velocypack::Builder linkBuilder; + bool valid; + + linkBuilder.openObject(); + valid = link->json(linkBuilder, true); + linkBuilder.close(); + + linksBuilder.add( + std::to_string(cid), + arangodb::velocypack::Value(arangodb::velocypack::ValueType::Null) + ); + + if (valid) { + linksBuilder.add(std::to_string(cid), linkBuilder.slice()); + } + } + } + } + } + } + + std::unordered_set collections; + + linksBuilder.close(); + updateLinks(collections, *vocbase, *this, linksBuilder.slice()); + collections.insert(_meta._collections.begin(), _meta._collections.end()); + validateLinks(collections, *vocbase, *this); // remove invalid cids (no such collection or no such link) + _meta._collections = std::move(collections); + } + } + + // reset non-updatable values to match current meta + meta._collections = _meta._collections; + + if (mask._threadsMaxIdle) { + _threadPool.max_idle(meta._threadsMaxIdle); + } + + if (mask._threadsMaxTotal) { + _threadPool.max_threads(meta._threadsMaxTotal); + } + + { + SCOPED_LOCK(_asyncMutex); + _asyncCondition.notify_all(); // trigger reload of timeout settings for async jobs + } + + _meta = std::move(meta); + } + + std::unordered_set collections; + + // update links if requested (on a best-effort basis) + // indexing of collections is done in different threads so no locks can be held and rollback is not possible + // as a result it's also possible for links to be simultaneously modified via a different callflow (e.g. from collections) + if (slice.hasKey(LINKS_FIELD)) { + if (partialUpdate) { + res = updateLinks(collections, *vocbase, *this, slice.get(LINKS_FIELD)); + } else { + arangodb::velocypack::Builder builder; + + builder.openObject(); + + if (!appendLinkRemoval(builder, _meta) + || !mergeSlice(builder, slice.get(LINKS_FIELD))) { + return arangodb::Result( + TRI_ERROR_INTERNAL, + std::string("failed to construct link update directive while updating iResearch view '") + std::to_string(id()) + "'" + ); + } + + builder.close(); + res = updateLinks(collections, *vocbase, *this, builder.slice()); + } + } + + // ........................................................................... + // if an exception occurs below then it would only affect collection linking + // consistency and an update retry would most likely happen + // always re-validate '_collections' because may have had externally triggered + // collection/link drops + // ........................................................................... + { + SCOPED_LOCK(mutex); // '_meta' can be asynchronously read + collections.insert(_meta._collections.begin(), _meta._collections.end()); + validateLinks(collections, *vocbase, *this); // remove invalid cids (no such collection or no such link) + _meta._collections = std::move(collections); + } + + // FIXME TODO to ensure valid recovery remove the original datapath only if the entire, but under lock to prevent double rename if (res.ok()) { res = DBServerLogicalView::updateProperties(slice, partialUpdate, doSync); diff --git a/arangod/IResearch/IResearchView.h b/arangod/IResearch/IResearchView.h index 3de7af8cbe..1ae68d4eea 100644 --- a/arangod/IResearch/IResearchView.h +++ b/arangod/IResearch/IResearchView.h @@ -246,16 +246,6 @@ class IResearchView final: public arangodb::DBServerLogicalView, //////////////////////////////////////////////////////////////////////////////// static arangodb::LogicalDataSource::Type const& type() noexcept; - /////////////////////////////////////////////////////////////////////////////// - /// @brief update the view properties via the LogicalView allowing for tracking - /// update via WAL entries - /////////////////////////////////////////////////////////////////////////////// - arangodb::Result updateLogicalProperties( - arangodb::velocypack::Slice const& slice, - bool partialUpdate, - bool doSync - ); - void toVelocyPack( velocypack::Builder& result, bool includeProperties, @@ -327,15 +317,8 @@ class IResearchView final: public arangodb::DBServerLogicalView, IResearchView( TRI_vocbase_t* vocbase, arangodb::velocypack::Slice const& info, - irs::utf8_path&& persistedPath - ); - - // FIXME remove - void dropImpl(); - arangodb::Result updatePropertiesImpl( - arangodb::velocypack::Slice const& slice, - bool partialUpdate, - bool doSync + irs::utf8_path&& persistedPath, + bool isNew ); /////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/VocBase/LogicalView.cpp b/arangod/VocBase/LogicalView.cpp index f0b3c82bb6..73f102665e 100644 --- a/arangod/VocBase/LogicalView.cpp +++ b/arangod/VocBase/LogicalView.cpp @@ -115,26 +115,16 @@ LogicalView::LogicalView(TRI_vocbase_t* vocbase, VPackSlice const& info) TRI_UpdateTickServer(static_cast(id())); } -/// @brief Persist the connected physical view -/// This should be called AFTER the view is successfully -/// created and only on Single/DBServer -void LogicalView::persistPhysicalView() { - // Coordinators are not allowed to have local views! - TRI_ASSERT(!ServerState::instance()->isCoordinator()); - - // We have not yet persisted this view - StorageEngine* engine = EngineSelectorFeature::ENGINE; - engine->createView(vocbase(), id(), this); -} - // ----------------------------------------------------------------------------- // --SECTION-- DBServerLogicalView // ----------------------------------------------------------------------------- DBServerLogicalView::DBServerLogicalView( TRI_vocbase_t* vocbase, - VPackSlice const& info -) : LogicalView(vocbase, info) { + VPackSlice const& info, + bool isNew +) : LogicalView(vocbase, info), + _isNew(isNew) { } DBServerLogicalView::~DBServerLogicalView() { @@ -145,6 +135,20 @@ DBServerLogicalView::~DBServerLogicalView() { } } +void DBServerLogicalView::open() { + // Coordinators are not allowed to have local views! + TRI_ASSERT(!ServerState::instance()->isCoordinator()); + + if (!_isNew) { + return; + } + + StorageEngine* engine = EngineSelectorFeature::ENGINE; + TRI_ASSERT(engine); + engine->createView(vocbase(), id(), this); + _isNew = false; +} + void DBServerLogicalView::drop() { TRI_ASSERT(!ServerState::instance()->isCoordinator()); StorageEngine* engine = EngineSelectorFeature::ENGINE; diff --git a/arangod/VocBase/LogicalView.h b/arangod/VocBase/LogicalView.h index 1c98664554..f0baf1d1e9 100644 --- a/arangod/VocBase/LogicalView.h +++ b/arangod/VocBase/LogicalView.h @@ -93,12 +93,6 @@ class LogicalView : public LogicalDataSource { bool doSync ) = 0; - //FIXME remove - /// @brief Persist the connected physical view. - /// This should be called AFTER the view is successfully - /// created and only on Sinlge/DBServer - void persistPhysicalView(); - protected: static TRI_voc_cid_t readViewId(velocypack::Slice slice); @@ -132,6 +126,8 @@ class DBServerLogicalView : public LogicalView { public: ~DBServerLogicalView() override; + void open() override; + void drop() override; Result rename( @@ -152,7 +148,14 @@ class DBServerLogicalView : public LogicalView { ) override; protected: - DBServerLogicalView(TRI_vocbase_t* vocbase, velocypack::Slice const& definition); + DBServerLogicalView( + TRI_vocbase_t* vocbase, + velocypack::Slice const& definition, + bool isNew + ); + + private: + bool _isNew; }; // LogicalView } // namespace arangodb diff --git a/arangod/VocBase/vocbase.cpp b/arangod/VocBase/vocbase.cpp index f78f6a245f..50aa90240d 100644 --- a/arangod/VocBase/vocbase.cpp +++ b/arangod/VocBase/vocbase.cpp @@ -314,10 +314,12 @@ bool TRI_vocbase_t::unregisterCollection( auto itr = _dataSourceById.find(collection->id()); if (itr == _dataSourceById.end() - || !std::dynamic_pointer_cast(itr->second)) { + || itr->second->category() != LogicalCollection::category()) { return true; // no such collection } + TRI_ASSERT(std::dynamic_pointer_cast(itr->second)); + // only if we find the collection by its id, we can delete it by name _dataSourceById.erase(itr); @@ -391,10 +393,12 @@ bool TRI_vocbase_t::unregisterView( auto itr = _dataSourceById.find(view->id()); if (itr == _dataSourceById.end() - || !std::dynamic_pointer_cast(itr->second)) { + || itr->second->category() != arangodb::LogicalView::category()) { return true; // no such view } + TRI_ASSERT(std::dynamic_pointer_cast(itr->second)); + // only if we find the collection by its id, we can delete it by name _dataSourceById.erase(itr); @@ -1590,8 +1594,6 @@ std::shared_ptr TRI_vocbase_t::createViewWorker( ); } - // FIXME first check for existence??? - // Try to create a new view. This is not registered yet auto view = viewFactory(*this, parameters, true); @@ -1609,27 +1611,26 @@ std::shared_ptr TRI_vocbase_t::createViewWorker( if (it != _dataSourceByName.end()) { events::CreateView(name, TRI_ERROR_ARANGO_DUPLICATE_NAME); + THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DUPLICATE_NAME); } registerView(basics::ConditionalLocking::DoNotLock, view); try { - // id might have been assigned - id = view->id(); - - // Let's try to persist it. - view->persistPhysicalView(); - // And lets open it. view->open(); events::CreateView(name, TRI_ERROR_NO_ERROR); - return view; } catch (...) { unregisterView(view); throw; } + + // noexcept below + id = view->id(); + + return view; } /// @brief creates a new view from parameter set From e2a6e751eda55230608b39107a25e2f9893bafe4 Mon Sep 17 00:00:00 2001 From: Andrey Abramov Date: Tue, 27 Mar 2018 21:26:21 +0300 Subject: [PATCH 4/5] do not use dynamic_pointer_cast in release --- arangod/IResearch/IResearchView.h | 1 + arangod/VocBase/LogicalView.h | 2 +- arangod/VocBase/vocbase.cpp | 79 +++++++++++++++++++++++-------- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/arangod/IResearch/IResearchView.h b/arangod/IResearch/IResearchView.h index 1ae68d4eea..d37ce3c95c 100644 --- a/arangod/IResearch/IResearchView.h +++ b/arangod/IResearch/IResearchView.h @@ -366,6 +366,7 @@ class IResearchView final: public arangodb::DBServerLogicalView, std::function _trxWriteCallback; // for insert(...)/remove(...) std::atomic _inRecovery; + // FIXME came from "LogicalView", check whether it needs to be there mutable basics::ReadWriteLock _infoLock; // lock protecting the properties }; diff --git a/arangod/VocBase/LogicalView.h b/arangod/VocBase/LogicalView.h index f0baf1d1e9..219621dcf4 100644 --- a/arangod/VocBase/LogicalView.h +++ b/arangod/VocBase/LogicalView.h @@ -99,8 +99,8 @@ class LogicalView : public LogicalDataSource { LogicalView(TRI_vocbase_t* vocbase, velocypack::Slice const& definition); private: + // FIXME seems to be ugly friend struct ::TRI_vocbase_t; - mutable basics::ReadWriteLock _lock; }; // LogicalView diff --git a/arangod/VocBase/vocbase.cpp b/arangod/VocBase/vocbase.cpp index 50aa90240d..d3c7f81653 100644 --- a/arangod/VocBase/vocbase.cpp +++ b/arangod/VocBase/vocbase.cpp @@ -895,12 +895,20 @@ std::vector TRI_vocbase_t::collectionNames() { result.reserve(_dataSourceByName.size()); for (auto& entry: _dataSourceByName) { - auto collection = - std::dynamic_pointer_cast(entry.second); + TRI_ASSERT(entry.second); + + if (entry.second->category() != LogicalCollection::category()) { + continue; + } + +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE + auto view = std::dynamic_pointer_cast(entry.second); + TRI_ASSERT(view); +#else + auto view = std::static_pointer_cast(entry.second); +#endif - if (collection) { result.emplace_back(entry.first); - } } return result; @@ -1337,10 +1345,12 @@ int TRI_vocbase_t::renameView( auto itr1 = _dataSourceByName.find(oldName); if (itr1 == _dataSourceByName.end() - || !std::dynamic_pointer_cast(itr1->second)) { + || arangodb::LogicalView::category() == itr1->second->category()) { return TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND; } + TRI_ASSERT(std::dynamic_pointer_cast(itr1->second)); + _dataSourceByName.emplace(newName, view); _dataSourceByName.erase(oldName); @@ -1446,10 +1456,12 @@ int TRI_vocbase_t::renameCollection( auto itr1 = _dataSourceByName.find(oldName); if (itr1 == _dataSourceByName.end() - || !std::dynamic_pointer_cast(itr1->second)) { + || arangodb::LogicalCollection::category() != itr1->second->category()) { return TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND; } + TRI_ASSERT(std::dynamic_pointer_cast(itr1->second)); + auto* databaseFeature = application_features::ApplicationServer::getFeature("Database"); TRI_ASSERT(databaseFeature); @@ -1519,9 +1531,10 @@ arangodb::LogicalCollection* TRI_vocbase_t::useCollection( auto it = _dataSourceByName.find(name); - if (it != _dataSourceByName.end()) { - collection = - std::dynamic_pointer_cast(it->second).get(); + if (it != _dataSourceByName.end() + && it->second->category() == LogicalCollection::category()) { + TRI_ASSERT(std::dynamic_pointer_cast(it->second)); + collection = static_cast(it->second.get()); } } @@ -1934,12 +1947,20 @@ std::vector> TRI_vocbase_t::views() { views.reserve(_dataSourceById.size()); for (auto& entry: _dataSourceById) { - auto view = - std::dynamic_pointer_cast(entry.second); + TRI_ASSERT(entry.second); - if (view) { - views.emplace_back(view); + if (entry.second->category() != LogicalView::category()) { + continue; } + +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE + auto view = std::dynamic_pointer_cast(entry.second); + TRI_ASSERT(view); +#else + auto view = std::static_pointer_cast(entry.second); +#endif + + views.emplace_back(view); } } @@ -1956,12 +1977,20 @@ void TRI_vocbase_t::processCollections( } } else { for (auto& entry: _dataSourceById) { - auto collection = - std::dynamic_pointer_cast(entry.second); + TRI_ASSERT(entry.second); - if (collection) { - cb(collection.get()); + if (entry.second->category() != LogicalCollection::category()) { + continue; } + +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE + auto collection = std::dynamic_pointer_cast(entry.second); + TRI_ASSERT(collection); +#else + auto collection = std::static_pointer_cast(entry.second); +#endif + + cb(collection.get()); } } } @@ -1984,12 +2013,20 @@ std::vector TRI_vocbase_t::collections( collections.reserve(_dataSourceById.size()); for (auto& entry: _dataSourceById) { - auto collection = - std::dynamic_pointer_cast(entry.second); + TRI_ASSERT(entry.second); - if (collection) { - collections.emplace_back(collection.get()); + if (entry.second->category() != LogicalCollection::category()) { + continue; } + +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE + auto collection = std::dynamic_pointer_cast(entry.second); + TRI_ASSERT(collection); +#else + auto collection = std::static_pointer_cast(entry.second); +#endif + + collections.emplace_back(collection.get()); } } } From 9addef64197ae3a63307c1fba3ecb17a4f5a596a Mon Sep 17 00:00:00 2001 From: Andrey Abramov Date: Wed, 28 Mar 2018 18:45:14 +0300 Subject: [PATCH 5/5] small fixes after review --- arangod/IResearch/IResearchView.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arangod/IResearch/IResearchView.cpp b/arangod/IResearch/IResearchView.cpp index a21cb4f195..e54801088f 100644 --- a/arangod/IResearch/IResearchView.cpp +++ b/arangod/IResearch/IResearchView.cpp @@ -1624,7 +1624,7 @@ arangodb::Result IResearchView::link( dataPath += "-"; dataPath += std::to_string(id); - auto view = std::unique_ptr( + auto view = std::shared_ptr( new IResearchView(&vocbase, info, std::move(dataPath), isNew) ); @@ -1644,7 +1644,7 @@ arangodb::Result IResearchView::link( return nullptr; } - return std::shared_ptr(std::move(view)); + return view; } size_t IResearchView::memory() const { @@ -1981,7 +1981,7 @@ void IResearchView::toVelocyPack( } arangodb::Result IResearchView::updateProperties( - const velocypack::Slice &slice, + velocypack::Slice const& slice, bool partialUpdate, bool doSync ) {