mirror of https://gitee.com/bigwinds/arangodb
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:
parent
2846bdc393
commit
f1bf5cc9cf
|
@ -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
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -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
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -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
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
|
@ -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; }
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue