mirror of https://gitee.com/bigwinds/arangodb
issue 399.1: store only transient link information by IResearchViewCoordinator (#5834)
* issue 399.1: store only transient link information by IResearchViewCoordinator * some fixes
This commit is contained in:
parent
ef6e5dd8df
commit
57d2517bd6
|
@ -33,7 +33,7 @@
|
|||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::aql;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
std::string const doneString = "DONE";
|
||||
|
@ -54,6 +54,13 @@ static std::string const& stateToString(ExecutionState state) {
|
|||
return unknownString;
|
||||
}
|
||||
|
||||
struct ExecutionBlockTypeHash {
|
||||
size_t operator()(ExecutionBlock::Type value) const noexcept {
|
||||
typedef std::underlying_type<decltype(value)>::type UnderlyingType;
|
||||
return std::hash<UnderlyingType>()(UnderlyingType(value));
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, arangodb::aql::ExecutionBlock::Type> const NamesToBlockTypeMap = {
|
||||
{ "-undefined-", arangodb::aql::ExecutionBlock::Type::_UNDEFINED},
|
||||
{ "CalculationBlock", arangodb::aql::ExecutionBlock::Type::CALCULATION},
|
||||
|
@ -83,23 +90,34 @@ std::unordered_map<std::string, arangodb::aql::ExecutionBlock::Type> const Names
|
|||
{ "UpsertBlock", arangodb::aql::ExecutionBlock::Type::UPSERT},
|
||||
{ "ScatterBlock", arangodb::aql::ExecutionBlock::Type::SCATTER},
|
||||
{ "DistributeBlock", arangodb::aql::ExecutionBlock::Type::DISTRIBUTE},
|
||||
#ifdef USE_IRESEARCH
|
||||
{ "IResearchViewBlock", arangodb::aql::ExecutionBlock::Type::IRESEARCH_VIEW},
|
||||
{ "IResearchViewOrderedBlock", arangodb::aql::ExecutionBlock::Type::IRESEARCH_VIEW_ORDERED},
|
||||
{ "IResearchViewUnorderedBlock", arangodb::aql::ExecutionBlock::Type::IRESEARCH_VIEW_UNORDERED}
|
||||
#endif
|
||||
};
|
||||
std::unordered_map<arangodb::aql::ExecutionBlock::Type, std::string> blockTypeToNamesMap;
|
||||
|
||||
std::unordered_map<
|
||||
arangodb::aql::ExecutionBlock::Type,
|
||||
std::reference_wrapper<const std::string>,
|
||||
ExecutionBlockTypeHash
|
||||
> blockTypeToNamesMap;
|
||||
|
||||
struct BlockTypeToNameMapInitializer {
|
||||
BlockTypeToNameMapInitializer() {
|
||||
blockTypeToNamesMap.reserve(NamesToBlockTypeMap.size());
|
||||
std::for_each(NamesToBlockTypeMap.begin(),
|
||||
NamesToBlockTypeMap.end(),
|
||||
[](std::pair<std::string const&, arangodb::aql::ExecutionBlock::Type> const& p) {
|
||||
blockTypeToNamesMap.emplace(p.second, p.first);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
} initializeBlockTypeToNameMap;
|
||||
|
||||
} // namespace
|
||||
|
||||
void ExecutionBlock::init() {
|
||||
blockTypeToNamesMap.reserve(NamesToBlockTypeMap.size());
|
||||
std::for_each(NamesToBlockTypeMap.begin(),
|
||||
NamesToBlockTypeMap.end(),
|
||||
[](std::pair<std::string const&, arangodb::aql::ExecutionBlock::Type> const& p) {
|
||||
blockTypeToNamesMap.insert(std::make_pair(p.second, p.first));
|
||||
});
|
||||
}
|
||||
|
||||
ExecutionBlock::ExecutionBlock(ExecutionEngine* engine, ExecutionNode const* ep)
|
||||
: _engine(engine),
|
||||
_trx(engine->getQuery()->trx()),
|
||||
|
|
|
@ -111,9 +111,11 @@ class ExecutionBlock {
|
|||
UPSERT,
|
||||
SCATTER,
|
||||
DISTRIBUTE,
|
||||
#ifdef USE_IRESEARCH
|
||||
IRESEARCH_VIEW,
|
||||
IRESEARCH_VIEW_ORDERED,
|
||||
IRESEARCH_VIEW_UNORDERED,
|
||||
#endif
|
||||
};
|
||||
// omitted in this list are (because):
|
||||
// WaitingExecutionBlockMock (mock)
|
||||
|
@ -124,7 +126,6 @@ class ExecutionBlock {
|
|||
|
||||
static std::string typeToString(Type type);
|
||||
static Type typeFromString(std::string const& type);
|
||||
static void init();
|
||||
|
||||
public:
|
||||
/// @brief batch size value
|
||||
|
|
|
@ -69,47 +69,6 @@ IResearchLinkCoordinator::IResearchLinkCoordinator(
|
|||
_sparse = true; // always sparse
|
||||
}
|
||||
|
||||
IResearchLinkCoordinator::~IResearchLinkCoordinator() {
|
||||
if (!_collection || !_view) {
|
||||
return; // nothing else can be done
|
||||
}
|
||||
|
||||
if (_collection->deleted()
|
||||
|| TRI_vocbase_col_status_e::TRI_VOC_COL_STATUS_DELETED == _collection->status()) {
|
||||
_view->drop(_collection->id());
|
||||
}
|
||||
}
|
||||
|
||||
int IResearchLinkCoordinator::drop() {
|
||||
if (!_collection) {
|
||||
return TRI_ERROR_ARANGO_COLLECTION_NOT_LOADED; // '_collection' required
|
||||
}
|
||||
|
||||
if (!_view) {
|
||||
return TRI_ERROR_ARANGO_COLLECTION_NOT_LOADED; // IResearchView required
|
||||
}
|
||||
|
||||
// if the collection is in the process of being removed then drop it from the view
|
||||
if (_collection->deleted()
|
||||
|| TRI_vocbase_col_status_e::TRI_VOC_COL_STATUS_DELETED == _collection->status()) {
|
||||
// revalidate all links
|
||||
auto const result = _view->updateProperties(
|
||||
emptyObjectSlice(), true, false
|
||||
);
|
||||
|
||||
if (!result.ok()) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to force view link revalidation while unloading dropped IResearch link '" << id()
|
||||
<< "' for IResearch view '" << _view->id() << "'";
|
||||
|
||||
return result.errorNumber();
|
||||
}
|
||||
}
|
||||
|
||||
// drop it from view
|
||||
return _view->drop(_collection->id()).errorNumber();
|
||||
}
|
||||
|
||||
bool IResearchLinkCoordinator::operator==(LogicalView const& view) const noexcept {
|
||||
return _view && _view->id() == view.id();
|
||||
}
|
||||
|
@ -159,7 +118,14 @@ bool IResearchLinkCoordinator::init(VPackSlice definition) {
|
|||
|
||||
if (!view) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error finding view: '" << viewId << "' for link '" << id() << "'";
|
||||
<< "error finding view '" << viewId << "' for link '" << id() << "'";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!view->emplace(_collection->id(), _collection->name(), definition)) {
|
||||
LOG_TOPIC(WARN, arangodb::iresearch::TOPIC)
|
||||
<< "error emplacing link to collection '" << _collection->name() << "' into IResearch view '" << viewId << "' link '" << id() << "'";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ class IResearchLinkCoordinator final: public arangodb::Index {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destructor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
virtual ~IResearchLinkCoordinator();
|
||||
virtual ~IResearchLinkCoordinator() = default;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief does this IResearch Link reference the supplied view
|
||||
|
@ -74,7 +74,7 @@ class IResearchLinkCoordinator final: public arangodb::Index {
|
|||
|
||||
virtual bool canBeDropped() const override { return true; }
|
||||
|
||||
virtual int drop() override;
|
||||
virtual int drop() override { return TRI_ERROR_NO_ERROR; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief finds first link between specified collection and view
|
||||
|
|
|
@ -733,12 +733,13 @@ IResearchView::IResearchView(
|
|||
it->_next = _memoryNodes;
|
||||
|
||||
auto* viewPtr = this;
|
||||
auto* iresearchFeature = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
|
||||
_asyncFeature = arangodb::application_features::ApplicationServer::lookupFeature<
|
||||
arangodb::iresearch::IResearchFeature
|
||||
>();
|
||||
|
||||
// add asynchronous commit tasks
|
||||
if (iresearchFeature) {
|
||||
if (_asyncFeature) {
|
||||
struct State: public IResearchViewMeta::CommitMeta {
|
||||
size_t _cleanupIntervalCount;
|
||||
std::chrono::system_clock::time_point _last;
|
||||
|
@ -817,8 +818,7 @@ IResearchView::IResearchView(
|
|||
state
|
||||
);
|
||||
|
||||
iresearchFeature->async(self(), 0, std::move(task));
|
||||
_asyncFeature = iresearchFeature;
|
||||
_asyncFeature->async(self(), 0, std::move(task));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,9 @@
|
|||
|
||||
namespace {
|
||||
|
||||
using namespace arangodb::basics;
|
||||
typedef irs::async_utils::read_write_mutex::read_mutex ReadMutex;
|
||||
typedef irs::async_utils::read_write_mutex::write_mutex WriteMutex;
|
||||
|
||||
using namespace arangodb::iresearch;
|
||||
|
||||
arangodb::Result dropLink(
|
||||
|
@ -127,9 +129,10 @@ arangodb::Result updateLinks(
|
|||
return {
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("error parsing link parameters from json for IResearch view '")
|
||||
+ StringUtils::itoa(view.id())
|
||||
+ view.name()
|
||||
+ "' offset '"
|
||||
+ StringUtils::itoa(linksItr.index()) + '"'
|
||||
+ std::to_string(linksItr.index())
|
||||
+ '"'
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -208,8 +211,9 @@ arangodb::Result updateLinks(
|
|||
return {
|
||||
TRI_ERROR_ARANGO_INDEX_NOT_FOUND,
|
||||
std::string("no link between view '")
|
||||
+ StringUtils::itoa(view.id())
|
||||
+ "' and collection '" + StringUtils::itoa(cid)
|
||||
+ view.name()
|
||||
+ "' and collection '"
|
||||
+ std::to_string(cid)
|
||||
+ "' found"
|
||||
};
|
||||
}
|
||||
|
@ -221,7 +225,7 @@ arangodb::Result updateLinks(
|
|||
auto link = currentLinks.get(collection->name());
|
||||
|
||||
if (!link.isObject()) {
|
||||
auto const collectiondId = StringUtils::itoa(collection->id());
|
||||
auto const collectiondId = std::to_string(collection->id());
|
||||
link = currentLinks.get(collectiondId);
|
||||
|
||||
if (!link.isObject()) {
|
||||
|
@ -256,7 +260,7 @@ namespace iresearch {
|
|||
arangodb::Result IResearchViewCoordinator::appendVelocyPack(
|
||||
arangodb::velocypack::Builder& builder,
|
||||
bool detailed,
|
||||
bool //forPersistence
|
||||
bool forPersistence
|
||||
) const {
|
||||
if (!builder.isOpenObject()) {
|
||||
return arangodb::Result(
|
||||
|
@ -279,12 +283,29 @@ arangodb::Result IResearchViewCoordinator::appendVelocyPack(
|
|||
arangodb::velocypack::Value(arangodb::velocypack::ValueType::Object)
|
||||
);
|
||||
_meta.json(builder); // regular properites
|
||||
_metaState.json(builder); // regular properites
|
||||
|
||||
auto links = _links.slice();
|
||||
arangodb::velocypack::Builder links;
|
||||
IResearchViewMetaState metaState;
|
||||
|
||||
if (links.isObject() && links.length()) {
|
||||
builder.add(StaticStrings::LinksField, links);
|
||||
{
|
||||
ReadMutex mutex(_mutex);
|
||||
SCOPED_LOCK(mutex); // '_collections' can be asynchronously modified
|
||||
|
||||
links.openObject();
|
||||
|
||||
for (auto& entry: _collections) {
|
||||
links.add(entry.second.first, entry.second.second.slice());
|
||||
metaState._collections.emplace(entry.first);
|
||||
}
|
||||
|
||||
links.close();
|
||||
}
|
||||
|
||||
metaState.json(builder); // FIXME TODO remove and fix JavaScript tests (no longer required)
|
||||
|
||||
// links are not persisted, their definitions are part of the corresponding collections
|
||||
if (!forPersistence) {
|
||||
builder.add(StaticStrings::LinksField, links.slice());
|
||||
}
|
||||
|
||||
builder.close(); // close PROPERTIES_FIELD
|
||||
|
@ -292,6 +313,42 @@ arangodb::Result IResearchViewCoordinator::appendVelocyPack(
|
|||
return arangodb::Result();
|
||||
}
|
||||
|
||||
bool IResearchViewCoordinator::emplace(
|
||||
TRI_voc_cid_t cid,
|
||||
std::string const& key,
|
||||
arangodb::velocypack::Slice const& value
|
||||
) {
|
||||
static const std::function<bool(irs::string_ref const& key)> acceptor = [](
|
||||
irs::string_ref const& key
|
||||
)->bool {
|
||||
return key != arangodb::StaticStrings::IndexType
|
||||
&& key != StaticStrings::ViewIdField; // ignored fields
|
||||
};
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
|
||||
// strip internal keys (added in createLink(...)) from externally visible link definition
|
||||
if (!mergeSliceSkipKeys(builder, value, acceptor)) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "failed to generate externally visible link definition while emplacing link definition into IResearch view '"
|
||||
<< name() << "' collection '" << cid << "'";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.close();
|
||||
|
||||
WriteMutex mutex(_mutex);
|
||||
SCOPED_LOCK(mutex); // '_collections' can be asynchronously read
|
||||
|
||||
return _collections.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(cid),
|
||||
std::forward_as_tuple(key, std::move(builder))
|
||||
).second;
|
||||
}
|
||||
|
||||
/*static*/ std::shared_ptr<LogicalView> IResearchViewCoordinator::make(
|
||||
TRI_vocbase_t& vocbase,
|
||||
velocypack::Slice const& info,
|
||||
|
@ -307,53 +364,13 @@ arangodb::Result IResearchViewCoordinator::appendVelocyPack(
|
|||
auto& properties = props.isObject() ? props : emptyObjectSlice(); // if no 'props' then assume defaults
|
||||
std::string error;
|
||||
|
||||
if (!view->_meta.init(properties, error)
|
||||
|| !view->_metaState.init(properties, error)) {
|
||||
if (!view->_meta.init(properties, error)) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "failed to initialize IResearch view from definition, error: " << error;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto const links = properties.get(StaticStrings::LinksField);
|
||||
IResearchLinkMeta linkMeta;
|
||||
|
||||
if (links.isObject()) {
|
||||
auto& builder = view->_links;
|
||||
VPackObjectBuilder guard(&builder);
|
||||
|
||||
size_t idx = 0;
|
||||
for (auto link : velocypack::ObjectIterator(links)) {
|
||||
auto const nameSlice = link.key;
|
||||
|
||||
if (!nameSlice.isString()) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "failed to initialize IResearch view link from definition at index " << idx
|
||||
<< ", link name is not string";
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!linkMeta.init(link.value, error)) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
<< "failed to initialize IResearch view link from definition at index " << idx
|
||||
<< ", error: " << error;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// append normalized link definition
|
||||
{
|
||||
VPackValueLength length;
|
||||
char const* name = nameSlice.getString(length);
|
||||
|
||||
builder.add(name, length, VPackValue(VPackValueType::Object));
|
||||
linkMeta.json(builder);
|
||||
builder.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (preCommit && !preCommit(view)) {
|
||||
LOG_TOPIC(ERR, arangodb::iresearch::TOPIC)
|
||||
<< "Failure during pre-commit while constructing IResearch View in database '" << vocbase.id() << "'";
|
||||
|
@ -411,8 +428,11 @@ IResearchViewCoordinator::IResearchViewCoordinator(
|
|||
bool IResearchViewCoordinator::visitCollections(
|
||||
CollectionVisitor const& visitor
|
||||
) const {
|
||||
for (auto& cid: _metaState._collections) {
|
||||
if (!visitor(cid)) {
|
||||
ReadMutex mutex(_mutex);
|
||||
SCOPED_LOCK(mutex); // '_collections' can be asynchronously modified
|
||||
|
||||
for (auto& entry: _collections) {
|
||||
if (!visitor(entry.first)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -427,7 +447,6 @@ arangodb::Result IResearchViewCoordinator::updateProperties(
|
|||
) {
|
||||
try {
|
||||
IResearchViewMeta meta;
|
||||
IResearchViewMetaState metaState;
|
||||
std::string error;
|
||||
|
||||
auto const& defaults = partialUpdate
|
||||
|
@ -438,53 +457,85 @@ arangodb::Result IResearchViewCoordinator::updateProperties(
|
|||
return { TRI_ERROR_BAD_PARAMETER, error };
|
||||
}
|
||||
|
||||
VPackBuilder builder;
|
||||
{
|
||||
VPackObjectBuilder const guard(&builder);
|
||||
// only trigger persisting of properties if they have changed
|
||||
if (_meta != meta) {
|
||||
auto* engine = arangodb::ClusterInfo::instance();
|
||||
|
||||
// system properties
|
||||
toVelocyPack(builder, false, true);
|
||||
if (!engine) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
std::string("failure to get storage engine while updating IResearch View '") + name() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
// properties
|
||||
{
|
||||
VPackObjectBuilder const guard(&builder, StaticStrings::PropertiesField);
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
// links
|
||||
{
|
||||
VPackObjectBuilder const guard(&builder, StaticStrings::LinksField);
|
||||
builder.openObject();
|
||||
builder.add(
|
||||
StaticStrings::PropertiesField,
|
||||
arangodb::velocypack::Value(arangodb::velocypack::ValueType::Object)
|
||||
);
|
||||
meta.json(builder);
|
||||
builder.close(); // close PROPERTIES_FIELD
|
||||
|
||||
bool modified = false;
|
||||
auto const res = updateLinks(
|
||||
properties.get(StaticStrings::LinksField),
|
||||
_links.slice(),
|
||||
*this,
|
||||
partialUpdate,
|
||||
_metaState._collections,
|
||||
modified,
|
||||
builder,
|
||||
metaState._collections
|
||||
);
|
||||
auto result = toVelocyPack(builder, false, true);
|
||||
|
||||
if (!res.ok()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!modified && _meta == meta && _metaState == metaState) {
|
||||
// nothing to do
|
||||
return {};
|
||||
}
|
||||
if (!result.ok()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// meta
|
||||
meta.json(builder);
|
||||
metaState.json(builder);
|
||||
builder.close();
|
||||
result = engine->setViewPropertiesCoordinator(
|
||||
vocbase().name(), std::to_string(id()), builder.slice()
|
||||
);
|
||||
|
||||
if (!result.ok()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return ClusterInfo::instance()->setViewPropertiesCoordinator(
|
||||
vocbase().name(), // database name,
|
||||
StringUtils::itoa(id()), // cluster-wide view id
|
||||
builder.slice()
|
||||
if (!properties.hasKey(StaticStrings::LinksField)) {
|
||||
return arangodb::Result(); // nothing more to do
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// update links if requested (on a best-effort basis)
|
||||
// indexing of collections is done in different threads so no locks can be held and rollback is not possible
|
||||
// as a result it's also possible for links to be simultaneously modified via a different callflow (e.g. from collections)
|
||||
// ...........................................................................
|
||||
|
||||
arangodb::velocypack::Builder currentLinks;
|
||||
std::unordered_set<TRI_voc_cid_t> currentCids;
|
||||
|
||||
{
|
||||
ReadMutex mutex(_mutex);
|
||||
SCOPED_LOCK(mutex); // '_collections' can be asynchronously modified
|
||||
|
||||
currentLinks.openObject();
|
||||
|
||||
for (auto& entry: _collections) {
|
||||
currentCids.emplace(entry.first);
|
||||
currentLinks.add(entry.second.first, entry.second.second.slice());
|
||||
}
|
||||
|
||||
currentLinks.close();
|
||||
}
|
||||
|
||||
arangodb::velocypack::Builder viewNewProperties;
|
||||
bool modified = false;
|
||||
std::unordered_set<TRI_voc_cid_t> newCids;
|
||||
|
||||
viewNewProperties.openObject();
|
||||
|
||||
return updateLinks(
|
||||
properties.get(StaticStrings::LinksField),
|
||||
currentLinks.slice(),
|
||||
*this,
|
||||
partialUpdate,
|
||||
currentCids,
|
||||
modified,
|
||||
viewNewProperties,
|
||||
newCids
|
||||
);
|
||||
} catch (std::exception const& e) {
|
||||
LOG_TOPIC(WARN, iresearch::TOPIC)
|
||||
|
@ -510,8 +561,22 @@ arangodb::Result IResearchViewCoordinator::updateProperties(
|
|||
Result IResearchViewCoordinator::drop() {
|
||||
// drop links first
|
||||
{
|
||||
auto const res = updateProperties(
|
||||
VPackSlice::emptyObjectSlice(), false, true
|
||||
std::unordered_set<TRI_voc_cid_t> currentCids;
|
||||
|
||||
visitCollections([¤tCids](TRI_voc_cid_t cid)->bool { currentCids.emplace(cid); return true; });
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
bool modified;
|
||||
std::unordered_set<TRI_voc_cid_t> newCids;
|
||||
auto res = updateLinks(
|
||||
arangodb::velocypack::Slice::emptyObjectSlice(),
|
||||
arangodb::velocypack::Slice::emptyObjectSlice(),
|
||||
*this,
|
||||
false,
|
||||
currentCids,
|
||||
modified,
|
||||
builder,
|
||||
newCids
|
||||
);
|
||||
|
||||
if (!res.ok()) {
|
||||
|
@ -539,26 +604,6 @@ Result IResearchViewCoordinator::drop() {
|
|||
return {};
|
||||
}
|
||||
|
||||
Result IResearchViewCoordinator::drop(TRI_voc_cid_t cid) {
|
||||
auto cid_itr = _metaState._collections.find(cid);
|
||||
|
||||
if (cid_itr == _metaState._collections.end()) {
|
||||
// no such cid
|
||||
return { TRI_ERROR_BAD_PARAMETER };
|
||||
}
|
||||
|
||||
VPackBuilder builder;
|
||||
{
|
||||
VPackObjectBuilder const guard(&builder);
|
||||
{
|
||||
VPackObjectBuilder const guard(&builder, StaticStrings::LinksField);
|
||||
builder.add(StringUtils::itoa(cid), VPackSlice::nullSlice());
|
||||
}
|
||||
}
|
||||
|
||||
return updateProperties(builder.slice(), true, true);
|
||||
}
|
||||
|
||||
} // iresearch
|
||||
} // arangodb
|
||||
|
||||
|
|
|
@ -40,6 +40,22 @@ namespace iresearch {
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
class IResearchViewCoordinator final : public arangodb::LogicalView {
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief acquire locks on the specified 'cid' during read-transactions
|
||||
/// allowing retrieval of documents contained in the aforementioned
|
||||
/// collection
|
||||
/// @note definitions are not persisted
|
||||
/// @param cid the collection ID to track
|
||||
/// @param key the key of the link definition for use in appendVelocyPack(...)
|
||||
/// @param value the link definition to use in appendVelocyPack(...)
|
||||
/// @return the 'cid' was newly added to the IResearch View
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool emplace(
|
||||
TRI_voc_cid_t cid,
|
||||
std::string const& key,
|
||||
arangodb::velocypack::Slice const& value
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief view factory
|
||||
/// @returns initialized view object
|
||||
|
@ -60,9 +76,6 @@ class IResearchViewCoordinator final : public arangodb::LogicalView {
|
|||
|
||||
Result drop() override;
|
||||
|
||||
// drops collection from a view
|
||||
Result drop(TRI_voc_cid_t cid);
|
||||
|
||||
virtual Result rename(
|
||||
std::string&& /*newName*/,
|
||||
bool /*doSync*/
|
||||
|
@ -89,10 +102,9 @@ class IResearchViewCoordinator final : public arangodb::LogicalView {
|
|||
TRI_vocbase_t& vocbase, velocypack::Slice info, uint64_t planVersion
|
||||
);
|
||||
|
||||
std::unordered_map<TRI_voc_cid_t, std::pair<std::string, arangodb::velocypack::Builder>> _collections; // transient member, not persisted
|
||||
mutable irs::async_utils::read_write_mutex _mutex; // for use with '_collections'
|
||||
IResearchViewMeta _meta;
|
||||
IResearchViewMetaState _metaState;
|
||||
velocypack::Builder _links;
|
||||
|
||||
}; // IResearchViewCoordinator
|
||||
|
||||
} // iresearch
|
||||
|
|
|
@ -73,7 +73,6 @@ void AqlFeature::start() {
|
|||
MUTEX_LOCKER(locker, AqlFeature::_aqlFeatureMutex);
|
||||
TRI_ASSERT(_AQL == nullptr);
|
||||
_AQL = this;
|
||||
aql::ExecutionBlock::init();
|
||||
LOG_TOPIC(DEBUG, Logger::QUERIES) << "AQL feature started";
|
||||
}
|
||||
|
||||
|
|
|
@ -239,9 +239,9 @@ static void JS_DropViewVocbase(
|
|||
auto view = vocbase.lookupView(name);
|
||||
|
||||
if (view) {
|
||||
auto res = vocbase.dropView(view->id(), allowDropSystem).errorNumber();
|
||||
auto res = vocbase.dropView(view->id(), allowDropSystem);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
if (!res.ok()) {
|
||||
TRI_V8_THROW_EXCEPTION(res);
|
||||
}
|
||||
}
|
||||
|
@ -285,11 +285,10 @@ static void JS_DropViewVocbaseObj(
|
|||
}
|
||||
}
|
||||
|
||||
auto res =
|
||||
view->vocbase().dropView(view->id(), allowDropSystem).errorNumber();
|
||||
auto res = view->vocbase().dropView(view->id(), allowDropSystem);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(res, "cannot drop view");
|
||||
if (!res.ok()) {
|
||||
TRI_V8_THROW_EXCEPTION(res);
|
||||
}
|
||||
|
||||
TRI_V8_RETURN_UNDEFINED();
|
||||
|
|
|
@ -110,23 +110,22 @@ function IResearchFeatureDDLTestSuite () {
|
|||
}
|
||||
},
|
||||
|
||||
//FIXME
|
||||
// testRemoveLinkViaCollection : function() {
|
||||
// db._drop("TestCollection0");
|
||||
// db._dropView("TestView");
|
||||
//
|
||||
// var view = db._createView("TestView", "arangosearch", {});
|
||||
// db._create("TestCollection0");
|
||||
// var addLink = { links: { "TestCollection0": {} } };
|
||||
// view.properties(addLink, true); // partial update
|
||||
// properties = view.properties();
|
||||
// assertTrue(Array === properties.collections.constructor);
|
||||
// assertEqual(1, properties.collections.length);
|
||||
// db._drop("TestCollection0");
|
||||
// properties = view.properties();
|
||||
// assertTrue(Array === properties.collections.constructor);
|
||||
// assertEqual(0, properties.collections.length);
|
||||
// },
|
||||
testRemoveLinkViaCollection : function() {
|
||||
db._drop("TestCollection0");
|
||||
db._dropView("TestView");
|
||||
|
||||
var view = db._createView("TestView", "arangosearch", {});
|
||||
db._create("TestCollection0");
|
||||
var addLink = { links: { "TestCollection0": {} } };
|
||||
view.properties(addLink, true); // partial update
|
||||
properties = view.properties();
|
||||
assertTrue(Array === properties.collections.constructor);
|
||||
assertEqual(1, properties.collections.length);
|
||||
db._drop("TestCollection0");
|
||||
properties = view.properties();
|
||||
assertTrue(Array === properties.collections.constructor);
|
||||
assertEqual(0, properties.collections.length);
|
||||
},
|
||||
|
||||
testViewDDL: function() {
|
||||
// collections
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "Agency/Store.h"
|
||||
#include "Basics/ArangoGlobalContext.h"
|
||||
#include "Basics/files.h"
|
||||
#include "VocBase/Methods/Indexes.h"
|
||||
|
||||
#if USE_ENTERPRISE
|
||||
#include "Enterprise/Ldap/LdapFeature.h"
|
||||
|
@ -256,15 +257,12 @@ SECTION("test_rename") {
|
|||
}
|
||||
|
||||
SECTION("visit_collections") {
|
||||
auto json = arangodb::velocypack::Parser::fromJson(
|
||||
"{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": \"1\", \"properties\": { \"collections\": [1,2,3] } }");
|
||||
|
||||
auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"testView\", \"type\": \"arangosearch\", \"id\": \"1\" }");
|
||||
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_COORDINATOR, 1, "testVocbase");
|
||||
|
||||
auto view = arangodb::LogicalView::create(vocbase, json->slice(), false); // false == do not persist
|
||||
auto logicalView = arangodb::LogicalView::create(vocbase, json->slice(), false); // false == do not persist
|
||||
auto* view = dynamic_cast<arangodb::iresearch::IResearchViewCoordinator*>(logicalView.get());
|
||||
|
||||
CHECK(nullptr != view);
|
||||
CHECK(nullptr != std::dynamic_pointer_cast<arangodb::iresearch::IResearchViewCoordinator>(view));
|
||||
CHECK(0 == view->planVersion());
|
||||
CHECK("testView" == view->name());
|
||||
CHECK(false == view->deleted());
|
||||
|
@ -273,6 +271,10 @@ SECTION("visit_collections") {
|
|||
CHECK(arangodb::LogicalView::category() == view->category());
|
||||
CHECK(&vocbase == &view->vocbase());
|
||||
|
||||
CHECK((true == view->emplace(1, "1", arangodb::velocypack::Slice::emptyObjectSlice())));
|
||||
CHECK((true == view->emplace(2, "2", arangodb::velocypack::Slice::emptyObjectSlice())));
|
||||
CHECK((true == view->emplace(3, "3", arangodb::velocypack::Slice::emptyObjectSlice())));
|
||||
|
||||
// visit view
|
||||
TRI_voc_cid_t expectedCollections[] = {1,2,3};
|
||||
auto* begin = expectedCollections;
|
||||
|
@ -353,8 +355,8 @@ SECTION("test_defaults") {
|
|||
CHECK(!slice.hasKey("deleted"));
|
||||
slice = slice.get("properties");
|
||||
CHECK(slice.isObject());
|
||||
CHECK((3 == slice.length()));
|
||||
CHECK((!slice.hasKey("links")));
|
||||
CHECK((4 == slice.length()));
|
||||
CHECK((slice.hasKey("links") && slice.get("links").isObject() && 0 == slice.get("links").length()));
|
||||
CHECK((meta.init(slice, error) && expectedMeta == meta));
|
||||
CHECK((true == metaState.init(slice, error) && expectedMetaState == metaState));
|
||||
}
|
||||
|
@ -899,7 +901,7 @@ SECTION("test_update_links_partial_remove") {
|
|||
|
||||
// testCollection2
|
||||
{
|
||||
auto const value = linksSlice.get(std::to_string(logicalCollection2->id()));
|
||||
auto const value = linksSlice.get(logicalCollection2->name());
|
||||
CHECK(value.isObject());
|
||||
|
||||
arangodb::iresearch::IResearchLinkMeta expectedMeta;
|
||||
|
@ -1631,7 +1633,7 @@ SECTION("test_update_links_partial_add") {
|
|||
|
||||
// testCollection2
|
||||
{
|
||||
auto const value = linksSlice.get(std::to_string(logicalCollection2->id()));
|
||||
auto const value = linksSlice.get(logicalCollection2->name());
|
||||
CHECK(value.isObject());
|
||||
|
||||
arangodb::iresearch::IResearchLinkMeta expectedMeta;
|
||||
|
@ -2192,7 +2194,7 @@ SECTION("test_update_links_replace") {
|
|||
|
||||
// testCollection2
|
||||
{
|
||||
auto const value = linksSlice.get(std::to_string(logicalCollection2->id()));
|
||||
auto const value = linksSlice.get(logicalCollection2->name());
|
||||
CHECK(value.isObject());
|
||||
|
||||
arangodb::iresearch::IResearchLinkMeta expectedMeta;
|
||||
|
@ -2521,7 +2523,7 @@ SECTION("test_update_links_clear") {
|
|||
|
||||
// explicitly specify id for the sake of tests
|
||||
auto linksJson = arangodb::velocypack::Parser::fromJson(
|
||||
"{ \"links\" : {"
|
||||
"{ \"locale\": \"en\", \"links\" : {"
|
||||
" \"testCollection1\" : { \"id\": \"1\", \"includeAllFields\" : true }, "
|
||||
" \"2\" : { \"id\": \"2\", \"trackListPositions\" : true }, "
|
||||
" \"testCollection3\" : { \"id\": \"3\" } "
|
||||
|
@ -2588,7 +2590,7 @@ SECTION("test_update_links_clear") {
|
|||
|
||||
// testCollection2
|
||||
{
|
||||
auto const value = linksSlice.get(std::to_string(logicalCollection2->id()));
|
||||
auto const value = linksSlice.get(logicalCollection2->name());
|
||||
CHECK(value.isObject());
|
||||
|
||||
arangodb::iresearch::IResearchLinkMeta expectedMeta;
|
||||
|
@ -2771,7 +2773,7 @@ SECTION("test_update_links_clear") {
|
|||
CHECK(arangodb::AgencyComm().setValue(currentCollection3Path, value->slice(), 0.0).successful());
|
||||
}
|
||||
|
||||
auto const updateJson = arangodb::velocypack::Parser::fromJson("{}");
|
||||
auto const updateJson = arangodb::velocypack::Parser::fromJson("{ \"links\": {}}");
|
||||
CHECK(view->updateProperties(updateJson->slice(), false, true).ok());
|
||||
CHECK(planVersion < arangodb::tests::getCurrentPlanVersion()); // plan version changed
|
||||
planVersion = arangodb::tests::getCurrentPlanVersion();
|
||||
|
@ -2803,7 +2805,10 @@ SECTION("test_update_links_clear") {
|
|||
info.close();
|
||||
|
||||
auto const properties = info.slice().get("properties");
|
||||
CHECK(!properties.hasKey(arangodb::iresearch::StaticStrings::LinksField));
|
||||
CHECK((properties.hasKey(arangodb::iresearch::StaticStrings::LinksField)));
|
||||
auto links = properties.get(arangodb::iresearch::StaticStrings::LinksField);
|
||||
CHECK((links.isObject()));
|
||||
CHECK((0 == links.length()));
|
||||
}
|
||||
|
||||
// test index in testCollection1
|
||||
|
@ -2899,7 +2904,6 @@ SECTION("test_drop_link") {
|
|||
REQUIRE(view);
|
||||
auto const viewId = std::to_string(view->planId());
|
||||
CHECK("42" == viewId);
|
||||
CHECK(TRI_ERROR_BAD_PARAMETER == view->drop(logicalCollection->id()).errorNumber()); // unable to drop nonexistent link
|
||||
|
||||
// simulate heartbeat thread (create index in current)
|
||||
{
|
||||
|
@ -2965,6 +2969,8 @@ SECTION("test_drop_link") {
|
|||
CHECK(expectedMeta == actualMeta);
|
||||
}
|
||||
|
||||
TRI_idx_iid_t linkId;
|
||||
|
||||
// check indexes
|
||||
{
|
||||
// get new version from plan
|
||||
|
@ -2972,6 +2978,7 @@ SECTION("test_drop_link") {
|
|||
REQUIRE(updatedCollection);
|
||||
auto link = arangodb::iresearch::IResearchLinkCoordinator::find(*updatedCollection, *view);
|
||||
CHECK(link);
|
||||
linkId = link->id();
|
||||
|
||||
auto index = std::dynamic_pointer_cast<arangodb::Index>(link);
|
||||
REQUIRE((false == !index));
|
||||
|
@ -3021,7 +3028,7 @@ SECTION("test_drop_link") {
|
|||
}
|
||||
|
||||
// drop link
|
||||
CHECK(view->drop(logicalCollection->id()).ok());
|
||||
CHECK((arangodb::methods::Indexes::drop(logicalCollection.get(), arangodb::velocypack::Parser::fromJson(std::to_string(linkId))->slice()).ok()));
|
||||
CHECK(planVersion < arangodb::tests::getCurrentPlanVersion()); // plan version changed
|
||||
planVersion = arangodb::tests::getCurrentPlanVersion();
|
||||
oldView = view;
|
||||
|
@ -3050,7 +3057,10 @@ SECTION("test_drop_link") {
|
|||
info.close();
|
||||
|
||||
auto const properties = info.slice().get("properties");
|
||||
CHECK(!properties.hasKey(arangodb::iresearch::StaticStrings::LinksField));
|
||||
CHECK((properties.hasKey(arangodb::iresearch::StaticStrings::LinksField)));
|
||||
auto links = properties.get(arangodb::iresearch::StaticStrings::LinksField);
|
||||
CHECK((links.isObject()));
|
||||
CHECK((0 == links.length()));
|
||||
}
|
||||
|
||||
// check indexes
|
||||
|
@ -3165,4 +3175,4 @@ SECTION("IResearchViewNode::createBlock") {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
Loading…
Reference in New Issue