1
0
Fork 0

issue 511.3: remove IResearchViewDBServer and use the IResearchView directly on db-server (#7748)

* issue 511.3: remove IResearchViewDBServer and use the IResearchView directly on db-server

* ensure objectId is set in RocksDBLink
This commit is contained in:
Vasiliy 2018-12-17 21:11:20 +03:00 committed by Andrey Abramov
parent 2846bdc393
commit f1bf5cc9cf
37 changed files with 1168 additions and 1967 deletions

View File

@ -54,7 +54,6 @@ if (USE_IRESEARCH)
IResearch/Containers.cpp IResearch/Containers.h
IResearch/IResearchAnalyzerFeature.cpp IResearch/IResearchAnalyzerFeature.h
IResearch/IResearchCommon.cpp IResearch/IResearchCommon.h
IResearch/IResearchViewDBServer.cpp IResearch/IResearchViewDBServer.h
IResearch/IResearchKludge.cpp IResearch/IResearchKludge.h
IResearch/IResearchLink.cpp IResearch/IResearchLink.h
IResearch/IResearchLinkCoordinator.cpp IResearch/IResearchLinkCoordinator.h

View File

@ -351,15 +351,15 @@ Result ClusterEngine::createView(
}
arangodb::Result ClusterEngine::dropView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) {
return TRI_ERROR_NOT_IMPLEMENTED;
}
void ClusterEngine::destroyView(
TRI_vocbase_t& /*vocbase*/,
LogicalView& /*view*/
TRI_vocbase_t const& /*vocbase*/,
LogicalView const& /*view*/
) noexcept {
// nothing to do here
}
@ -424,4 +424,4 @@ std::unique_ptr<TRI_vocbase_t> ClusterEngine::openExistingDatabase(
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -297,13 +297,13 @@ class ClusterEngine final : public StorageEngine {
}
arangodb::Result dropView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) override;
void destroyView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) noexcept override;
void signalCleanup(TRI_vocbase_t& vocbase) override;
@ -358,4 +358,4 @@ class ClusterEngine final : public StorageEngine {
} // namespace arangodb
#endif
#endif

View File

@ -41,7 +41,6 @@
#include "IResearchRocksDBRecoveryHelper.h"
#include "IResearchView.h"
#include "IResearchViewCoordinator.h"
#include "IResearchViewDBServer.h"
#include "Aql/AqlValue.h"
#include "Aql/AqlFunctionFeature.h"
#include "Aql/Function.h"
@ -289,7 +288,7 @@ void registerViewFactory() {
if (arangodb::ServerState::instance()->isCoordinator()) {
res = viewTypes->emplace(viewType, arangodb::iresearch::IResearchViewCoordinator::factory());
} else if (arangodb::ServerState::instance()->isDBServer()) {
res = viewTypes->emplace(viewType, arangodb::iresearch::IResearchViewDBServer::factory());
res = viewTypes->emplace(viewType, arangodb::iresearch::IResearchView::factory());
} else if (arangodb::ServerState::instance()->isSingleServer()) {
res = viewTypes->emplace(viewType, arangodb::iresearch::IResearchView::factory());
} else {
@ -799,4 +798,4 @@ NS_END // arangodb
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -27,7 +27,7 @@
#include "IResearchLinkHelper.h"
#include "IResearchPrimaryKeyFilter.h"
#include "IResearchView.h"
#include "IResearchViewDBServer.h"
#include "IResearchViewCoordinator.h"
#include "Basics/LocalTaskQueue.h"
#include "Basics/StaticStrings.h"
#include "Cluster/ClusterInfo.h"
@ -626,55 +626,12 @@ arangodb::Result IResearchLink::init(
auto idSlice = definition.get(StaticStrings::ViewIdField);
auto viewId = idSlice.copyString();
auto& vocbase = _collection.vocbase();
auto logicalView = arangodb::ServerState::instance()->isCoordinator()
auto logicalView = arangodb::ServerState::instance()->isClusterRole()
&& arangodb::ClusterInfo::instance()
? arangodb::ClusterInfo::instance()->getView(vocbase.name(), viewId)
: vocbase.lookupView(viewId) // will only contain IResearchView (even for a DBServer)
: vocbase.lookupView(viewId)
;
// creation of link on a DBServer
if (!logicalView && arangodb::ServerState::instance()->isDBServer()) {
auto* ci = ClusterInfo::instance();
if (!ci) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure to find 'ClusterInfo' instance for lookup of link '") + std::to_string(_id) + "'"
);
}
auto logicalWiew = ci->getView(vocbase.name(), viewId);
auto* wiew = LogicalView::cast<IResearchViewDBServer>(logicalWiew.get());
if (wiew) {
// FIXME figure out elegant way of testing for cluster wide LogicalCollection
if (_collection.id() == _collection.planId() && _collection.isAStub()) {
// this is a cluster-wide collection/index/link (per-cid view links have their corresponding collections in vocbase)
auto clusterCol = ci->getCollectionCurrent(
vocbase.name(), std::to_string(_collection.id())
);
if (clusterCol) {
for (auto& entry: clusterCol->errorNum()) {
auto collection = vocbase.lookupCollection(entry.first); // find shard collection
if (collection) {
// ensure the shard collection is registered with the cluster-wide view
// required from creating snapshots for per-cid views loaded from WAL
// only register existing per-cid view instances, do not create new per-cid view
// instances since they will be created/registered by their per-cid links just below
wiew->ensure(collection->id(), false);
}
}
}
return arangodb::Result(); // leave '_view' uninitialized to mark the index as unloaded/unusable
}
logicalView = wiew->ensure(_collection.id()); // repoint LogicalView at the per-cid instance
}
}
if (!logicalView
|| arangodb::iresearch::DATA_SOURCE_TYPE != logicalView->type()) {
return arangodb::Result(
@ -683,15 +640,8 @@ arangodb::Result IResearchLink::init(
);
}
if (!arangodb::ServerState::instance()->isCoordinator()) { // link on coordinator does not have a data-store
auto* dbServerView = dynamic_cast<IResearchViewDBServer*>(logicalView.get());
// dbserver has both IResearchViewDBServer and IResearchView instances
auto* view = LogicalView::cast<IResearchView>(
dbServerView
? dbServerView->ensure(_collection.id()).get()
: logicalView.get()
);
if (arangodb::ServerState::instance()->isCoordinator()) {
auto* view = LogicalView::cast<IResearchViewCoordinator>(logicalView.get());
if (!view) {
return arangodb::Result(
@ -700,19 +650,64 @@ arangodb::Result IResearchLink::init(
);
}
auto res = initDataStore(*view);
if (!res.ok()) {
return res;
}
if (!view->link(_asyncSelf)) {
unload(); // unlock the directory
if (!view->emplace(_collection.id(), _collection.name(), definition)) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failed to link with view '") + view->name() + "' while initializing link '" + std::to_string(_id) + "'"
);
}
} else {
auto* view = LogicalView::cast<IResearchView>(logicalView.get());
if (!view) {
return arangodb::Result(
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
std::string("error finding view: '") + viewId + "' for link '" + std::to_string(_id) + "'"
);
}
if (arangodb::ServerState::instance()->isDBServer()
&& _collection.id() == _collection.planId()
&& _collection.isAStub()) { // cluster cluster-wide link
auto shardIds = _collection.shardIds();
// go through all shard IDs of the collection and try to link any links
// missing links will be populated when they are created in the per-shard collection
if (shardIds) {
for (auto& entry: *shardIds) {
auto collection = vocbase.lookupCollection(entry.first); // per-shard collections are always in 'vocbase'
if (!collection) {
continue; // missing collection should be created after Plan becomes Current
}
auto link = IResearchLinkHelper::find(*collection, *view);
if (link && !view->link(link->self())) {
unload(); // unlock the directory
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failed to link with view '") + view->name() + "' while initializing link '" + std::to_string(_id) + "', collection '" + collection->name() + "'"
);
}
}
}
} else if (arangodb::ServerState::instance()->isSingleServer() // single-server link
|| arangodb::ServerState::instance()->isDBServer()) { // cluster per-shard link
auto res = initDataStore(*view);
if (!res.ok()) {
return res;
}
if (!view->link(_asyncSelf)) {
unload(); // unlock the directory
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failed to link with view '") + view->name() + "' while initializing link '" + std::to_string(_id) + "'"
);
}
}
}
const_cast<std::string&>(_viewGuid) = logicalView->guid(); // ensue that this is a GUID (required by operator==(IResearchView))
@ -1173,12 +1168,12 @@ arangodb::Result IResearchLink::unload() {
}
std::shared_ptr<IResearchView> IResearchLink::view() const {
// FIXME TODO change to lookup in CollectionNameResolver once per-shard views are removed
// IResearchView instances are in ClusterInfo for coordinator and db-server
return std::dynamic_pointer_cast<IResearchView>(
arangodb::ServerState::instance()->isCoordinator()
arangodb::ServerState::instance()->isClusterRole()
&& arangodb::ClusterInfo::instance()
? arangodb::ClusterInfo::instance()->getView(_collection.vocbase().name(), _viewGuid)
: _collection.vocbase().lookupView(_viewGuid) // always look up in vocbase (single server or cluster per-shard view)
: _collection.vocbase().lookupView(_viewGuid)
);
}

View File

@ -181,18 +181,9 @@ arangodb::Result IResearchLinkCoordinator::init(
);
}
if (!view->emplace(Index::collection().id(), Index::collection().name(), definition)) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("error emplacing link to collection '") + Index::collection().name() + "' into arangosearch view '" + viewId + "' link '" + std::to_string(Index::id()) + "'"
);
}
_view = view;
IResearchLink::init(definition);
return arangodb::Result();
return IResearchLink::init(definition);
}
bool IResearchLinkCoordinator::matchesDefinition(VPackSlice const& slice) const {

View File

@ -29,7 +29,6 @@
#include "IResearchLinkMeta.h"
#include "IResearchView.h"
#include "IResearchViewCoordinator.h"
#include "IResearchViewDBServer.h"
#include "VelocyPackHelper.h"
#include "Basics/StaticStrings.h"
#include "Logger/Logger.h"
@ -681,19 +680,6 @@ namespace iresearch {
);
}
auto* dbServerView = dynamic_cast<IResearchViewDBServer*>(&view);
// dbserver has both IResearchViewDBServer and IResearchView instances
if (dbServerView) {
return modifyLinks<IResearchViewDBServer>(
modified,
vocbase,
*dbServerView,
links,
stale
);
}
return modifyLinks<IResearchView>(
modified,
vocbase,

View File

@ -149,6 +149,11 @@ void IResearchRocksDBLink::toVelocyPack(
));
}
if (arangodb::Index::hasFlag(flags, arangodb::Index::Serialize::ObjectId)) {
TRI_ASSERT(_objectId != 0); // If we store it, it cannot be 0
builder.add("objectId", VPackValue(std::to_string(_objectId)));
}
if (arangodb::Index::hasFlag(flags, arangodb::Index::Serialize::Figures)) {
VPackBuilder figuresBuilder;

View File

@ -28,6 +28,7 @@
#include "VelocyPackHelper.h"
#include "Aql/AstNode.h"
#include "Aql/PlanCache.h"
#include "Aql/QueryCache.h"
#include "Basics/StaticStrings.h"
#include "StorageEngine/EngineSelectorFeature.h"
@ -70,24 +71,50 @@ class ViewTrxState final
return *(_subReaders[subReaderId]);
}
void add(arangodb::iresearch::IResearchLink::Snapshot&& snapshot);
void clear() noexcept { _subReaders.clear(); _snapshots.clear(); }
void add(
TRI_voc_cid_t cid,
arangodb::iresearch::IResearchLink::Snapshot&& snapshot
);
void clear() noexcept {
_collections.clear();
_subReaders.clear();
_snapshots.clear();
}
template <typename Itr>
bool equalCollections(Itr begin, Itr end) {
size_t count = 0;
for (; begin != end; ++count, ++begin) {
if (_collections.find(*begin) == _collections.end()
|| count > _collections.size()) {
return false;
}
}
return _collections.size() == count;
}
virtual uint64_t docs_count() const override;
virtual uint64_t live_docs_count() const override;
virtual size_t size() const noexcept override { return _subReaders.size(); }
private:
std::unordered_set<TRI_voc_cid_t> _collections;
std::vector<arangodb::iresearch::IResearchLink::Snapshot> _snapshots; // prevent data-store deallocation (lock @ AsyncSelf)
std::vector<irs::sub_reader const*> _subReaders;
};
void ViewTrxState::add(
TRI_voc_cid_t cid,
arangodb::iresearch::IResearchLink::Snapshot&& snapshot
) {
for(auto& entry: static_cast<irs::index_reader const&>(snapshot)) {
_subReaders.emplace_back(&entry);
}
_collections.emplace(cid);
_snapshots.emplace_back(std::move(snapshot));
}
@ -132,123 +159,6 @@ inline arangodb::FlushFeature* getFlushFeature() noexcept {
>("Flush");
}
////////////////////////////////////////////////////////////////////////////////
/// @brief persist view definition to the storage engine
/// if in-recovery then register a post-recovery lambda for persistence
/// @return success
////////////////////////////////////////////////////////////////////////////////
arangodb::Result persistProperties(
arangodb::LogicalView const& view,
arangodb::iresearch::IResearchView::AsyncViewPtr const& asyncSelf
) {
auto* engine = arangodb::EngineSelectorFeature::ENGINE;
if (!engine) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure to get storage engine while persisting definition for LogicalView '") + view.name() + "'"
);
}
if (!engine->inRecovery()) {
// change view throws exception on error
try {
engine->changeView(view.vocbase(), view, true);
} catch (arangodb::basics::Exception& e) {
IR_LOG_EXCEPTION();
return arangodb::Result(
e.code(),
std::string("caught exception during persistance of properties for arangosearch View '") + view.name() + "': " + e.what()
);
} catch (std::exception const& e) {
IR_LOG_EXCEPTION();
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("caught exception during persistance of properties for arangosearch View '") + view.name() + "': " + e.what()
);
} catch (...) {
IR_LOG_EXCEPTION();
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("caught exception during persistance of properties for arangosearch View '") + view.name() + "'"
);
}
return arangodb::Result();
}
auto* feature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
if (!feature) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure to get 'Database' feature while persisting definition for LogicalView '") + view.name() + "'"
);
}
return feature->registerPostRecoveryCallback(
[&view, asyncSelf]()->arangodb::Result {
auto* engine = arangodb::EngineSelectorFeature::ENGINE;
if (!engine) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure to get storage engine while persisting definition for LogicalView")
);
}
if (!asyncSelf) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("invalid view instance passed while persisting definition for LogicalView")
);
}
SCOPED_LOCK(asyncSelf->mutex());
if (!asyncSelf->get()) {
LOG_TOPIC(INFO, arangodb::iresearch::TOPIC)
<< "no view instance available while persisting definition for LogicalView";
return arangodb::Result(); // nothing to persist, view allready deallocated
}
// change view throws exception on error
try {
engine->changeView(view.vocbase(), view, true);
} catch (arangodb::basics::Exception& e) {
IR_LOG_EXCEPTION();
return arangodb::Result(
e.code(),
std::string("caught exception during persistance of properties for arangosearch View '") + view.name() + "': " + e.what()
);
} catch (std::exception const& e) {
IR_LOG_EXCEPTION();
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("caught exception during persistance of properties for arangosearch View '") + view.name() + "': " + e.what()
);
} catch (...) {
IR_LOG_EXCEPTION();
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("caught exception during persistance of properties for arangosearch View '") + view.name() + "'"
);
}
return arangodb::Result();
}
);
}
}
namespace arangodb {
@ -278,12 +188,20 @@ struct IResearchView::ViewFactory: public arangodb::ViewFactory {
return res;
}
TRI_set_errno(TRI_ERROR_NO_ERROR); // reset before calling createView(...)
auto impl = vocbase.createView(definition);
arangodb::LogicalView::ptr impl;
res = arangodb::ServerState::instance()->isSingleServer()
? arangodb::LogicalViewHelperStorageEngine::construct(impl, vocbase, definition)
: arangodb::LogicalViewHelperClusterInfo::construct(impl, vocbase, definition)
;
if (!res.ok()) {
return res;
}
if (!impl) {
return arangodb::Result(
TRI_ERROR_NO_ERROR == TRI_errno() ? TRI_ERROR_INTERNAL : TRI_errno(),
TRI_ERROR_INTERNAL,
std::string("failure during instantiation while creating arangosearch View in database '") + vocbase.name() + "'"
);
}
@ -375,7 +293,7 @@ IResearchView::IResearchView(
TRI_vocbase_t& vocbase,
arangodb::velocypack::Slice const& info,
uint64_t planVersion
): LogicalViewStorageEngine(vocbase, info, planVersion),
): LogicalView(vocbase, info, planVersion),
FlushTransaction(toString(*this)),
_asyncFeature(nullptr),
_asyncSelf(irs::memory::make_unique<AsyncViewPtr::element_type>(this)),
@ -487,7 +405,8 @@ IResearchView::IResearchView(
SCOPED_LOCK(self->mutex());
auto* view = self->get();
if (view) {
// populate snapshot when view is registred with a transaction on single-server
if (view && arangodb::ServerState::instance()->isSingleServer()) {
view->snapshot(trx, IResearchView::Snapshot::FindOrCreate);
}
};
@ -498,12 +417,31 @@ IResearchView::~IResearchView() {
updateProperties(_meta); // trigger reload of settings for async jobs
_asyncSelf->reset(); // the view is being deallocated, its use is no longer valid (wait for all the view users to finish)
_flushCallback.reset(); // unregister flush callback from flush thread
if (arangodb::ServerState::instance()->isSingleServer()) {
arangodb::LogicalViewHelperStorageEngine::destruct(*this); // cleanup of the storage engine
}
}
arangodb::Result IResearchView::appendVelocyPackDetailed(
arangodb::Result IResearchView::appendVelocyPackImpl(
arangodb::velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const {
if (forPersistence && arangodb::ServerState::instance()->isSingleServer()) {
auto res = arangodb::LogicalViewHelperStorageEngine::properties(
builder, *this
);
if (!res.ok()) {
return res;
}
}
if (!detailed) {
return arangodb::Result(); // nothing more to output
}
if (!builder.isOpenObject()) {
return arangodb::Result(TRI_ERROR_BAD_PARAMETER);
}
@ -773,7 +711,10 @@ arangodb::Result IResearchView::dropImpl() {
);
}
return arangodb::Result();
return arangodb::ServerState::instance()->isSingleServer()
? arangodb::LogicalViewHelperStorageEngine::drop(*this) // single-server additionaly requires removal from the StorageEngine
: arangodb::Result()
;
}
/*static*/ arangodb::ViewFactory const& IResearchView::factory() {
@ -794,7 +735,8 @@ bool IResearchView::link(AsyncLinkPtr const& link) {
if (itr == _links.end()) {
_links.emplace(cid, link);
} else if (ServerState::instance()->isSingleServer() && !itr->second) {
} else if (arangodb::ServerState::instance()->isSingleServer()
&& !itr->second) {
_links[cid] = link;
return true; // single-server persisted cid placeholder substituted with actual link
@ -806,38 +748,18 @@ bool IResearchView::link(AsyncLinkPtr const& link) {
return false; // link already present
}
try {
auto res = persistProperties(*this, _asyncSelf);
auto res = arangodb::ServerState::instance()->isSingleServer()
? arangodb::LogicalViewHelperStorageEngine::properties(*this)
: arangodb::Result()
;
if (!res.ok()) {
_links.erase(cid); // undo meta modification
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "failed to persist logical view while emplacing collection '" << cid
<< "' into arangosearch View '" << name() << "': " << res.errorMessage();
if (!res.ok()) {
_links.erase(cid); // undo meta modification
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "failed to persist logical view while emplacing collection '" << cid
<< "' into arangosearch View '" << name() << "': " << res.errorMessage();
return false;
}
} catch (arangodb::basics::Exception& e) {
_links.erase(cid); // undo meta modification
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "caught exception during persisting of logical view while emplacing collection ' " << cid
<< "' into arangosearch View '" << name() << "': " << e.code() << " " << e.what();
IR_LOG_EXCEPTION();
throw;
} catch (std::exception const& e) {
_links.erase(cid); // undo meta modification
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "caught exception during persisting of logical view while emplacing collection ' " << cid
<< "' into arangosearch View '" << name() << "': " << e.what();
IR_LOG_EXCEPTION();
throw;
} catch (...) {
_links.erase(cid); // undo meta modification
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "caught exception during persisting of logical view while emplacing collection ' " << cid
<< "' into arangosearch View '" << name() << "'";
IR_LOG_EXCEPTION();
throw;
return false;
}
return true;
@ -936,9 +858,36 @@ void IResearchView::open() {
}
}
arangodb::Result IResearchView::properties(
arangodb::velocypack::Slice const& properties,
bool partialUpdate
) {
auto res = updateProperties(properties, partialUpdate);
if (!res.ok()) {
return res;
}
arangodb::aql::PlanCache::instance()->invalidate(&vocbase());
arangodb::aql::QueryCache::instance()->invalidate(&vocbase());
return arangodb::ServerState::instance()->isSingleServer()
? arangodb::LogicalViewHelperStorageEngine::properties(*this)
: arangodb::LogicalViewHelperClusterInfo::properties(*this)
;
}
arangodb::Result IResearchView::renameImpl(std::string const& oldName) {
return arangodb::ServerState::instance()->isSingleServer()
? arangodb::LogicalViewHelperStorageEngine::rename(*this, oldName)
: arangodb::LogicalViewHelperClusterInfo::rename(*this, oldName)
;
}
irs::index_reader const* IResearchView::snapshot(
transaction::Methods& trx,
IResearchView::Snapshot mode /*= IResearchView::Snapshot::Find*/
IResearchView::Snapshot mode /*= IResearchView::Snapshot::Find*/,
std::unordered_set<TRI_voc_cid_t> const* shards /*= nullptr*/
) const {
if (!trx.state()) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
@ -947,6 +896,16 @@ irs::index_reader const* IResearchView::snapshot(
return nullptr;
}
std::unordered_set<TRI_voc_cid_t> collections; // use set to avoid duplicate iteration of same link
if (shards) { // add requested shards
collections = *shards;
} else { // add all known shards
for (auto& entry: _links) {
collections.emplace(entry.first);
}
}
auto& state = *(trx.state());
auto* key = this;
@ -959,10 +918,11 @@ irs::index_reader const* IResearchView::snapshot(
switch (mode) {
case Snapshot::Find:
return ctx;
return ctx && ctx->equalCollections(collections.begin(), collections.end())
? ctx : nullptr; // ensure same collections
case Snapshot::FindOrCreate:
if (ctx) {
return ctx;
if (ctx && ctx->equalCollections(collections.begin(), collections.end())) {
return ctx; // ensure same collections
}
break;
case Snapshot::SyncAndReplace: {
@ -1001,10 +961,11 @@ irs::index_reader const* IResearchView::snapshot(
SCOPED_LOCK(mutex);
try {
// collect snapshots from all known links
for (auto& entry: _links) {
auto cid = entry.first;
auto* link = entry.second ? entry.second->get() : nullptr; // do not need to lock link since collection is part of the transaction
// collect snapshots from all requested links
for (auto& cid: collections) {
auto itr = _links.find(cid);
auto* link =
itr != _links.end() && itr->second ? itr->second->get() : nullptr; // do not need to lock link since collection is part of the transaction
if (!link) {
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
@ -1024,7 +985,7 @@ irs::index_reader const* IResearchView::snapshot(
return nullptr; // skip failed readers
}
ctx->add(std::move(snapshot));
ctx->add(cid, std::move(snapshot));
}
} catch (arangodb::basics::Exception& e) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
@ -1063,17 +1024,18 @@ arangodb::Result IResearchView::unlink(TRI_voc_cid_t cid) noexcept {
_links.erase(itr);
try {
auto res = persistProperties(*this, _asyncSelf);
auto res = arangodb::ServerState::instance()->isSingleServer()
? arangodb::LogicalViewHelperStorageEngine::properties(*this)
: arangodb::Result()
;
if (!res.ok()) {
_links.swap(links); // restore original collections
return res;
}
} catch (...) {
if (!res.ok()) {
_links.swap(links); // restore original collections
throw;
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "failed to persist logical view while unlinking collection '" << cid
<< "' from arangosearch view '" << name() << "': " << res.errorMessage();
return res;
}
} catch (arangodb::basics::Exception const& e) {
return arangodb::Result(
@ -1350,8 +1312,8 @@ void IResearchView::verifyKnownCollections() {
++itr;
}
if (modified) {
persistProperties(*this, _asyncSelf);
if (modified && arangodb::ServerState::instance()->isSingleServer()) {
arangodb::LogicalViewHelperStorageEngine::properties(*this);
}
}

View File

@ -101,7 +101,7 @@ class AsyncMeta: public IResearchViewMeta {
/// the IResearchLink or IResearchViewBlock
///////////////////////////////////////////////////////////////////////////////
class IResearchView final
: public arangodb::LogicalViewStorageEngine,
: public arangodb::LogicalView,
public arangodb::FlushTransaction {
typedef std::shared_ptr<TypedResourceMutex<IResearchLink>> AsyncLinkPtr;
public:
@ -168,7 +168,20 @@ class IResearchView final
///////////////////////////////////////////////////////////////////////////////
void open() override;
//////////////////////////////////////////////////////////////////////////////
/// @brief updates properties of an existing view
//////////////////////////////////////////////////////////////////////////////
using LogicalDataSource::properties;
virtual arangodb::Result properties(
arangodb::velocypack::Slice const& properties,
bool partialUpdate
) override final;
////////////////////////////////////////////////////////////////////////////////
/// @param shards the list of shard to restrict the snaphost to
/// nullptr == use all registered links
/// !nullptr && shard not registred then return nullptr
/// if mode == Find && list found doesn't match then return nullptr
/// @return pointer to an index reader containing the datastore record snapshot
/// associated with 'state'
/// (nullptr == no view snapshot associated with the specified state)
@ -176,7 +189,8 @@ class IResearchView final
////////////////////////////////////////////////////////////////////////////////
irs::index_reader const* snapshot(
transaction::Methods& trx,
Snapshot mode = Snapshot::Find
Snapshot mode = Snapshot::Find,
std::unordered_set<TRI_voc_cid_t> const* shards = nullptr
) const;
//////////////////////////////////////////////////////////////////////////////
@ -186,11 +200,6 @@ class IResearchView final
//////////////////////////////////////////////////////////////////////////////
arangodb::Result unlink(TRI_voc_cid_t cid) noexcept;
//////////////////////////////////////////////////////////////////////////////
/// @brief updates properties of an existing view
//////////////////////////////////////////////////////////////////////////////
arangodb::Result updateProperties(std::shared_ptr<AsyncMeta> const& meta); // nullptr == TRI_ERROR_BAD_PARAMETER
///////////////////////////////////////////////////////////////////////////////
/// @brief visit all collection IDs that were added to the view
/// @return 'visitor' success
@ -203,8 +212,9 @@ class IResearchView final
/// @brief fill and return a JSON description of a IResearchView object
/// only fields describing the view itself, not 'link' descriptions
//////////////////////////////////////////////////////////////////////////////
virtual arangodb::Result appendVelocyPackDetailed(
virtual arangodb::Result appendVelocyPackImpl(
arangodb::velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const override;
@ -214,12 +224,10 @@ class IResearchView final
arangodb::Result dropImpl() override;
//////////////////////////////////////////////////////////////////////////////
/// @brief called when a view's properties are updated (i.e. delta-modified)
/// @brief renames implementation-specific parts of an existing view
/// including persistance of properties
//////////////////////////////////////////////////////////////////////////////
arangodb::Result updateProperties(
arangodb::velocypack::Slice const& slice,
bool partialUpdate
) override;
arangodb::Result renameImpl(std::string const& oldName) override;
private:
struct ViewFactory; // forward declaration
@ -259,6 +267,20 @@ class IResearchView final
std::function<void(arangodb::transaction::Methods& trx, arangodb::transaction::Status status)> _trxCallback; // for snapshot(...)
std::atomic<bool> _asyncTerminate; // trigger termination of long-running async jobs
std::atomic<bool> _inRecovery;
//////////////////////////////////////////////////////////////////////////////
/// @brief updates properties of an existing view
//////////////////////////////////////////////////////////////////////////////
// FIXME TODO does this need to be public?
arangodb::Result updateProperties(std::shared_ptr<AsyncMeta> const& meta); // nullptr == TRI_ERROR_BAD_PARAMETER
//////////////////////////////////////////////////////////////////////////////
/// @brief called when a view's properties are updated (i.e. delta-modified)
//////////////////////////////////////////////////////////////////////////////
arangodb::Result updateProperties(
arangodb::velocypack::Slice const& slice,
bool partialUpdate
);
};
} // iresearch

View File

@ -86,44 +86,12 @@ struct IResearchViewCoordinator::ViewFactory: public arangodb::ViewFactory {
arangodb::LogicalView::ptr impl;
res = instantiate(impl, vocbase, definition, 0);
if (!res.ok()) {
return res;
}
if (!impl) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure during instantiation while creating arangosearch View in database '") + vocbase.name() + "'"
);
}
arangodb::velocypack::Builder builder;
builder.openObject();
res = impl->properties(builder, true, true); // include links so that Agency will always have a full definition
if (!res.ok()) {
return res;
}
builder.close();
std::string error;
auto resNum = ci->createViewCoordinator(
vocbase.name(), std::to_string(impl->id()), builder.slice(), error
res = arangodb::LogicalViewHelperClusterInfo::construct(
impl, vocbase, definition
);
if (TRI_ERROR_NO_ERROR != resNum) {
if (error.empty()) {
error = TRI_errno_string(resNum);
}
return arangodb::Result(
resNum,
std::string("failure during ClusterInfo persistance of created view while creating arangosearch View in database '") + vocbase.name() + "', error: " + error
);
if (!res.ok()) {
return res;
}
// create links on a best-effor basis
@ -188,10 +156,29 @@ struct IResearchViewCoordinator::ViewFactory: public arangodb::ViewFactory {
}
};
arangodb::Result IResearchViewCoordinator::appendVelocyPackDetailed(
arangodb::velocypack::Builder& builder,
bool forPersistence
IResearchViewCoordinator::~IResearchViewCoordinator() {
arangodb::LogicalViewHelperClusterInfo::destruct(*this); // cleanup of the storage engine
}
arangodb::Result IResearchViewCoordinator::appendVelocyPackImpl(
arangodb::velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const {
if (forPersistence) {
auto res = arangodb::LogicalViewHelperClusterInfo::properties(
builder, *this
);
if (!res.ok()) {
return res;
}
}
if (!detailed) {
return arangodb::Result(); // nothing more to output
}
if (!builder.isOpenObject()) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
@ -328,6 +315,12 @@ bool IResearchViewCoordinator::emplace(
return factory;
}
arangodb::Result IResearchViewCoordinator::renameImpl(
std::string const& oldName
) {
return arangodb::LogicalViewHelperClusterInfo::rename(*this, oldName);
}
arangodb::Result IResearchViewCoordinator::unlink(TRI_voc_cid_t cid) noexcept {
return arangodb::Result(); // NOOP since no internal store
}
@ -336,7 +329,7 @@ IResearchViewCoordinator::IResearchViewCoordinator(
TRI_vocbase_t& vocbase,
velocypack::Slice info,
uint64_t planVersion
) : LogicalViewClusterInfo(vocbase, info, planVersion) {
) : LogicalView(vocbase, info, planVersion) {
TRI_ASSERT(ServerState::instance()->isCoordinator());
}
@ -416,21 +409,13 @@ arangodb::Result IResearchViewCoordinator::properties(
// only trigger persisting of properties if they have changed
if (_meta != meta) {
arangodb::velocypack::Builder builder;
auto oldMeta = std::move(_meta);
builder.openObject();
meta.json(builder);
_meta = std::move(meta); // update meta for persistence
auto result = properties(builder, false, true);
auto result = arangodb::LogicalViewHelperClusterInfo::properties(*this);
if (!result.ok()) {
return result;
}
builder.close();
result = engine->setViewPropertiesCoordinator(
vocbase().name(), std::to_string(id()), builder.slice()
);
_meta = std::move(oldMeta); // restore meta
if (!result.ok()) {
return result;
@ -551,7 +536,7 @@ Result IResearchViewCoordinator::dropImpl() {
}
}
return {};
return arangodb::LogicalViewHelperClusterInfo::drop(*this);
}
} // iresearch

View File

@ -44,8 +44,9 @@ namespace iresearch {
/// @brief an abstraction over the distributed IResearch index implementing the
/// LogicalView interface
///////////////////////////////////////////////////////////////////////////////
class IResearchViewCoordinator final : public arangodb::LogicalViewClusterInfo {
class IResearchViewCoordinator final: public arangodb::LogicalView {
public:
virtual ~IResearchViewCoordinator();
////////////////////////////////////////////////////////////////////////////////
/// @brief acquire locks on the specified 'cid' during read-transactions
@ -89,13 +90,16 @@ class IResearchViewCoordinator final : public arangodb::LogicalViewClusterInfo {
protected:
virtual Result appendVelocyPackDetailed(
arangodb::velocypack::Builder& builder,
bool forPersistence
virtual Result appendVelocyPackImpl(
arangodb::velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const override;
virtual arangodb::Result dropImpl() override;
arangodb::Result renameImpl(std::string const& oldName) override;
private:
struct ViewFactory; // forward declaration

View File

@ -1,774 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// 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
////////////////////////////////////////////////////////////////////////////////
#include "IResearchCommon.h"
#include "IResearchDocument.h"
#include "IResearchFeature.h"
#include "IResearchLinkHelper.h"
#include "IResearchView.h"
#include "IResearchViewDBServer.h"
#include "VelocyPackHelper.h"
#include "Basics/StaticStrings.h"
#include "Cluster/ClusterInfo.h"
#include "Logger/LogMacros.h"
#include "RestServer/DatabasePathFeature.h"
#include "RestServer/ViewTypesFeature.h"
#include "StorageEngine/TransactionState.h"
#include "Transaction/Methods.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/vocbase.h"
namespace {
typedef irs::async_utils::read_write_mutex::read_mutex ReadMutex;
typedef irs::async_utils::read_write_mutex::write_mutex WriteMutex;
////////////////////////////////////////////////////////////////////////////////
/// @brief the view name prefix of per-cid view instances
////////////////////////////////////////////////////////////////////////////////
std::string const VIEW_NAME_PREFIX("_iresearch_");
////////////////////////////////////////////////////////////////////////////////
/// @brief index reader implementation over multiple irs::index_reader
////////////////////////////////////////////////////////////////////////////////
class CompoundReader final: public irs::index_reader {
public:
irs::sub_reader const& operator[](
size_t subReaderId
) const noexcept override {
TRI_ASSERT(subReaderId < _subReaders.size());
return *(_subReaders[subReaderId]);
}
void add(irs::index_reader const& reader) {
for(auto& entry: reader) {
_subReaders.emplace_back(&entry);
}
}
void clear() noexcept { _subReaders.clear(); }
virtual uint64_t docs_count() const override;
virtual uint64_t live_docs_count() const override;
virtual size_t size() const noexcept override { return _subReaders.size(); }
private:
std::vector<irs::sub_reader const*> _subReaders;
};
uint64_t CompoundReader::docs_count() const {
uint64_t count = 0;
for (auto& entry: _subReaders) {
count += entry->docs_count();
}
return count;
}
uint64_t CompoundReader::live_docs_count() const {
uint64_t count = 0;
for (auto& entry: _subReaders) {
count += entry->live_docs_count();
}
return count;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief the container storing the view state for a given TransactionState
/// @note it is assumed that DBServer ViewState resides in the same
/// TransactionState as the IResearchView ViewState, therefore a separate
/// lock is not required to be held by the DBServer CompoundReader
////////////////////////////////////////////////////////////////////////////////
struct ViewState: public arangodb::TransactionState::Cookie {
CompoundReader _snapshot;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief generate the name used for the per-cid views
/// must be unique to avoid view collisions in vocbase
////////////////////////////////////////////////////////////////////////////////
std::string generateName(TRI_voc_cid_t viewId, TRI_voc_cid_t collectionId) {
return VIEW_NAME_PREFIX
+ std::to_string(collectionId)
+ "_" + std::to_string(viewId)
;
}
}
namespace arangodb {
namespace iresearch {
////////////////////////////////////////////////////////////////////////////////
/// @brief IResearchView-specific implementation of a ViewFactory
////////////////////////////////////////////////////////////////////////////////
struct IResearchViewDBServer::ViewFactory: public arangodb::ViewFactory {
virtual arangodb::Result create(
arangodb::LogicalView::ptr& view,
TRI_vocbase_t& vocbase,
arangodb::velocypack::Slice const& definition
) const override {
auto* ci = ClusterInfo::instance();
if (!ci) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure to find 'ClusterInfo' instance while creating arangosearch View in database '") + vocbase.name() + "'"
);
}
arangodb::LogicalView::ptr impl;
auto res = instantiate(impl, vocbase, definition, 0);
if (!res.ok()) {
return res;
}
if (!impl) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure during instantiation while creating arangosearch View in database '") + vocbase.name() + "'"
);
}
arangodb::velocypack::Builder builder;
builder.openObject();
res = impl->properties(builder, true, true); // include links so that Agency will always have a full definition
if (!res.ok()) {
return res;
}
builder.close();
std::string error;
auto resNum = ci->createViewCoordinator(
vocbase.name(), std::to_string(impl->id()), builder.slice(), error
);
if (TRI_ERROR_NO_ERROR != resNum) {
if (error.empty()) {
error = TRI_errno_string(resNum);
}
return arangodb::Result(
resNum,
std::string("failure during ClusterInfo persistance of created view while creating arangosearch View in database '") + vocbase.name() + "', error: " + error
);
}
// NOTE: link creation is ignored since on the db-server links are created
// by their LogicalCollections themselves
view = ci->getView(vocbase.name(), std::to_string(impl->id())); // refresh view from Agency
if (view) {
view->open(); // open view to match the behaviour in StorageEngine::openExistingDatabase(...) and original behaviour of TRI_vocbase_t::createView(...)
}
return arangodb::Result();
}
virtual arangodb::Result instantiate(
arangodb::LogicalView::ptr& view,
TRI_vocbase_t& vocbase,
arangodb::velocypack::Slice const& definition,
uint64_t planVersion
) const override {
irs::string_ref name;
bool seen;
if (!getString(name, definition, arangodb::StaticStrings::DataSourceName, seen, irs::string_ref::EMPTY)
|| !seen) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
std::string("definition supplied without a 'name' while instantiating arangosearch View in database '") + vocbase.name() + "'"
);
}
// not a per-cid view instance (get here from ClusterInfo)
if (!irs::starts_with(name, VIEW_NAME_PREFIX)) {
auto* feature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabasePathFeature
>("DatabasePath");
if (!feature) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure to find feature 'DatabasePath' while constructing arangosearch View in database '") + vocbase.name() + "'"
);
}
auto* ci = ClusterInfo::instance();
if (!ci) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure to find 'ClusterInfo' instance while constructing arangosearch View in database '") + vocbase.name() + "'"
);
}
std::string error;
auto meta = std::make_shared<AsyncMeta>();
if (!meta->init(definition, error)) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
error.empty()
? (std::string("failed to initialize arangosearch View '") + static_cast<std::string>(name) + "' from definition: " + definition.toString())
: (std::string("failed to initialize arangosearch View '") + static_cast<std::string>(name) + "' from definition, error in attribute '" + error + "': " + definition.toString())
);
}
view = std::shared_ptr<IResearchViewDBServer>(
new IResearchViewDBServer(vocbase, definition, *feature, planVersion, std::move(meta))
);
return arangodb::Result();
}
// .........................................................................
// a per-cid view instance
// get here only from StorageEngine startup or WAL recovery
// .........................................................................
view = vocbase.lookupView(name);
if (view) {
return arangodb::Result(); // resuse view from vocbase
}
// no view for shard
arangodb::LogicalView::ptr impl;
auto res = IResearchView::factory().instantiate(
impl, vocbase, definition, planVersion
);
if (!res.ok()) {
return res;
}
if (!impl) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure during instantiation while creating an arangosearch View '") + std::string(name) + "' in database '" + vocbase.name() + "'"
);
}
// a wrapper to remove the view from vocbase if it no longer has any links
// hold a reference to the original view in the deleter so that the view is
// still valid for the duration of the pointer wrapper
view = std::shared_ptr<arangodb::LogicalView>(
impl.get(),
[impl] (arangodb::LogicalView*) noexcept -> void {
auto& vocbase = impl->vocbase();
// suppress any errors in destructor
try {
// same view in vocbase and with no collections
if (impl == vocbase.lookupView(impl->id()) // avoid double dropView(...)
&& impl->visitCollections([](TRI_voc_cid_t){ return false; })
&& !impl->drop().ok()) { // per-cid collections always system
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "failure to drop stale arangosearch View '" << impl->name() << "' while from database '" << vocbase.name() << "'";
}
} catch (basics::Exception const& e) {
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
<< "caught exception while dropping stale arangosearch View '" << impl->name()
<< "' while from database '" << vocbase.name()
<< "', errorCode: '" << e.code()
<< "', error: '" << e.message();
} catch (std::exception const& e) {
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
<< "caught exception while dropping stale arangosearch View '" << impl->name()
<< "' while from database '" << vocbase.name()
<< "', error: '" << e.what() << "'";
} catch (...) {
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
<< "caught an unspecified exception while dropping stale arangosearch View '" << impl->name()
<< "' while from database '" << vocbase.name() << "'";
}
}
);
return arangodb::Result();
}
};
IResearchViewDBServer::IResearchViewDBServer(
TRI_vocbase_t& vocbase,
arangodb::velocypack::Slice const& info,
arangodb::DatabasePathFeature const& /*dbPathFeature*/,
uint64_t planVersion,
std::shared_ptr<AsyncMeta> meta /*=nullptr*/
) : LogicalViewClusterInfo(vocbase, info, planVersion),
_meta(std::move(meta)) {
}
IResearchViewDBServer::~IResearchViewDBServer() noexcept {
_collections.clear(); // ensure view distructors called before mutex is deallocated
}
arangodb::Result IResearchViewDBServer::appendVelocyPackDetailed(
arangodb::velocypack::Builder& builder,
bool forPersistence
) const {
if (!builder.isOpenObject()) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
std::string("invalid builder provided for IResearchViewDBServer definition")
);
}
{
SCOPED_LOCK(_meta->read()); // '_meta' can be asynchronously updated
static const std::function<bool(irs::string_ref const& key)> acceptor = [](
irs::string_ref const& key
)->bool {
return key != StaticStrings::VersionField; // ignored fields
};
static const std::function<bool(irs::string_ref const& key)> persistenceAcceptor = [](
irs::string_ref const&
)->bool {
return true;
};
arangodb::velocypack::Builder sanitizedBuilder;
sanitizedBuilder.openObject();
if (!_meta->json(sanitizedBuilder)
|| !mergeSliceSkipKeys(builder, sanitizedBuilder.close().slice(), forPersistence ? persistenceAcceptor : acceptor)) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure to generate definition while generating properties jSON for arangosearch view in database '") + vocbase().name() + "'"
);
}
}
return arangodb::Result();
}
arangodb::Result IResearchViewDBServer::dropImpl() {
WriteMutex mutex(_mutex);
SCOPED_LOCK(mutex); // 'collections_' can be asynchronously read
for (auto itr = _collections.begin(); itr != _collections.end();) {
auto res = itr->second->drop();
if (!res.ok()) {
return res; // fail on first failure
}
itr = _collections.erase(itr);
}
return arangodb::Result();
}
std::shared_ptr<arangodb::LogicalView> IResearchViewDBServer::ensure(
TRI_voc_cid_t cid,
bool create /*= true*/
) {
WriteMutex mutex(_mutex);
SCOPED_LOCK(mutex); // 'collections_' can be asynchronously read
auto itr = _collections.find(cid);
if (itr != _collections.end()) {
return itr->second;
}
auto viewName = generateName(id(), cid);
auto view = vocbase().lookupView(viewName); // on startup a IResearchView might only be in vocbase but not in a brand new IResearchViewDBServer
auto* impl = LogicalView::cast<IResearchView>(view.get());
if (impl) {
_collections.emplace(cid, view); // track the IResearchView instance from vocbase
impl->updateProperties(_meta);
return view; // do not wrap in deleter since view already present in vocbase (as if already present in '_collections')
}
if (!create) {
return nullptr;
}
arangodb::velocypack::Builder builder;
builder.openObject();
builder.add(
arangodb::StaticStrings::DataSourceSystem,
arangodb::velocypack::Value(true)
); // required to for use of VIEW_NAME_PREFIX
builder.add(
arangodb::StaticStrings::DataSourceName,
toValuePair(viewName)
); // mark the view definition as an internal per-cid instance
builder.add(
arangodb::StaticStrings::DataSourcePlanId,
arangodb::velocypack::Value(id())
); // planId required for cluster-wide view lookup from per-cid view
builder.add(
arangodb::StaticStrings::DataSourceType,
toValuePair(DATA_SOURCE_TYPE.name())
); // type required for proper factory selection
{
SCOPED_LOCK(_meta->read()); // '_meta' can be asynchronously updated
if (!_meta->json(builder)) {
builder.close(); // close StaticStrings::PropertiesField
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "failure to generate properties definition while constructing arangosearch view in database '" << vocbase().name() << "'";
return nullptr;
}
}
builder.close();
view = vocbase().createView(builder.slice());
impl = LogicalView::cast<IResearchView>(view.get());
if (!impl) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "failure while creating an arangosearch view for collection '" << cid << "' in database '" << vocbase().name() << "'";
return nullptr;
}
// FIXME should we register?
_collections.emplace(cid, view);
impl->updateProperties(_meta);
// hold a reference to the original view in the deleter so that the view is still valid for the duration of the pointer wrapper
// this shared_ptr should not be stored in TRI_vocbase_t since the deleter depends on 'this'
return std::shared_ptr<arangodb::LogicalView>(
view.get(),
[this, view, cid](arangodb::LogicalView*)->void {
// FIXME destructor has to be noexcept
static const auto visitor = [](TRI_voc_cid_t)->bool { return false; };
auto& vocbase = view->vocbase();
// same view in vocbase and with no collections
if (view.get() == vocbase.lookupView(view->id()).get() // avoid double dropView(...)
&& view->visitCollections(visitor)) {
// FIXME TODO ensure somehow that 'this' is still valid
unlink(cid);
}
}
);
}
/*static*/ arangodb::ViewFactory const& IResearchViewDBServer::factory() {
static const ViewFactory factory;
return factory;
}
void IResearchViewDBServer::open() {
ReadMutex mutex(_mutex);
SCOPED_LOCK(mutex); // 'collections_' can be asynchronously modified
for (auto& entry: _collections) {
entry.second->open();
}
}
irs::index_reader const* IResearchViewDBServer::snapshot(
transaction::Methods& trx,
std::vector<std::string> const& shards,
IResearchView::Snapshot mode /*= IResearchView::Snapshot::Find*/
) const {
auto* state = trx.state();
if (!state) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "failed to get transaction state while creating arangosearch view snapshot";
return nullptr;
}
// TODO FIXME find a better way to look up a ViewState
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
auto* cookie = dynamic_cast<ViewState*>(state->cookie(this));
#else
auto* cookie = static_cast<ViewState*>(state->cookie(this));
#endif
switch (mode) {
case IResearchView::Snapshot::Find:
return cookie ? &cookie->_snapshot : nullptr;
case IResearchView::Snapshot::FindOrCreate:
if (cookie) {
return &cookie->_snapshot;
}
break;
default:
break;
}
auto* resolver = trx.resolver();
if (!resolver) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "failed to retrieve CollectionNameResolver from the transaction";
return nullptr;
}
std::unique_ptr<ViewState> cookiePtr;
CompoundReader* reader = nullptr;
if (!cookie) {
cookiePtr = irs::memory::make_unique<ViewState>();
reader = &cookiePtr->_snapshot;
} else {
reader = &cookie->_snapshot;
reader->clear();
}
TRI_ASSERT(reader);
ReadMutex mutex(_mutex);
SCOPED_LOCK(mutex); // 'collections_' can be asynchronously modified
try {
for (auto& shardId : shards) {
auto shard = resolver->getCollection(shardId);
if (!shard) {
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
<< "failed to find shard by id '" << shardId << "', skipping it";
continue;
}
auto cid = shard->id();
auto const shardView = _collections.find(cid);
if (shardView == _collections.end()) {
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
<< "failed to find shard view for shard id '" << cid << "', skipping it";
continue;
}
auto* rdr = LogicalView::cast<IResearchView>(*shardView->second).snapshot(trx, mode);
if (rdr) {
reader->add(*rdr);
}
}
} catch (arangodb::basics::Exception& e) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "caught exception while collecting readers for snapshot of DBServer arangosearch view '" << id()
<< "': " << e.code() << " " << e.what();
IR_LOG_EXCEPTION();
return nullptr;
} catch (std::exception const& e) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "caught exception while collecting readers for snapshot of DBServer arangosearch view '" << id()
<< "': " << e.what();
IR_LOG_EXCEPTION();
return nullptr;
} catch (...) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "caught exception while collecting readers for snapshot of DBServer arangosearch view '" << id() << "'";
IR_LOG_EXCEPTION();
return nullptr;
}
if (cookiePtr) {
state->cookie(this, std::move(cookiePtr));
}
return reader;
}
arangodb::Result IResearchViewDBServer::unlink(TRI_voc_cid_t cid) noexcept {
try {
WriteMutex mutex(_mutex);
SCOPED_LOCK(mutex); // 'collections_' can be asynchronously read
auto itr = _collections.find(cid);
if (itr == _collections.end()) {
return arangodb::Result(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
}
auto res = itr->second->drop();
if (!res.ok()) {
return res;
}
_collections.erase(itr);
} catch (arangodb::basics::Exception const& e) {
return arangodb::Result(
e.code(),
std::string("caught exception while unlinking collection '") + std::to_string(cid) + "' from arangosearch view '" + name() + "': " + e.what()
);
} catch (std::exception const& e) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("caught exception while unlinking collection '") + std::to_string(cid) + "' from arangosearch view '" + name() + "': " + e.what()
);
} catch (...) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("caught exception while unlinking collection '") + std::to_string(cid) + "' from arangosearch view '" + name() + "'"
);
}
return arangodb::Result();
}
arangodb::Result IResearchViewDBServer::properties(
arangodb::velocypack::Slice const& slice,
bool partialUpdate
) {
if (!slice.isObject()) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
std::string("invalid properties supplied while updating arangosearch view in database '") + vocbase().name() + "'"
);
}
// ...........................................................................
// sanitize update slice
// ...........................................................................
static const std::function<bool(irs::string_ref const& key)> propsAcceptor = [](
irs::string_ref const& key
)->bool {
return key != StaticStrings::LinksField; // ignored fields
};
arangodb::velocypack::Builder props;
props.openObject();
if (!mergeSliceSkipKeys(props, slice, propsAcceptor)) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure to generate definition while updating arangosearch view in database '") + vocbase().name() + "'"
);
}
props.close();
IResearchViewMeta meta;
std::string error;
if (partialUpdate) {
SCOPED_LOCK(_meta->read());
if (!meta.init(props.slice(), error, *_meta)) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
std::string("failure parsing properties while updating arangosearch view in database '") + vocbase().name() + "'"
);
}
} else if (!meta.init(props.slice(), error)) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
std::string("failure parsing properties while updating arangosearch view in database '") + vocbase().name() + "'"
);
}
WriteMutex mutex(_mutex);
SCOPED_LOCK(mutex); // '_collections' can be asynchronously read
{
SCOPED_LOCK(_meta->write());
// reset non-updatable values to match current meta
meta._locale = _meta->_locale;
static_cast<IResearchViewMeta&>(*_meta) = std::move(meta);
}
auto* feature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::iresearch::IResearchFeature
>();
if (feature) {
feature->asyncNotify();
}
if (!slice.hasKey(StaticStrings::LinksField) && partialUpdate) {
return arangodb::Result();
}
// ...........................................................................
// update links if requested (on a best-effort basis)
// ...........................................................................
std::unordered_set<TRI_voc_cid_t> collections;
auto links = slice.hasKey(StaticStrings::LinksField)
? slice.get(StaticStrings::LinksField)
: arangodb::velocypack::Slice::emptyObjectSlice(); // used for !partialUpdate
if (partialUpdate) {
return IResearchLinkHelper::updateLinks(
collections, vocbase(), *this, links
);
}
std::unordered_set<TRI_voc_cid_t> stale;
for (auto& entry: _collections) {
stale.emplace(entry.first);
}
return IResearchLinkHelper::updateLinks(
collections, vocbase(), *this, links, stale
);
}
bool IResearchViewDBServer::visitCollections(
CollectionVisitor const& visitor
) const {
ReadMutex mutex(_mutex);
SCOPED_LOCK(mutex); // 'collections_' can be asynchronously modified
for (auto& entry: _collections) {
if (!visitor(entry.first)) {
return false;
}
}
return true;
}
} // iresearch
} // arangodb
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------

View File

@ -1,132 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 ARANGOD_IRESEARCH__IRESEARCH_VIEW_DBSERVER_H
#define ARANGOD_IRESEARCH__IRESEARCH_VIEW_DBSERVER_H 1
#include "utils/async_utils.hpp"
#include "IResearchView.h"
#include "Transaction/Status.h"
#include "velocypack/Builder.h"
#include "VocBase/LogicalView.h"
namespace arangodb {
class DatabasePathFeature;
class TransactionState;
struct ViewFactory; // forward declaration
class CollectionNameResolver;
namespace transaction {
class Methods; // forward declaration
} // transaction
} // arangodb
namespace arangodb {
namespace iresearch {
class AsyncMeta;
class IResearchViewDBServer final: public arangodb::LogicalViewClusterInfo {
public:
virtual ~IResearchViewDBServer() noexcept;
//////////////////////////////////////////////////////////////////////////////
/// @brief ensure there is a view instance for the specified 'cid'
/// @param force creation of a new instance if none is available in vocbase
/// @return an existing instance or create a new instance if none is registred
/// on ptr reset the view will be dropped if it has no collections
/// @note view created in vocbase() to match callflow during regular startup
//////////////////////////////////////////////////////////////////////////////
std::shared_ptr<arangodb::LogicalView> ensure(
TRI_voc_cid_t cid,
bool create = true
);
//////////////////////////////////////////////////////////////////////////////
/// @brief the factory for this type of view
//////////////////////////////////////////////////////////////////////////////
static arangodb::ViewFactory const& factory();
virtual void open() override;
virtual arangodb::Result properties(
arangodb::velocypack::Slice const& properties,
bool partialUpdate
) override;
////////////////////////////////////////////////////////////////////////////////
/// @return pointer to an index reader containing the datastore record snapshot
/// associated with 'state'
/// (nullptr == no view snapshot associated with the specified state)
/// if force == true && no snapshot -> associate current snapshot
////////////////////////////////////////////////////////////////////////////////
irs::index_reader const* snapshot(
transaction::Methods& trx,
std::vector<std::string> const& shards,
IResearchView::Snapshot mode = IResearchView::Snapshot::Find
) const;
//////////////////////////////////////////////////////////////////////////////
/// @brief unlink remove 'cid' from the persisted list of tracked collection
/// IDs
/// @return success == view does not track collection
//////////////////////////////////////////////////////////////////////////////
arangodb::Result unlink(TRI_voc_cid_t cid) noexcept;
virtual bool visitCollections(
CollectionVisitor const& visitor
) const override;
protected:
virtual arangodb::Result appendVelocyPackDetailed(
arangodb::velocypack::Builder& builder,
bool forPersistence
) const override;
virtual arangodb::Result dropImpl() override;
private:
struct ViewFactory; // forward declaration
std::map<TRI_voc_cid_t, std::shared_ptr<arangodb::LogicalView>> _collections;
std::shared_ptr<AsyncMeta> _meta; // the shared view configuration (never null!!!)
mutable irs::async_utils::read_write_mutex _mutex; // for use with members
IResearchViewDBServer(
TRI_vocbase_t& vocbase,
arangodb::velocypack::Slice const& info,
arangodb::DatabasePathFeature const& dbPathFeature,
uint64_t planVersion,
std::shared_ptr<AsyncMeta> meta = nullptr
);
};
} // iresearch
} // arangodb
#endif

View File

@ -23,7 +23,6 @@
#include "IResearchCommon.h"
#include "IResearchViewCoordinator.h"
#include "IResearchViewDBServer.h"
#include "IResearchViewNode.h"
#include "IResearchViewBlock.h"
#include "IResearchOrderFactory.h"
@ -39,8 +38,8 @@
#include "Basics/StringUtils.h"
#include "Cluster/ClusterInfo.h"
#include "StorageEngine/TransactionState.h"
#include "velocypack/Iterator.h"
#include "VocBase/LogicalCollection.h"
namespace {
@ -676,9 +675,24 @@ std::unique_ptr<aql::ExecutionBlock> IResearchViewNode::createBlock(
IResearchView::Snapshot::FindOrCreate,
IResearchView::Snapshot::SyncAndReplace
};
std::unordered_set<TRI_voc_cid_t> collections;
auto& resolver = engine.getQuery()->resolver();
reader = LogicalView::cast<IResearchViewDBServer>(view).snapshot(
*trx, _shards, SNAPSHOT[size_t(_options.forceSync)]
for (auto& shard: _shards) {
auto collection = resolver.getCollection(shard);
if (!collection) {
THROW_ARANGO_EXCEPTION(arangodb::Result(
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
std::string("failed to find shard by id '") + shard + "'"
));
}
collections.emplace(collection->id());
}
reader = LogicalView::cast<IResearchView>(view).snapshot(
*trx, SNAPSHOT[size_t(_options.forceSync)], &collections
);
} else {
static IResearchView::Snapshot const SNAPSHOT[] {
@ -693,7 +707,7 @@ std::unique_ptr<aql::ExecutionBlock> IResearchViewNode::createBlock(
if (!reader) {
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
<< "failed to get snapshot while creating arangosearch view ExecutionBlock for view '" << view.name() << "' tid '";
<< "failed to get snapshot while creating arangosearch view ExecutionBlock for view '" << view.name() << "'";
THROW_ARANGO_EXCEPTION_MESSAGE(
TRI_ERROR_INTERNAL,

View File

@ -1400,8 +1400,7 @@ Result MMFilesEngine::createView(
"Database")
->forceSyncProperties();
saveViewInfo(&vocbase, &view, doSync);
saveViewInfo(vocbase, view, doSync);
if (inRecovery()) {
// Nothing more do. In recovery we do not write markers.
@ -1452,13 +1451,13 @@ void MMFilesEngine::getViewProperties(
}
arangodb::Result MMFilesEngine::dropView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) {
auto* db = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
TRI_ASSERT(db);
saveViewInfo(&vocbase, &view, db->forceSyncProperties());
saveViewInfo(vocbase, view, db->forceSyncProperties());
if (inRecovery()) {
// nothing to do here
@ -1498,8 +1497,8 @@ arangodb::Result MMFilesEngine::dropView(
}
void MMFilesEngine::destroyView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) noexcept {
try {
auto directory = viewDirectory(vocbase.id(), view.id());
@ -1514,14 +1513,16 @@ void MMFilesEngine::destroyView(
}
}
void MMFilesEngine::saveViewInfo(TRI_vocbase_t* vocbase,
arangodb::LogicalView const* view,
bool forceSync) const {
std::string const filename = viewParametersFilename(vocbase->id(), view->id());
void MMFilesEngine::saveViewInfo(
TRI_vocbase_t const& vocbase,
LogicalView const& view,
bool forceSync
) const {
auto filename = viewParametersFilename(vocbase.id(), view.id());
VPackBuilder builder;
builder.openObject();
view->properties(builder, true, true);
view.properties(builder, true, true);
builder.close();
LOG_TOPIC(TRACE, Logger::VIEWS)
@ -1572,7 +1573,8 @@ Result MMFilesEngine::changeView(
}
}
saveViewInfo(&vocbase, &view, doSync);
saveViewInfo(vocbase, view, doSync);
return {};
}

View File

@ -374,19 +374,23 @@ class MMFilesEngine final : public StorageEngine {
) override;
arangodb::Result dropView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) override;
void destroyView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) noexcept override;
std::string createViewDirectoryName(std::string const& basePath,
TRI_voc_cid_t id);
void saveViewInfo(TRI_vocbase_t* vocbase, arangodb::LogicalView const*, bool sync) const;
void saveViewInfo(
TRI_vocbase_t const& vocbase,
LogicalView const& view,
bool sync
) const;
void signalCleanup(TRI_vocbase_t& vocbase) override;
@ -627,4 +631,4 @@ class MMFilesEngine final : public StorageEngine {
}
#endif
#endif

View File

@ -1439,8 +1439,8 @@ Result RocksDBEngine::createView(
}
arangodb::Result RocksDBEngine::dropView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) {
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
LOG_TOPIC(DEBUG, Logger::ENGINES) << "RocksDBEngine::dropView";
@ -1469,8 +1469,8 @@ arangodb::Result RocksDBEngine::dropView(
}
void RocksDBEngine::destroyView(
TRI_vocbase_t& /*vocbase*/,
LogicalView& /*view*/
TRI_vocbase_t const& /*vocbase*/,
LogicalView const& /*view*/
) noexcept {
// nothing to do here
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
@ -2316,4 +2316,4 @@ bool RocksDBEngine::canUseRangeDeleteInWal() const {
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -293,13 +293,13 @@ class RocksDBEngine final : public StorageEngine {
}
arangodb::Result dropView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) override;
void destroyView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) noexcept override;
void signalCleanup(TRI_vocbase_t& vocbase) override;
@ -479,4 +479,4 @@ class RocksDBEngine final : public StorageEngine {
} // namespace arangodb
#endif
#endif

View File

@ -360,8 +360,8 @@ class StorageEngine : public application_features::ApplicationFeature {
// the WAL entry for view deletion will be written *after* the call
// to "dropView" returns
virtual arangodb::Result dropView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) = 0;
// perform a physical deletion of the view
@ -369,8 +369,8 @@ class StorageEngine : public application_features::ApplicationFeature {
// assured that no one is using the view anymore
// 'noexcept' becuase it may be used in destructor
virtual void destroyView(
TRI_vocbase_t& vocbase,
LogicalView& view
TRI_vocbase_t const& vocbase,
LogicalView const& view
) noexcept = 0;
// Returns the StorageEngine-specific implementation
@ -490,4 +490,4 @@ class StorageEngine : public application_features::ApplicationFeature {
}
#endif
#endif

View File

@ -23,8 +23,6 @@
#include "LogicalView.h"
#include "Aql/PlanCache.h"
#include "Aql/QueryCache.h"
#include "Basics/StaticStrings.h"
#include "Basics/VelocyPackHelper.h"
#include "Cluster/ClusterInfo.h"
@ -85,6 +83,26 @@ LogicalView::LogicalView(
TRI_UpdateTickServer(static_cast<TRI_voc_tick_t>(id()));
}
Result LogicalView::appendVelocyPack(
velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const {
if (!builder.isOpenObject()) {
return Result(
TRI_ERROR_BAD_PARAMETER,
std::string("invalid builder provided for LogicalView definition")
);
}
builder.add(
StaticStrings::DataSourceType,
arangodb::velocypack::Value(type().name())
);
return appendVelocyPackImpl(builder, detailed, forPersistence);
}
/*static*/ LogicalDataSource::Category const& LogicalView::category() noexcept {
static const Category category;
@ -114,6 +132,30 @@ LogicalView::LogicalView(
return factory.create(view, vocbase, definition);
}
Result LogicalView::drop() {
if (deleted()) {
return Result(); // view already dropped
}
try {
deleted(true); // mark as deleted to avoid double-delete (including recursive calls)
auto res = dropImpl();
if (!res.ok()) {
deleted(false); // not fully deleted
return res;
}
} catch (...) {
deleted(false); // not fully deleted
throw;
}
return Result();
}
/*static*/ bool LogicalView::enumerate(
TRI_vocbase_t& vocbase,
std::function<bool(std::shared_ptr<LogicalView> const&)> const& callback
@ -172,327 +214,361 @@ LogicalView::LogicalView(
return factory.instantiate(view, vocbase, definition, planVersion);
}
// -----------------------------------------------------------------------------
// --SECTION-- LogicalViewClusterInfo
// -----------------------------------------------------------------------------
LogicalViewClusterInfo::LogicalViewClusterInfo(
TRI_vocbase_t& vocbase,
VPackSlice const& definition,
uint64_t planVersion
): LogicalView(vocbase, definition, planVersion) {
TRI_ASSERT(
ServerState::instance()->isCoordinator()
|| ServerState::instance()->isDBServer()
);
}
arangodb::Result LogicalViewClusterInfo::appendVelocyPack(
arangodb::velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const {
if (!builder.isOpenObject()) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
std::string("invalid builder provided for LogicalView definition")
);
}
builder.add(
StaticStrings::DataSourceType,
arangodb::velocypack::Value(type().name())
);
// implementation Information
if (detailed) {
auto res = appendVelocyPackDetailed(builder, forPersistence);
if (!res.ok()) {
return res;
}
}
// ensure that the object is still open
if (!builder.isOpenObject()) {
return arangodb::Result(TRI_ERROR_INTERNAL);
}
return arangodb::Result();
}
arangodb::Result LogicalViewClusterInfo::drop() {
if (deleted()) {
return Result(); // view already dropped
}
auto* engine = arangodb::ClusterInfo::instance();
if (!engine) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure to get storage engine while dropping View '") + name() + "'"
);
}
Result LogicalView::rename(std::string&& newName) {
auto oldName = name();
try {
deleted(true); // mark as deleted to avoid double-delete (including recursive calls)
name(std::move(newName));
auto res = dropImpl();
auto res = renameImpl(oldName);
if (!res.ok()) {
deleted(false); // not fully deleted
name(std::move(oldName)); // restore name
return res;
}
} catch (...) {
name(std::move(oldName));
throw;
}
return Result();
}
// -----------------------------------------------------------------------------
// --SECTION-- LogicalViewHelperClusterInfo
// -----------------------------------------------------------------------------
/*static*/ Result LogicalViewHelperClusterInfo::construct(
LogicalView::ptr& view,
TRI_vocbase_t& vocbase,
velocypack::Slice const& definition
) noexcept {
try {
auto* engine = ClusterInfo::instance();
if (!engine) {
return Result(
TRI_ERROR_INTERNAL,
std::string("failure to find storage engine while creating arangosearch View in database '") + vocbase.name() + "'"
);
}
LogicalView::ptr impl;
auto res = LogicalView::instantiate(impl, vocbase, definition);
if (!res.ok()) {
return res;
}
if (!impl) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failure during instantiation while creating arangosearch View in database '") + vocbase.name() + "'"
);
}
velocypack::Builder builder;
builder.openObject();
res = impl->properties(builder, true, true); // include links so that Agency will always have a full definition
if (!res.ok()) {
return res;
}
builder.close();
std::string error;
auto resNum = engine->dropViewCoordinator(
vocbase().name(), std::to_string(id()), error
auto resNum = engine->createViewCoordinator(
vocbase.name(), std::to_string(impl->id()), builder.slice(), error
);
if (TRI_ERROR_NO_ERROR != resNum) {
deleted(false); // not fully deleted
if (error.empty()) {
error = TRI_errno_string(resNum);
}
return arangodb::Result(
resNum,
std::string("failure during ClusterInfo removal of View in database '") + vocbase().name() + "', error: " + error
std::string("failure during ClusterInfo persistance of created view while creating arangosearch View in database '") + vocbase.name() + "', error: " + error
);
}
view = engine->getView(vocbase.name(), std::to_string(impl->id())); // refresh view from Agency
if (view) {
view->open(); // open view to match the behaviour in StorageEngine::openExistingDatabase(...) and original behaviour of TRI_vocbase_t::createView(...)
}
return Result();
} catch (basics::Exception const& e) {
return Result(e.code()); // noexcept constructor
} catch (...) {
deleted(false); // not fully deleted
throw;
// NOOP
}
return arangodb::Result();
return Result(TRI_ERROR_INTERNAL); // noexcept constructor
}
arangodb::Result LogicalViewClusterInfo::rename(std::string&&) {
// renaming a view in a cluster is unsupported
return TRI_ERROR_CLUSTER_UNSUPPORTED;
/*static*/ Result LogicalViewHelperClusterInfo::destruct(
LogicalView const& view
) noexcept {
return Result(); // nothing to clean up since the Plan is managed by the Agency
}
// -----------------------------------------------------------------------------
// --SECTION-- LogicalViewStorageEngine
// -----------------------------------------------------------------------------
/*static*/ Result LogicalViewHelperClusterInfo::drop(
LogicalView const& view
) noexcept {
try {
auto* engine = ClusterInfo::instance();
LogicalViewStorageEngine::LogicalViewStorageEngine(
TRI_vocbase_t& vocbase,
VPackSlice const& definition,
uint64_t planVersion
): LogicalView(vocbase, definition, planVersion) {
TRI_ASSERT(
ServerState::instance()->isDBServer()
|| ServerState::instance()->isSingleServer()
);
}
if (!engine) {
return Result(
TRI_ERROR_INTERNAL,
std::string("failure to find storage engine while dropping view '") + view.name() + "' from database '" + view.vocbase().name() + "'"
);
}
LogicalViewStorageEngine::~LogicalViewStorageEngine() {
if (deleted()) {
StorageEngine* engine = EngineSelectorFeature::ENGINE;
TRI_ASSERT(engine);
// FIXME TODO is this required?
engine->destroyView(vocbase(), *this);
}
}
arangodb::Result LogicalViewStorageEngine::appendVelocyPack(
arangodb::velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const {
if (!builder.isOpenObject()) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
std::string("invalid builder provided for LogicalView definition")
std::string error;
auto res = engine->dropViewCoordinator(
view.vocbase().name(), std::to_string(view.id()), error
);
if (TRI_ERROR_NO_ERROR == res) {
return Result();
}
if (error.empty()) {
error = TRI_errno_string(res);
}
return Result(
res,
std::string("failure during ClusterInfo removal of view '") + view.name() + "' from database '" + view.vocbase().name() + "': " + error
);
} catch (basics::Exception const& e) {
return Result(e.code()); // noexcept constructor
} catch (...) {
// NOOP
}
builder.add(
StaticStrings::DataSourceType,
arangodb::velocypack::Value(type().name())
);
return Result(TRI_ERROR_INTERNAL); // noexcept constructor
}
// 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
if (forPersistence) {
// storage engine related properties
/*static*/ Result LogicalViewHelperClusterInfo::properties(
velocypack::Builder& builder,
LogicalView const& view
) noexcept {
return Result(); // NOOP
}
/*static*/ Result LogicalViewHelperClusterInfo::properties(
LogicalView const& view
) noexcept {
try {
auto* engine = ClusterInfo::instance();
if (!engine) {
return Result(
TRI_ERROR_INTERNAL,
std::string("failure to find storage engine while updating definition of view '") + view.name() + "' from database '" + view.vocbase().name() + "'"
);
}
velocypack::Builder builder;
builder.openObject();
auto res = view.properties(builder, true, true);
if (!res.ok()) {
return res;
}
builder.close();
return engine->setViewPropertiesCoordinator(
view.vocbase().name(), std::to_string(view.id()), builder.slice()
);
} catch (basics::Exception const& e) {
return Result(e.code()); // noexcept constructor
} catch (...) {
// NOOP
}
return Result(TRI_ERROR_INTERNAL); // noexcept constructor
}
/*static*/ Result LogicalViewHelperClusterInfo::rename(
LogicalView const& view,
std::string const& oldName
) noexcept {
return Result(TRI_ERROR_CLUSTER_UNSUPPORTED); // renaming a view in a cluster is not supported
}
// -----------------------------------------------------------------------------
// --SECTION-- LogicalViewHelperStorageEngine
// -----------------------------------------------------------------------------
/*static*/ Result LogicalViewHelperStorageEngine::construct(
LogicalView::ptr& view,
TRI_vocbase_t& vocbase,
velocypack::Slice const& definition
) noexcept {
try {
TRI_set_errno(TRI_ERROR_NO_ERROR); // reset before calling createView(...)
auto impl = vocbase.createView(definition);
if (!impl) {
return Result(
TRI_ERROR_NO_ERROR == TRI_errno() ? TRI_ERROR_INTERNAL : TRI_errno(),
std::string("failure during instantiation while creating arangosearch View in database '") + vocbase.name() + "'"
);
}
view = impl;
return Result();
} catch (basics::Exception const& e) {
return Result(e.code()); // noexcept constructor
} catch (...) {
// NOOP
}
return Result(TRI_ERROR_INTERNAL); // noexcept constructor
}
/*static*/ Result LogicalViewHelperStorageEngine::destruct(
LogicalView const& view
) noexcept {
if (!view.deleted()) {
return Result(); // NOOP
}
try {
auto* engine = EngineSelectorFeature::ENGINE;
if (!engine) {
return TRI_ERROR_INTERNAL;
return Result(
TRI_ERROR_INTERNAL,
std::string("failed to find a storage engine while destructing view '") + view.name() + "' in database '" + view.vocbase().name() + "'"
);
}
engine->getViewProperties(vocbase(), *this, builder);
engine->destroyView(view.vocbase(), view);
return Result();
} catch (basics::Exception const& e) {
return Result(e.code()); // noexcept constructor
} catch (...) {
// NOOP
}
// implementation Information
if (detailed) {
auto res = appendVelocyPackDetailed(builder, forPersistence);
if (!res.ok()) {
return res;
}
}
// ensure that the object is still open
if (!builder.isOpenObject()) {
return arangodb::Result(TRI_ERROR_INTERNAL);
}
return arangodb::Result();
return Result(TRI_ERROR_INTERNAL); // noexcept constructor
}
arangodb::Result LogicalViewStorageEngine::drop() {
if (deleted()) {
return Result(); // view already dropped
}
/*static*/ Result LogicalViewHelperStorageEngine::drop(
LogicalView const& view
) noexcept {
try {
deleted(true); // mark as deleted to avoid double-delete (including recursive calls)
auto res = dropImpl();
if (!res.ok()) {
deleted(false); // not fully deleted
return res;
}
res = vocbase().dropView(id(), true); // true since caller should have checked for 'system'
if (!res.ok()) {
deleted(false); // not fully deleted
return res;
}
return view.vocbase().dropView(view.id(), true); // true since caller should have checked for 'system'
} catch (basics::Exception const& e) {
return Result(e.code()); // noexcept constructor
} catch (...) {
deleted(false); // not fully deleted
throw;
// NOOP
}
return arangodb::Result();
return Result(TRI_ERROR_INTERNAL); // noexcept constructor
}
Result LogicalViewStorageEngine::rename(std::string&& newName) {
TRI_ASSERT(!ServerState::instance()->isCoordinator());
auto* databaseFeature = application_features::ApplicationServer::lookupFeature<
DatabaseFeature
>("Database");
if (!databaseFeature) {
return Result(
TRI_ERROR_INTERNAL,
"failed to find feature 'Database' while renaming view"
);
}
StorageEngine* engine = EngineSelectorFeature::ENGINE;
if (!engine) {
return Result(
TRI_ERROR_INTERNAL,
"failed to find a storage engine while renaming view"
);
}
auto doSync = databaseFeature->forceSyncProperties();
auto oldName = name();
auto res = vocbase().renameView(id(), newName);
if (!res.ok()) {
return res;
}
/*static*/ Result LogicalViewHelperStorageEngine::properties(
velocypack::Builder& builder,
LogicalView const& view
) noexcept {
try {
name(std::move(newName));
auto res = engine->inRecovery()
? Result() : engine->changeView(vocbase(), *this, doSync);
if (!res.ok()) {
name(std::move(oldName)); // restore name
vocbase().renameView(id(), oldName);
return res;
if (!builder.isOpenObject()) {
return Result(
TRI_ERROR_BAD_PARAMETER,
std::string("invalid builder provided for LogicalView definition")
);
}
} catch (basics::Exception const& ex) {
name(std::move(oldName));
vocbase().renameView(id(), oldName);
return Result(ex.code(), ex.message());
auto* engine = EngineSelectorFeature::ENGINE;
if (!engine) {
return Result(
TRI_ERROR_INTERNAL,
std::string("failed to find a storage engine while querying definition of view '") + view.name() + "' in database '" + view.vocbase().name() + "'"
);
}
engine->getViewProperties(view.vocbase(), view, builder);
return Result();
} catch (basics::Exception const& e) {
return Result(e.code()); // noexcept constructor
} catch (...) {
name(std::move(oldName));
vocbase().renameView(id(), oldName);
return Result(TRI_ERROR_INTERNAL, "caught exception while renaming view");;
// NOOP
}
return TRI_ERROR_NO_ERROR;
return Result(TRI_ERROR_INTERNAL); // noexcept constructor
}
arangodb::Result LogicalViewStorageEngine::properties(
VPackSlice const& slice,
bool partialUpdate
) {
TRI_ASSERT(!ServerState::instance()->isCoordinator());
auto* databaseFeature = application_features::ApplicationServer::lookupFeature<
DatabaseFeature
>("Database");
if (!databaseFeature) {
return Result(
TRI_ERROR_INTERNAL,
"failed to find feature 'Database' while updating collection"
);
}
auto* engine = EngineSelectorFeature::ENGINE;
if (!engine) {
return Result(
TRI_ERROR_INTERNAL,
"failed to find a storage engine while updating collection"
);
}
auto res = updateProperties(slice, partialUpdate);
if (!res.ok()) {
LOG_TOPIC(ERR, Logger::VIEWS) << "failed to update view with properties '"
<< slice.toJson() << "'";
return res;
}
LOG_TOPIC(DEBUG, Logger::VIEWS) << "updated view with properties '"
<< slice.toJson() << "'";
auto doSync = !engine->inRecovery() && databaseFeature->forceSyncProperties();
// after this call the properties are stored
if (engine->inRecovery()) {
return arangodb::Result(); // do not modify engine while in recovery
}
/*static*/ Result LogicalViewHelperStorageEngine::properties(
LogicalView const& view
) noexcept {
try {
engine->changeView(vocbase(), *this, doSync);
} catch (arangodb::basics::Exception const& e) {
return Result(e.code(), e.message());
auto* databaseFeature = application_features::ApplicationServer::lookupFeature<
DatabaseFeature
>("Database");
if (!databaseFeature) {
return Result(
TRI_ERROR_INTERNAL,
std::string("failed to find feature 'Database' while updating definition of view '") + view.name() + "' in database '" + view.vocbase().name() + "'"
);
}
auto* engine = EngineSelectorFeature::ENGINE;
if (!engine) {
return Result(
TRI_ERROR_INTERNAL,
std::string("failed to find a storage engine while updating definition of view '") + view.name() + "' in database '" + view.vocbase().name() + "'"
);
}
auto doSync = databaseFeature->forceSyncProperties();
if (engine->inRecovery()) {
return Result(); // do not modify engine while in recovery
}
return engine->changeView(view.vocbase(), view, doSync);
} catch (basics::Exception const& e) {
return Result(e.code()); // noexcept constructor
} catch (...) {
return Result(TRI_ERROR_INTERNAL, "caught exception while updating view");
// NOOP
}
arangodb::aql::PlanCache::instance()->invalidate(&vocbase());
arangodb::aql::QueryCache::instance()->invalidate(&vocbase());
return Result(TRI_ERROR_INTERNAL); // noexcept constructor
}
return {};
/*static*/ Result LogicalViewHelperStorageEngine::rename(
LogicalView const& view,
std::string const& oldName
) noexcept {
try {
return view.vocbase().renameView(view.id(), oldName);
} catch (basics::Exception const& e) {
return Result(e.code()); // noexcept constructor
} catch (...) {
// NOOP
}
return Result(TRI_ERROR_INTERNAL); // noexcept constructor
}
} // arangodb

View File

@ -108,6 +108,15 @@ class LogicalView : public LogicalDataSource {
#endif
}
//////////////////////////////////////////////////////////////////////////////
/// @brief queries properties of an existing view
//////////////////////////////////////////////////////////////////////////////
virtual Result appendVelocyPack(
velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const override final;
//////////////////////////////////////////////////////////////////////////////
/// @brief the category representing a logical view
//////////////////////////////////////////////////////////////////////////////
@ -127,6 +136,11 @@ class LogicalView : public LogicalDataSource {
velocypack::Slice definition
);
//////////////////////////////////////////////////////////////////////////////
/// @brief drop an existing view
//////////////////////////////////////////////////////////////////////////////
virtual Result drop() override final;
//////////////////////////////////////////////////////////////////////////////
/// @brief calls the callback on every view found for the specified vocbase
/// @param callback if false is returned then enumiration stops
@ -150,29 +164,15 @@ class LogicalView : public LogicalDataSource {
uint64_t planVersion = 0 // '0' by default for non-cluster
);
//////////////////////////////////////////////////////////////////////////////
/// @brief updates properties of an existing view
//////////////////////////////////////////////////////////////////////////////
using LogicalDataSource::properties;
virtual arangodb::Result properties(
velocypack::Slice const& properties,
bool partialUpdate
) override = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief opens an existing view when the server is restarted
//////////////////////////////////////////////////////////////////////////////
virtual void open() = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief drop an existing view
//////////////////////////////////////////////////////////////////////////////
virtual arangodb::Result drop() override = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief renames an existing view
//////////////////////////////////////////////////////////////////////////////
virtual Result rename(std::string&& newName) override = 0;
virtual Result rename(std::string&& newName) override final;
//////////////////////////////////////////////////////////////////////////////
/// @brief invoke visitor on all collections that a view will return
@ -187,6 +187,27 @@ class LogicalView : public LogicalDataSource {
uint64_t planVersion
);
//////////////////////////////////////////////////////////////////////////////
/// @brief queries properties of an existing view
//////////////////////////////////////////////////////////////////////////////
virtual Result appendVelocyPackImpl(
velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief drop implementation-specific parts of an existing view
/// including persisted properties
//////////////////////////////////////////////////////////////////////////////
virtual Result dropImpl() = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief renames implementation-specific parts of an existing view
/// including persistance of properties
//////////////////////////////////////////////////////////////////////////////
virtual Result renameImpl(std::string const& oldName) = 0;
private:
// FIXME seems to be ugly
friend struct ::TRI_vocbase_t;
@ -196,91 +217,57 @@ class LogicalView : public LogicalDataSource {
}; // LogicalView
////////////////////////////////////////////////////////////////////////////////
/// @brief a LogicalView base class for ClusterInfo view implementations
/// @brief a helper for ClusterInfo View operations
////////////////////////////////////////////////////////////////////////////////
class LogicalViewClusterInfo: public LogicalView {
public:
virtual Result drop() override final;
virtual Result rename(std::string&& newName) override final;
protected:
LogicalViewClusterInfo(
struct LogicalViewHelperClusterInfo {
static Result construct(
LogicalView::ptr& view,
TRI_vocbase_t& vocbase,
velocypack::Slice const& definition,
uint64_t planVersion
);
velocypack::Slice const& definition
) noexcept;
virtual Result appendVelocyPack(
arangodb::velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const override final;
static Result destruct(LogicalView const& view) noexcept;
static Result drop(LogicalView const& view) noexcept;
//////////////////////////////////////////////////////////////////////////////
/// @brief fill and return a jSON description of a View object implementation
//////////////////////////////////////////////////////////////////////////////
virtual arangodb::Result appendVelocyPackDetailed(
static Result properties(
velocypack::Builder& builder,
bool forPersistence
) const = 0;
LogicalView const& view
) noexcept;
protected:
//////////////////////////////////////////////////////////////////////////////
/// @brief drop implementation-specific parts of an existing view
//////////////////////////////////////////////////////////////////////////////
virtual arangodb::Result dropImpl() = 0;
static Result properties(
LogicalView const& view
) noexcept;
static Result rename(
LogicalView const& view,
std::string const& oldName
) noexcept;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief a LogicalView base class for StorageEngine view implementations
/// @brief a helper for StorageEngine View operations
////////////////////////////////////////////////////////////////////////////////
class LogicalViewStorageEngine: public LogicalView {
public:
~LogicalViewStorageEngine() override;
virtual Result drop() override final;
using LogicalDataSource::properties;
virtual arangodb::Result properties(
velocypack::Slice const& properties,
bool partialUpdate
) override final;
virtual Result rename(std::string&& newName) override final;
protected:
LogicalViewStorageEngine(
struct LogicalViewHelperStorageEngine {
static Result construct(
LogicalView::ptr& view,
TRI_vocbase_t& vocbase,
velocypack::Slice const& definition,
uint64_t planVersion
);
velocypack::Slice const& definition
) noexcept;
virtual Result appendVelocyPack(
arangodb::velocypack::Builder& builder,
bool detailed,
bool forPersistence
) const override final;
static Result destruct(LogicalView const& view) noexcept;
static Result drop(LogicalView const& view) noexcept;
//////////////////////////////////////////////////////////////////////////////
/// @brief fill and return a jSON description of a View object implementation
//////////////////////////////////////////////////////////////////////////////
virtual arangodb::Result appendVelocyPackDetailed(
static Result properties(
velocypack::Builder& builder,
bool forPersistence
) const = 0;
LogicalView const& view
) noexcept;
//////////////////////////////////////////////////////////////////////////////
/// @brief drop implementation-specific parts of an existing view
//////////////////////////////////////////////////////////////////////////////
virtual arangodb::Result dropImpl() = 0;
static Result properties(LogicalView const& view) noexcept;
///////////////////////////////////////////////////////////////////////////////
/// @brief called when a view's properties are updated (i.e. delta-modified)
///////////////////////////////////////////////////////////////////////////////
virtual arangodb::Result updateProperties(
velocypack::Slice const& slice,
bool partialUpdate
) = 0;
static Result rename(
LogicalView const& view,
std::string const& oldName
) noexcept;
};
} // namespace arangodb

View File

@ -1353,7 +1353,7 @@ arangodb::Result TRI_vocbase_t::dropCollection(
/// @brief renames a view
arangodb::Result TRI_vocbase_t::renameView(
TRI_voc_cid_t cid,
std::string const& newName
std::string const& oldName
) {
TRI_ASSERT(!ServerState::instance()->isCoordinator());
auto const view = lookupView(cid);
@ -1362,8 +1362,28 @@ arangodb::Result TRI_vocbase_t::renameView(
return TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND;
}
auto* databaseFeature = application_features::ApplicationServer::lookupFeature<
DatabaseFeature
>("Database");
if (!databaseFeature) {
return Result(
TRI_ERROR_INTERNAL,
std::string("failed to find feature 'Database' while renaming view '") + view->name() + "' in database '" + name() + "'"
);
}
auto* engine = EngineSelectorFeature::ENGINE;
if (!engine) {
return arangodb::Result(
TRI_ERROR_INTERNAL,
std::string("failed to find StorageEngine while renaming view '") + view->name() + "' in database '" + name() + "'"
);
}
// lock collection because we are going to copy its current name
std::string oldName = view->name();
auto newName = view->name();
// old name should be different
@ -1398,6 +1418,15 @@ arangodb::Result TRI_vocbase_t::renameView(
TRI_ASSERT(std::dynamic_pointer_cast<arangodb::LogicalView>(itr1->second));
auto doSync = databaseFeature->forceSyncProperties();
auto res = engine->inRecovery()
? arangodb::Result() // skip persistence while in recovery since definition already from engine
: engine->changeView(*this, *view, doSync);
if (!res.ok()) {
return res;
}
// stores the parameters on disk
auto itr2 = _dataSourceByName.emplace(newName, itr1->second);
@ -1717,15 +1746,16 @@ arangodb::Result TRI_vocbase_t::dropView(
TRI_ASSERT(writeLocker.isLocked());
TRI_ASSERT(locker.isLocked());
arangodb::aql::PlanCache::instance()->invalidate(this);
arangodb::aql::QueryCache::instance()->invalidate(this);
auto res = engine->dropView(*this, *view);
if (!res.ok()) {
return res;
}
// invalidate all entries in the plan and query cache now
arangodb::aql::PlanCache::instance()->invalidate(this);
arangodb::aql::QueryCache::instance()->invalidate(this);
unregisterView(*view);
locker.unlock();
@ -2205,4 +2235,4 @@ TRI_voc_rid_t TRI_StringToRid(char const* p, size_t len, bool& isOld,
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -333,7 +333,7 @@ struct TRI_vocbase_t {
/// @brief renames a view
arangodb::Result renameView(
TRI_voc_cid_t cid,
std::string const& newName
std::string const& oldName
);
/// @brief creates a new collection from parameter set
@ -454,4 +454,4 @@ void TRI_SanitizeObject(arangodb::velocypack::Slice const slice,
void TRI_SanitizeObjectWithEdges(arangodb::velocypack::Slice const slice,
arangodb::velocypack::Builder& builder);
#endif
#endif

View File

@ -54,26 +54,13 @@ struct TestView: public arangodb::LogicalView {
TestView(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition, uint64_t planVersion)
: arangodb::LogicalView(vocbase, definition, planVersion), _definition(definition) {
}
virtual arangodb::Result appendVelocyPack(arangodb::velocypack::Builder& builder, bool , bool) const override {
virtual arangodb::Result appendVelocyPackImpl(arangodb::velocypack::Builder& builder, bool , bool) const override {
return arangodb::iresearch::mergeSlice(builder, _definition.slice()) ? TRI_ERROR_NO_ERROR : TRI_ERROR_INTERNAL;
}
virtual arangodb::Result drop() override {
auto* ci = arangodb::ClusterInfo::instance();
if (!ci) {
return TRI_ERROR_INTERNAL;
}
deleted(true);
std::string error;
auto res = ci->dropViewCoordinator(vocbase().name(), std::to_string(id()), error);
return arangodb::Result(res, error);
}
virtual arangodb::Result dropImpl() override { return arangodb::LogicalViewHelperClusterInfo::drop(*this); }
virtual void open() override {}
virtual arangodb::Result properties(arangodb::velocypack::Slice const&, bool) override { return arangodb::Result(); }
virtual arangodb::Result rename(std::string&& newName) override { name(std::move(newName)); return arangodb::Result(); }
virtual arangodb::Result renameImpl(std::string const& oldName) override { return arangodb::LogicalViewHelperStorageEngine::rename(*this, oldName); }
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
};
@ -277,4 +264,4 @@ SECTION("test_drop_databse") {
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -1638,8 +1638,7 @@ TEST_CASE("IResearchQueryTestJoin", "[iresearch][iresearch-query]") {
));
auto queryResult = arangodb::tests::executeQuery(vocbase, query);
//REQUIRE(TRI_ERROR_NOT_IMPLEMENTED == queryResult.code);
REQUIRE(TRI_ERROR_NO_ERROR == queryResult.code); // FIXME TODO check, has this case been implmemented?
REQUIRE(TRI_ERROR_NOT_IMPLEMENTED == queryResult.code);
}
// multiple sorts (not supported now)

View File

@ -1066,7 +1066,7 @@ SECTION("test_drop_cid") {
arangodb::DatabaseFeature
>("Database");
CHECK_THROWS((feature->recoveryDone()));
CHECK_NOTHROW((feature->recoveryDone()));
}
}
}
@ -1573,7 +1573,7 @@ SECTION("test_emplace_cid") {
arangodb::DatabaseFeature
>("Database");
CHECK_THROWS((feature->recoveryDone()));
CHECK_NOTHROW((feature->recoveryDone()));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1194,8 +1194,8 @@ void StorageEngineMock::destroyCollection(
}
void StorageEngineMock::destroyView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView& view
TRI_vocbase_t const& vocbase,
arangodb::LogicalView const& view
) noexcept {
before();
// NOOP, assume physical view destroyed OK
@ -1214,8 +1214,8 @@ arangodb::Result StorageEngineMock::dropDatabase(TRI_vocbase_t& vocbase) {
}
arangodb::Result StorageEngineMock::dropView(
TRI_vocbase_t& vocbase,
arangodb::LogicalView& view
TRI_vocbase_t const& vocbase,
arangodb::LogicalView const& view
) {
before();
TRI_ASSERT(views.find(std::make_pair(vocbase.id(), view.id())) != views.end());

View File

@ -188,10 +188,10 @@ class StorageEngineMock: public arangodb::StorageEngine {
virtual TRI_voc_tick_t currentTick() const override;
virtual std::string databasePath(TRI_vocbase_t const* vocbase) const override;
virtual void destroyCollection(TRI_vocbase_t& vocbase, arangodb::LogicalCollection& collection) override;
virtual void destroyView(TRI_vocbase_t& vocbase, arangodb::LogicalView& view) noexcept override;
virtual void destroyView(TRI_vocbase_t const& vocbase, arangodb::LogicalView const& view) noexcept override;
virtual arangodb::Result dropCollection(TRI_vocbase_t& vocbase, arangodb::LogicalCollection& collection) override;
virtual arangodb::Result dropDatabase(TRI_vocbase_t& vocbase) override;
virtual arangodb::Result dropView(TRI_vocbase_t& vocbase, arangodb::LogicalView& view) override;
virtual arangodb::Result dropView(TRI_vocbase_t const& vocbase, arangodb::LogicalView const& view) override;
virtual arangodb::Result firstTick(uint64_t&) override;
virtual std::vector<std::string> currentWalFiles() const override;
virtual arangodb::Result flushWal(bool waitForSync, bool waitForCollector, bool writeShutdownFile) override;

View File

@ -56,13 +56,13 @@ struct TestView: public arangodb::LogicalView {
TestView(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition, uint64_t planVersion)
: arangodb::LogicalView(vocbase, definition, planVersion) {
}
virtual arangodb::Result appendVelocyPack(arangodb::velocypack::Builder& builder, bool /*detailed*/, bool /*forPersistence*/) const override {
virtual arangodb::Result appendVelocyPackImpl(arangodb::velocypack::Builder& builder, bool, bool) const override {
builder.add("properties", _properties.slice());
return _appendVelocyPackResult;
}
virtual arangodb::Result drop() override { return arangodb::Result(); }
virtual arangodb::Result dropImpl() override { return arangodb::Result(); }
virtual void open() override {}
virtual arangodb::Result rename(std::string&& newName) override { name(std::move(newName)); return arangodb::Result(); }
virtual arangodb::Result renameImpl(std::string const&) override { return arangodb::Result(); }
virtual arangodb::Result properties(arangodb::velocypack::Slice const& properties, bool partialUpdate) override { _properties = arangodb::velocypack::Builder(properties); return arangodb::Result(); }
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
};

View File

@ -46,13 +46,13 @@ struct TestView: public arangodb::LogicalView {
TestView(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition, uint64_t planVersion)
: arangodb::LogicalView(vocbase, definition, planVersion) {
}
virtual arangodb::Result appendVelocyPack(arangodb::velocypack::Builder& builder, bool /*detailed*/, bool /*forPersistence*/) const override {
virtual arangodb::Result appendVelocyPackImpl(arangodb::velocypack::Builder& builder, bool, bool) const override {
builder.add("properties", _properties.slice());
return _appendVelocyPackResult;
}
virtual arangodb::Result drop() override { return vocbase().dropView(id(), true); }
virtual arangodb::Result dropImpl() override { return arangodb::LogicalViewHelperStorageEngine::drop(*this); }
virtual void open() override {}
virtual arangodb::Result rename(std::string&& newName) override { auto res = vocbase().renameView(id(), newName); name(std::move(newName)); return res; }
virtual arangodb::Result renameImpl(std::string const& oldName) override { return arangodb::LogicalViewHelperStorageEngine::rename(*this, oldName); }
virtual arangodb::Result properties(arangodb::velocypack::Slice const& properties, bool partialUpdate) override { _properties = arangodb::velocypack::Builder(properties); return arangodb::Result(); }
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
};

View File

@ -40,10 +40,10 @@ struct TestView: public arangodb::LogicalView {
TestView(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition, uint64_t planVersion)
: arangodb::LogicalView(vocbase, definition, planVersion) {
}
virtual arangodb::Result appendVelocyPack(arangodb::velocypack::Builder&, bool , bool) const override { return arangodb::Result(); }
virtual arangodb::Result drop() override { deleted(true); return vocbase().dropView(id(), true); }
virtual arangodb::Result appendVelocyPackImpl(arangodb::velocypack::Builder&, bool , bool) const override { return arangodb::Result(); }
virtual arangodb::Result dropImpl() override { return arangodb::LogicalViewHelperStorageEngine::drop(*this); }
virtual void open() override {}
virtual arangodb::Result rename(std::string&& newName) override { name(std::move(newName)); return arangodb::Result(); }
virtual arangodb::Result renameImpl(std::string const& oldName) override { return arangodb::LogicalViewHelperStorageEngine::rename(* this, oldName); }
virtual arangodb::Result properties(arangodb::velocypack::Slice const&, bool) override { return arangodb::Result(); }
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
};

View File

@ -75,13 +75,13 @@ struct TestView: public arangodb::LogicalView {
TestView(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition, uint64_t planVersion)
: arangodb::LogicalView(vocbase, definition, planVersion) {
}
virtual arangodb::Result appendVelocyPack(arangodb::velocypack::Builder& builder, bool /*detailed*/, bool /*forPersistence*/) const override {
virtual arangodb::Result appendVelocyPackImpl(arangodb::velocypack::Builder& builder, bool, bool) const override {
builder.add("properties", _properties.slice());
return _appendVelocyPackResult;
}
virtual arangodb::Result drop() override { return arangodb::Result(); }
virtual arangodb::Result dropImpl() override { return arangodb::Result(); }
virtual void open() override {}
virtual arangodb::Result rename(std::string&& newName) override { name(std::move(newName)); return arangodb::Result(); }
virtual arangodb::Result renameImpl(std::string const&) override { return arangodb::Result(); }
virtual arangodb::Result properties(arangodb::velocypack::Slice const& properties, bool partialUpdate) override { _properties = arangodb::velocypack::Builder(properties); return arangodb::Result(); }
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
};

View File

@ -73,13 +73,13 @@ struct TestView: public arangodb::LogicalView {
TestView(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition, uint64_t planVersion)
: arangodb::LogicalView(vocbase, definition, planVersion) {
}
virtual arangodb::Result appendVelocyPack(arangodb::velocypack::Builder& builder, bool /*detailed*/, bool /*forPersistence*/) const override {
virtual arangodb::Result appendVelocyPackImpl(arangodb::velocypack::Builder& builder, bool, bool) const override {
builder.add("properties", _properties.slice());
return _appendVelocyPackResult;
}
virtual arangodb::Result drop() override { return vocbase().dropView(id(), true); }
virtual arangodb::Result dropImpl() override { return arangodb::LogicalViewHelperStorageEngine::drop(*this); }
virtual void open() override {}
virtual arangodb::Result rename(std::string&& newName) override { auto res = vocbase().renameView(id(), newName); name(std::move(newName)); return res; }
virtual arangodb::Result renameImpl(std::string const& oldName) override { return arangodb::LogicalViewHelperStorageEngine::rename(*this, oldName); }
virtual arangodb::Result properties(arangodb::velocypack::Slice const& properties, bool partialUpdate) override { _properties = arangodb::velocypack::Builder(properties); return arangodb::Result(); }
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
};

View File

@ -107,9 +107,10 @@ SECTION("test_category") {
LogicalViewImpl(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition)
: LogicalView(vocbase, definition, 0) {
}
virtual arangodb::Result drop() override { return arangodb::Result(); }
virtual arangodb::Result appendVelocyPackImpl(arangodb::velocypack::Builder&, bool, bool) const override { return arangodb::Result(); }
virtual arangodb::Result dropImpl() override { return arangodb::Result(); }
virtual void open() override {}
virtual arangodb::Result rename(std::string&& newName) override { return arangodb::Result(); }
virtual arangodb::Result renameImpl(std::string const&) override { return arangodb::Result(); }
virtual arangodb::Result properties(arangodb::velocypack::Slice const& properties, bool partialUpdate) override { return arangodb::Result(); }
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
};
@ -141,9 +142,10 @@ SECTION("test_construct") {
LogicalViewImpl(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition)
: LogicalView(vocbase, definition, 0) {
}
virtual arangodb::Result drop() override { return arangodb::Result(); }
virtual arangodb::Result appendVelocyPackImpl(arangodb::velocypack::Builder&, bool, bool) const override { return arangodb::Result(); }
virtual arangodb::Result dropImpl() override { return arangodb::Result(); }
virtual void open() override {}
virtual arangodb::Result rename(std::string&& newName) override { return arangodb::Result(); }
virtual arangodb::Result renameImpl(std::string const&) override { return arangodb::Result(); }
virtual arangodb::Result properties(arangodb::velocypack::Slice const& properties, bool partialUpdate) override { return arangodb::Result(); }
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
};
@ -177,9 +179,10 @@ SECTION("test_defaults") {
LogicalViewImpl(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition)
: LogicalView(vocbase, definition, 0) {
}
virtual arangodb::Result drop() override { return arangodb::Result(); }
virtual arangodb::Result appendVelocyPackImpl(arangodb::velocypack::Builder&, bool, bool) const override { return arangodb::Result(); }
virtual arangodb::Result dropImpl() override { return arangodb::Result(); }
virtual void open() override {}
virtual arangodb::Result rename(std::string&& newName) override { return arangodb::Result(); }
virtual arangodb::Result renameImpl(std::string const&) override { return arangodb::Result(); }
virtual arangodb::Result properties(arangodb::velocypack::Slice const& properties, bool partialUpdate) override { return arangodb::Result(); }
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
};
@ -203,4 +206,4 @@ SECTION("test_defaults") {
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -41,10 +41,10 @@ struct TestView: public arangodb::LogicalView {
TestView(TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& definition, uint64_t planVersion)
: arangodb::LogicalView(vocbase, definition, planVersion) {
}
virtual arangodb::Result appendVelocyPack(arangodb::velocypack::Builder&, bool , bool) const override { return arangodb::Result(); }
virtual arangodb::Result drop() override { deleted(true); return vocbase().dropView(id(), true); }
virtual arangodb::Result appendVelocyPackImpl(arangodb::velocypack::Builder&, bool , bool) const override { return arangodb::Result(); }
virtual arangodb::Result dropImpl() override { return arangodb::LogicalViewHelperStorageEngine::drop(*this); }
virtual void open() override {}
virtual arangodb::Result rename(std::string&& newName) override { name(std::move(newName)); return arangodb::Result(); }
virtual arangodb::Result renameImpl(std::string const& oldName) override { return arangodb::LogicalViewHelperStorageEngine::rename(*this, oldName); }
virtual arangodb::Result properties(arangodb::velocypack::Slice const&, bool) override { return arangodb::Result(); }
virtual bool visitCollections(CollectionVisitor const& visitor) const override { return true; }
};