diff --git a/arangod/CMakeLists.txt b/arangod/CMakeLists.txt index ab49162a14..6b3e8d94cc 100644 --- a/arangod/CMakeLists.txt +++ b/arangod/CMakeLists.txt @@ -493,6 +493,7 @@ SET(ARANGOD_SOURCES VocBase/Graphs.cpp VocBase/KeyGenerator.cpp VocBase/LogicalCollection.cpp + VocBase/LogicalDataSource.cpp VocBase/LogicalView.cpp VocBase/ManagedDocumentResult.cpp VocBase/ticks.cpp diff --git a/arangod/IResearch/IResearchFeature.cpp b/arangod/IResearch/IResearchFeature.cpp index ab0feef9ee..022fc01419 100644 --- a/arangod/IResearch/IResearchFeature.cpp +++ b/arangod/IResearch/IResearchFeature.cpp @@ -177,7 +177,7 @@ arangodb::Result transactionStateRegistrationCallback( auto view = vocbase->lookupView(cid); - if (!view || arangodb::iresearch::IResearchView::type() != view->type()) { + if (!view || arangodb::iresearch::IResearchView::type() != view->type().name()) { return arangodb::Result(); // not an IResearchView (noop) } diff --git a/arangod/IResearch/IResearchLink.cpp b/arangod/IResearch/IResearchLink.cpp index fd5f737582..fd55c1585b 100644 --- a/arangod/IResearch/IResearchLink.cpp +++ b/arangod/IResearch/IResearchLink.cpp @@ -240,7 +240,7 @@ bool IResearchLink::init(arangodb::velocypack::Slice const& definition) { // NOTE: this will cause a deadlock if registering a link while view is being created auto logicalView = vocbase->lookupView(viewId); - if (!logicalView || IResearchView::type() != logicalView->type()) { + if (!logicalView || IResearchView::type() != logicalView->type().name()) { LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH) << "error looking up view '" << viewId << "': no such view"; return false; // no such view } @@ -599,4 +599,4 @@ NS_END // arangodb // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/arangod/IResearch/IResearchRocksDBRecoveryHelper.cpp b/arangod/IResearch/IResearchRocksDBRecoveryHelper.cpp index 955258d328..546c4104f3 100644 --- a/arangod/IResearch/IResearchRocksDBRecoveryHelper.cpp +++ b/arangod/IResearch/IResearchRocksDBRecoveryHelper.cpp @@ -211,7 +211,7 @@ void dropCollectionFromAllViews( if (vocbase) { // iterate over vocbase views for (auto logicalView : vocbase->views()) { - if (arangodb::iresearch::IResearchView::type() != logicalView->type()) { + if (arangodb::iresearch::IResearchView::type() != logicalView->type().name()) { continue; } @@ -267,7 +267,7 @@ void dropCollectionFromView( auto logicalView = vocbase->lookupView(viewId); - if (!logicalView || arangodb::iresearch::IResearchView::type() != logicalView->type()) { + if (!logicalView || arangodb::iresearch::IResearchView::type() != logicalView->type().name()) { LOG_TOPIC(TRACE, arangodb::iresearch::IResearchFeature::IRESEARCH) << "error looking up view '" << viewId << "': no such view"; return; @@ -428,3 +428,7 @@ void IResearchRocksDBRecoveryHelper::LogData(const rocksdb::Slice& blob) { } // iresearch } // arangodb + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/arangod/V8Server/v8-views.cpp b/arangod/V8Server/v8-views.cpp index 868e124644..6dcc5e7027 100644 --- a/arangod/V8Server/v8-views.cpp +++ b/arangod/V8Server/v8-views.cpp @@ -505,7 +505,7 @@ static void JS_TypeViewVocbase( LogicalView* view = v->get(); - std::string const type = view->type(); + auto& type = view->type().name(); TRI_V8_RETURN(TRI_V8_STD_STRING(isolate, type)); TRI_V8_TRY_CATCH_END } @@ -546,3 +546,7 @@ void TRI_InitV8Views(v8::Handle context, TRI_vocbase_t* vocbase, TRI_AddGlobalFunctionVocbase(isolate, TRI_V8_ASCII_STRING(isolate, "ArangoView"), ft->GetFunction()); } + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/arangod/VocBase/LogicalCollection.cpp b/arangod/VocBase/LogicalCollection.cpp index 6a741a50d2..13ef9e704c 100644 --- a/arangod/VocBase/LogicalCollection.cpp +++ b/arangod/VocBase/LogicalCollection.cpp @@ -131,33 +131,52 @@ static TRI_voc_cid_t ReadPlanId(VPackSlice info, TRI_voc_cid_t cid) { return cid; } -static std::string const ReadStringValue(VPackSlice info, - std::string const& name, - std::string const& def) { - if (!info.isObject()) { - return def; +std::string ReadStringValue( + arangodb::velocypack::Slice info, + std::string const& name, + std::string const& def +) { + return info.isObject() ? Helper::getStringValue(info, name, def) : def; +} + +arangodb::LogicalDataSource::Type const& ReadType( + arangodb::velocypack::Slice info, + std::string const& key, + TRI_col_type_e def +) { + static const auto& document = + arangodb::LogicalDataSource::Type::emplace("document"); + static const auto& edge = arangodb::LogicalDataSource::Type::emplace("edge"); + + // arbitrary system-global value for unknown + static const auto& unknown = arangodb::LogicalDataSource::Type::emplace(""); + + switch (Helper::readNumericValue(info, key, def)) { + case TRI_col_type_e::TRI_COL_TYPE_DOCUMENT: + return document; + case TRI_col_type_e::TRI_COL_TYPE_EDGE: + return edge; + default: + return unknown; } - return Helper::getStringValue(info, name, def); -} } +} // namespace + /// @brief This the "copy" constructor used in the cluster /// it is required to create objects that survive plan /// modifications and can be freed /// Can only be given to V8, cannot be used for functionality. LogicalCollection::LogicalCollection(LogicalCollection const& other) - : _internalVersion(0), + : LogicalDataSource(other), + _internalVersion(0), _isAStub(other._isAStub), - _cid(other.cid()), - _planId(other.planId()), _type(other.type()), - _name(other.name()), _distributeShardsLike(other._distributeShardsLike), _avoidServers(other.avoidServers()), _status(other.status()), _isSmart(other.isSmart()), _isLocal(false), - _isDeleted(other._isDeleted), _isSystem(other.isSystem()), _waitForSync(other.waitForSync()), _version(other._version), @@ -165,7 +184,6 @@ LogicalCollection::LogicalCollection(LogicalCollection const& other) _numberOfShards(other.numberOfShards()), _allowUserKeys(other.allowUserKeys()), _shardIds(new ShardMap()), // Not needed - _vocbase(other.vocbase()), _keyOptions(other._keyOptions), _keyGenerator(KeyGenerator::factory(VPackSlice(keyOptions()))), _globallyUniqueId(other._globallyUniqueId), @@ -188,20 +206,24 @@ LogicalCollection::LogicalCollection(LogicalCollection const& other) LogicalCollection::LogicalCollection(TRI_vocbase_t* vocbase, VPackSlice const& info, bool isAStub) - : _internalVersion(0), + : LogicalDataSource( + ReadType(info, "type", TRI_COL_TYPE_UNKNOWN), + vocbase, + ReadCid(info), + ReadPlanId(info, ReadCid(info)), + ReadStringValue(info, "name", ""), + Helper::readBooleanValue(info, "deleted", false) + ), + _internalVersion(0), _isAStub(isAStub), - _cid(ReadCid(info)), - _planId(ReadPlanId(info, _cid)), _type(Helper::readNumericValue( info, "type", TRI_COL_TYPE_UNKNOWN)), - _name(ReadStringValue(info, "name", "")), _distributeShardsLike(ReadStringValue(info, "distributeShardsLike", "")), _status(Helper::readNumericValue( info, "status", TRI_VOC_COL_STATUS_CORRUPTED)), _isSmart(Helper::readBooleanValue(info, "isSmart", false)), _isLocal(!ServerState::instance()->isCoordinator()), - _isDeleted(Helper::readBooleanValue(info, "deleted", false)), - _isSystem(IsSystemName(_name) && + _isSystem(IsSystemName(ReadStringValue(info, "name", "")) && Helper::readBooleanValue(info, "isSystem", false)), _waitForSync(Helper::readBooleanValue(info, "waitForSync", false)), _version(Helper::readNumericValue(info, "version", @@ -211,7 +233,6 @@ LogicalCollection::LogicalCollection(TRI_vocbase_t* vocbase, Helper::readNumericValue(info, "numberOfShards", 1)), _allowUserKeys(Helper::readBooleanValue(info, "allowUserKeys", true)), _shardIds(new ShardMap()), - _vocbase(vocbase), _keyOptions(nullptr), _keyGenerator(), _globallyUniqueId(Helper::getStringValue(info, "globallyUniqueId", "")), @@ -219,29 +240,28 @@ LogicalCollection::LogicalCollection(TRI_vocbase_t* vocbase, EngineSelectorFeature::ENGINE->createPhysicalCollection(this, info)), _clusterEstimateTTL(0), _planVersion(0) { - TRI_ASSERT(info.isObject()); if (!IsAllowedName(info)) { THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_ILLEGAL_NAME); } - + if (_version < minimumVersion()) { // collection is too "old" - std::string errorMsg(std::string("collection '") + _name + + std::string errorMsg(std::string("collection '") + name() + "' has a too old version. Please start the server " "with the --database.auto-upgrade option."); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_FAILED, errorMsg); } - + if (_globallyUniqueId.empty()) { // no id found. generate a new one _globallyUniqueId = generateGloballyUniqueId(); } - + TRI_ASSERT(!_globallyUniqueId.empty()); - + // add keyOptions from slice VPackSlice keyOpts = info.get("keyOptions"); _keyGenerator.reset(KeyGenerator::factory(keyOpts)); @@ -341,8 +361,10 @@ LogicalCollection::LogicalCollection(TRI_vocbase_t* vocbase, } if (_shardKeys.empty() || _shardKeys.size() > 8) { - THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, - std::string("invalid number of shard keys for collection '") + _name + "'"); + THROW_ARANGO_EXCEPTION_MESSAGE( + TRI_ERROR_BAD_PARAMETER, + std::string("invalid number of shard keys for collection '") + name() + "'" + ); } auto shardsSlice = info.get("shards"); @@ -383,8 +405,8 @@ LogicalCollection::LogicalCollection(TRI_vocbase_t* vocbase, } // update server's tick value - TRI_UpdateTickServer(static_cast(_cid)); - + TRI_UpdateTickServer(static_cast(id())); + TRI_ASSERT(_physical != nullptr); // This has to be called AFTER _phyiscal and _logical are properly linked // together. @@ -506,23 +528,15 @@ uint64_t LogicalCollection::numberDocuments(transaction::Methods* trx) const { uint32_t LogicalCollection::internalVersion() const { return _internalVersion; } std::string LogicalCollection::cid_as_string() const { - return basics::StringUtils::itoa(_cid); + return std::to_string(id()); } -TRI_voc_cid_t LogicalCollection::planId() const { return _planId; } - std::string LogicalCollection::planId_as_string() const { - return basics::StringUtils::itoa(_planId); + return std::to_string(planId()); } TRI_col_type_e LogicalCollection::type() const { return _type; } -std::string LogicalCollection::name() const { - // TODO Activate this lock. Right now we have some locks outside. - // READ_LOCKER(readLocker, _lock); - return _name; -} - std::string LogicalCollection::globallyUniqueId() const { if (!_globallyUniqueId.empty()) { return _globallyUniqueId; @@ -548,8 +562,8 @@ void LogicalCollection::avoidServers(std::vector const& a) { } std::string LogicalCollection::dbName() const { - TRI_ASSERT(_vocbase != nullptr); - return _vocbase->name(); + TRI_ASSERT(vocbase()); + return vocbase()->name(); } TRI_vocbase_col_status_e LogicalCollection::status() const { return _status; } @@ -607,8 +621,6 @@ TRI_voc_rid_t LogicalCollection::revision(transaction::Methods* trx) const { bool LogicalCollection::isLocal() const { return _isLocal; } -bool LogicalCollection::deleted() const { return _isDeleted; } - bool LogicalCollection::isSystem() const { return _isSystem; } bool LogicalCollection::waitForSync() const { return _waitForSync; } @@ -619,8 +631,6 @@ std::unique_ptr const& LogicalCollection::followers() const { return _followers; } -void LogicalCollection::setDeleted(bool newValue) { _isDeleted = newValue; } - // SECTION: Indexes std::unordered_map LogicalCollection::clusterIndexEstimates(bool doNotUpdate){ READ_LOCKER(readlock, _clusterEstimatesLock); @@ -644,7 +654,7 @@ std::unordered_map LogicalCollection::clusterIndexEstimates readlock.unlock(); WRITE_LOCKER(writelock, _clusterEstimatesLock); if(needEstimateUpdate()){ - selectivityEstimatesOnCoordinator(_vocbase->name(), name(), _clusterEstimates); + selectivityEstimatesOnCoordinator(vocbase()->name(), name(), _clusterEstimates); _clusterEstimateTTL = TRI_microtime(); } return _clusterEstimates; @@ -737,7 +747,7 @@ void LogicalCollection::setShardMap(std::shared_ptr& map) { // not fail. the WAL entry for the rename will be written *after* the call // to "renameCollection" returns -int LogicalCollection::rename(std::string const& newName) { +Result LogicalCollection::rename(std::string&& newName, bool doSync) { // Should only be called from inside vocbase. // Otherwise caching is destroyed. TRI_ASSERT(!ServerState::instance()->isCoordinator()); // NOT YET IMPLEMENTED @@ -765,23 +775,24 @@ int LogicalCollection::rename(std::string const& newName) { return TRI_ERROR_INTERNAL; } - std::string oldName = _name; - _name = newName; + std::string oldName = name(); + // Okay we can finally rename safely try { StorageEngine* engine = EngineSelectorFeature::ENGINE; - bool const doSync = - application_features::ApplicationServer::getFeature( - "Database") - ->forceSyncProperties(); - engine->changeCollection(_vocbase, _cid, this, doSync); + TRI_ASSERT(engine != nullptr); + + name(std::move(newName)); + engine->changeCollection(vocbase(), id(), this, doSync); } catch (basics::Exception const& ex) { // Engine Rename somehow failed. Reset to old name - _name = oldName; + name(std::move(oldName)); + return ex.code(); } catch (...) { // Engine Rename somehow failed. Reset to old name - _name = oldName; + name(std::move(oldName)); + return TRI_ERROR_INTERNAL; } @@ -810,9 +821,9 @@ void LogicalCollection::drop() { TRI_ASSERT(!ServerState::instance()->isCoordinator()); StorageEngine* engine = EngineSelectorFeature::ENGINE; - engine->destroyCollection(_vocbase, this); - _isDeleted = true; + engine->destroyCollection(vocbase(), this); + deleted(true); _physical->drop(); } @@ -844,7 +855,7 @@ void LogicalCollection::toVelocyPackForClusterInventory(VPackBuilder& result, result.add(p.value); } if (!_distributeShardsLike.empty()) { - CollectionNameResolver resolver(_vocbase); + CollectionNameResolver resolver(vocbase()); result.add("distributeShardsLike", VPackValue(resolver.getCollectionNameCluster( static_cast(basics::StringUtils::uint64( @@ -866,16 +877,16 @@ void LogicalCollection::toVelocyPack(VPackBuilder& result, bool translateCids, TRI_ASSERT(result.isOpenObject()); // Collection Meta Information - result.add("cid", VPackValue(std::to_string(_cid))); - result.add("id", VPackValue(std::to_string(_cid))); - result.add("name", VPackValue(_name)); + result.add("cid", VPackValue(std::to_string(id()))); + result.add("id", VPackValue(std::to_string(id()))); + result.add("name", VPackValue(name())); result.add("type", VPackValue(static_cast(_type))); result.add("status", VPackValue(_status)); result.add("statusString", VPackValue(::translateStatus(_status))); result.add("version", VPackValue(_version)); // Collection Flags - result.add("deleted", VPackValue(_isDeleted)); + result.add("deleted", VPackValue(deleted())); result.add("isSystem", VPackValue(_isSystem)); result.add("waitForSync", VPackValue(_waitForSync)); result.add("globallyUniqueId", VPackValue(_globallyUniqueId)); @@ -903,7 +914,7 @@ void LogicalCollection::toVelocyPack(VPackBuilder& result, bool translateCids, // Cluster Specific result.add("isSmart", VPackValue(_isSmart)); - result.add("planId", VPackValue(std::to_string(_planId))); + result.add("planId", VPackValue(std::to_string(planId()))); result.add("numberOfShards", VPackValue(_numberOfShards)); result.add(VPackValue("shards")); result.openObject(); @@ -926,7 +937,7 @@ void LogicalCollection::toVelocyPack(VPackBuilder& result, bool translateCids, if (!_distributeShardsLike.empty() && ServerState::instance()->isCoordinator()) { if (translateCids) { - CollectionNameResolver resolver(_vocbase); + CollectionNameResolver resolver(vocbase()); result.add("distributeShardsLike", VPackValue(resolver.getCollectionNameCluster( static_cast(basics::StringUtils::uint64( @@ -1060,11 +1071,12 @@ arangodb::Result LogicalCollection::updateProperties(VPackSlice const& slice, if (!_isLocal) { // We need to inform the cluster as well return ClusterInfo::instance()->setCollectionPropertiesCoordinator( - _vocbase->name(), cid_as_string(), this); + vocbase()->name(), std::to_string(id()), this + ); } StorageEngine* engine = EngineSelectorFeature::ENGINE; - engine->changeCollection(_vocbase, _cid, this, doSync); + engine->changeCollection(vocbase(), id(), this, doSync); return {}; } @@ -1088,7 +1100,7 @@ std::shared_ptr LogicalCollection::figures() cons /// @brief opens an existing collection void LogicalCollection::open(bool ignoreErrors) { getPhysical()->open(ignoreErrors); - TRI_UpdateTickServer(_cid); + TRI_UpdateTickServer(id()); } /// SECTION Indexes @@ -1119,7 +1131,7 @@ bool LogicalCollection::dropIndex(TRI_idx_iid_t iid) { #if USE_PLAN_CACHE arangodb::aql::PlanCache::instance()->invalidate(_vocbase); #endif - arangodb::aql::QueryCache::instance()->invalidate(_vocbase, name()); + arangodb::aql::QueryCache::instance()->invalidate(vocbase(), name()); return _physical->dropIndex(iid); } @@ -1133,7 +1145,7 @@ void LogicalCollection::persistPhysicalCollection() { // We have not yet persisted this collection! TRI_ASSERT(getPhysical()->path().empty()); StorageEngine* engine = EngineSelectorFeature::ENGINE; - std::string path = engine->createCollection(_vocbase, _cid, this); + std::string path = engine->createCollection(vocbase(), id(), this); getPhysical()->setPath(path); } @@ -1294,15 +1306,15 @@ ChecksumResult LogicalCollection::checksum(bool withRevisions, bool withData) co return ChecksumResult(std::move(res)); } - trx.pinData(_cid); // will throw when it fails - + trx.pinData(id()); // will throw when it fails + // get last tick LogicalCollection* collection = trx.documentCollection(); auto physical = collection->getPhysical(); TRI_ASSERT(physical != nullptr); std::string const revisionId = TRI_RidToString(physical->revision(&trx)); uint64_t hash = 0; - + ManagedDocumentResult mmdr; trx.invokeOnAllElements(name(), [&hash, &withData, &withRevisions, &trx, &collection, &mmdr](LocalDocumentId const& token) { if (collection->readDocument(&trx, token, mmdr)) { @@ -1381,37 +1393,41 @@ Result LogicalCollection::compareChecksums(VPackSlice checksumSlice, std::string std::string LogicalCollection::generateGloballyUniqueId() const { if (_version < VERSION_33) { - return _name; // predictable UUID for legacy collections + return name(); // predictable UUID for legacy collections } - + ServerState::RoleEnum role = ServerState::instance()->getRole(); std::string result; result.reserve(64); if (ServerState::isCoordinator(role)) { - TRI_ASSERT(_planId != 0); + TRI_ASSERT(planId()); result.append("c"); - result.append(std::to_string(_planId)); + result.append(std::to_string(planId())); } else if (ServerState::isDBServer(role)) { - TRI_ASSERT(_planId != 0); + TRI_ASSERT(planId()); result.append("c"); // we add the shard name to the collection. If we ever // replicate shards, we can identify them cluster-wide - result.append(std::to_string(_planId)); + result.append(std::to_string(planId())); result.push_back('/'); - result.append(_name); + result.append(name()); } else { // single server if (isSystem()) { // system collection can't be renamed - result.append(_name); + result.append(name()); } else { - TRI_ASSERT(_cid != 0); + TRI_ASSERT(id()); result.append("h"); char buff[sizeof(TRI_server_id_t) * 2 + 1]; size_t len = TRI_StringUInt64HexInPlace(ServerIdFeature::getId(), buff); result.append(buff, len); TRI_ASSERT(result.size() > 3); result.push_back('/'); - result.append(std::to_string(_cid)); + result.append(std::to_string(id())); } } return result; } + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/arangod/VocBase/LogicalCollection.h b/arangod/VocBase/LogicalCollection.h index 1bacdf25dc..6974c6338c 100644 --- a/arangod/VocBase/LogicalCollection.h +++ b/arangod/VocBase/LogicalCollection.h @@ -25,11 +25,11 @@ #ifndef ARANGOD_VOCBASE_LOGICAL_COLLECTION_H #define ARANGOD_VOCBASE_LOGICAL_COLLECTION_H 1 +#include "LogicalDataSource.h" #include "Basics/Common.h" #include "Basics/ReadWriteLock.h" #include "Indexes/IndexIterator.h" #include "VocBase/voc-types.h" -#include "VocBase/vocbase.h" #include #include @@ -73,7 +73,7 @@ class ChecksumResult : public Result { velocypack::Builder _builder; }; -class LogicalCollection { +class LogicalCollection: public LogicalDataSource { friend struct ::TRI_vocbase_t; public: @@ -116,16 +116,14 @@ class LogicalCollection { uint32_t internalVersion() const; - inline TRI_voc_cid_t cid() const { return _cid; } + inline TRI_voc_cid_t cid() const { return id(); } virtual std::string cid_as_string() const; - TRI_voc_cid_t planId() const; std::string planId_as_string() const; TRI_col_type_e type() const; - virtual std::string name() const; std::string dbName() const; std::string globallyUniqueId() const; @@ -169,7 +167,7 @@ class LogicalCollection { // SECTION: Properties TRI_voc_rid_t revision(transaction::Methods*) const; bool isLocal() const; - bool deleted() const; + using LogicalDataSource::deleted; // required by TRI_vocbase_t bool isSystem() const; bool waitForSync() const; bool isSmart() const; @@ -179,8 +177,6 @@ class LogicalCollection { std::unique_ptr const& followers() const; - void setDeleted(bool); - PhysicalCollection* getPhysical() const { return _physical.get(); } std::unique_ptr getAllIterator(transaction::Methods* trx, bool reverse); @@ -236,17 +232,17 @@ class LogicalCollection { std::string const& key) const; // SECTION: Modification Functions - int rename(std::string const&); void load(); void unload(); - virtual void drop(); + virtual void drop() override; + virtual Result rename(std::string&& name, bool doSync) override; virtual void setStatus(TRI_vocbase_col_status_e); // SECTION: Serialisation void toVelocyPack(velocypack::Builder&, bool translateCids, bool forPersistence = false) const; - + void toVelocyPackIgnore(velocypack::Builder& result, std::unordered_set const& ignoreKeys, bool translateCids, bool forPersistence) const; @@ -260,7 +256,6 @@ class LogicalCollection { bool isReady, bool allInSync) const; - inline TRI_vocbase_t* vocbase() const { return _vocbase; } // Update this collection. virtual arangodb::Result updateProperties(velocypack::Slice const&, bool); @@ -326,7 +321,7 @@ class LogicalCollection { bool readDocument(transaction::Methods* trx, LocalDocumentId const& token, ManagedDocumentResult& result) const; - + bool readDocumentWithCallback(transaction::Methods* trx, LocalDocumentId const& token, IndexIterator::DocumentCallback const& cb) const; @@ -388,18 +383,9 @@ class LogicalCollection { bool const _isAStub; - // @brief Local collection id - TRI_voc_cid_t const _cid; - - // @brief Global collection id - TRI_voc_cid_t const _planId; - // @brief Collection type TRI_col_type_e const _type; - // @brief Collection Name - std::string _name; - // @brief Name of other collection this shards should be distributed like std::string _distributeShardsLike; @@ -420,12 +406,10 @@ class LogicalCollection { // SECTION: Properties bool _isLocal; - bool _isDeleted; - bool const _isSystem; bool _waitForSync; - + uint32_t _version; // SECTION: Replication @@ -440,7 +424,6 @@ class LogicalCollection { // the first one still has a valid copy std::shared_ptr _shardIds; - TRI_vocbase_t* _vocbase; // SECTION: Key Options // TODO Really VPack? std::shared_ptr const> @@ -470,4 +453,4 @@ class LogicalCollection { } // namespace arangodb -#endif +#endif \ No newline at end of file diff --git a/arangod/VocBase/LogicalDataSource.cpp b/arangod/VocBase/LogicalDataSource.cpp new file mode 100644 index 0000000000..71dce5076e --- /dev/null +++ b/arangod/VocBase/LogicalDataSource.cpp @@ -0,0 +1,49 @@ +//////////////////////////////////////////////////////////////////////////////// +/// 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 + +#include "LogicalDataSource.h" + +namespace arangodb { + +/*static*/ LogicalDataSource::Type const& LogicalDataSource::Type::emplace( + std::string&& name +) { + static std::mutex mutex; + static std::map types; + std::lock_guard lock(mutex); + auto itr = types.emplace(std::move(name), Type()); + + if (itr.second) { + itr.first->second._name = &(itr.first->first); // point '_name' at key + } + + return itr.first->second; +} + +} // arangodb + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/arangod/VocBase/LogicalDataSource.h b/arangod/VocBase/LogicalDataSource.h new file mode 100644 index 0000000000..6efbf29eb3 --- /dev/null +++ b/arangod/VocBase/LogicalDataSource.h @@ -0,0 +1,114 @@ +//////////////////////////////////////////////////////////////////////////////// +/// 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__VOCBASE__LOGICAL_DATA_SOURCE_H +#define ARANGOD__VOCBASE__LOGICAL_DATA_SOURCE_H 1 + +#include "voc-types.h" +#include "Basics/Result.h" + +struct TRI_vocbase_t; // forward declaration + +namespace arangodb { + +//////////////////////////////////////////////////////////////////////////////// +/// @brief a common ancestor to all database objects proving access to documents +/// e.g. LogicalCollection / LoigcalView +//////////////////////////////////////////////////////////////////////////////// +class LogicalDataSource { + public: + + ////////////////////////////////////////////////////////////////////////////// + /// @brief singleton identifying the underlying implementation type + /// each implementation should have its own static instance + /// once a type is emplace(...)ed it cannot be removed + ////////////////////////////////////////////////////////////////////////////// + class Type final { + public: + Type(Type&& other) noexcept = default; + bool operator==(Type const& other) const noexcept { return this == &other; } + bool operator!=(Type const& other) const noexcept { return this != &other; } + static Type const& emplace(std::string&& name); + inline std::string const& name() const noexcept { return *_name; } + + private: + std::string const* _name; // type name for e.g. log messages + + Type() = default; + Type(Type const&) = delete; + Type& operator=(Type const&) = delete; + Type& operator=(Type&&) noexcept = delete; + }; + + LogicalDataSource( + Type const& type, + TRI_vocbase_t* vocbase, + TRI_voc_cid_t id, + TRI_voc_cid_t planId, + std::string&& name, + bool deleted + ) noexcept + : _name(std::move(name)), + _type(type), + _vocbase(vocbase), + _id(id), + _planId(planId), + _deleted(deleted) { + } + LogicalDataSource(LogicalDataSource const& other) + : _name(other._name), + _type(other._type), + _vocbase(other._vocbase), + _id(other._id), + _planId(other._planId), + _deleted(other._deleted) { + } + + virtual ~LogicalDataSource() {} + + inline bool deleted() const noexcept { return _deleted; } + virtual void drop() = 0; + inline TRI_voc_cid_t id() const { return _id; } + inline std::string const& name() const { return _name; } + inline TRI_voc_cid_t planId() const noexcept { return _planId; } + virtual Result rename(std::string&& newName, bool doSync) = 0; + inline Type const& type() const noexcept { return _type; } + inline TRI_vocbase_t* vocbase() const { return _vocbase; } + + protected: + inline void deleted(bool deleted) noexcept { _deleted = deleted; } + inline void name(std::string&& name) noexcept { _name = std::move(name); } + + private: + // members ordered by sizeof(decltype(..)) + std::string _name; // data-source name + Type const& _type; // the type of the underlying data-source implementation + TRI_vocbase_t* const _vocbase; // the database where the data-source resides TODO change to reference + TRI_voc_cid_t const _id; // local data-source id (current database node) + TRI_voc_cid_t const _planId; // global data-source id (cluster-wide) + bool _deleted; // data-source marked as deleted +}; + +} // arangodb + +#endif // ARANGOD__VOCBASE__LOGICAL_DATA_SOURCE_H diff --git a/arangod/VocBase/LogicalView.cpp b/arangod/VocBase/LogicalView.cpp index eea4fde88c..cc53d526ef 100644 --- a/arangod/VocBase/LogicalView.cpp +++ b/arangod/VocBase/LogicalView.cpp @@ -81,14 +81,14 @@ static TRI_voc_cid_t ReadPlanId(VPackSlice info, TRI_voc_cid_t vid) { return vid; } -static std::string const ReadStringValue(VPackSlice info, - std::string const& name, - std::string const& def) { - if (!info.isObject()) { - return def; - } - return Helper::getStringValue(info, name, def); +std::string ReadStringValue( + arangodb::velocypack::Slice info, + std::string const& name, + std::string const& def +) { + return info.isObject() ? Helper::getStringValue(info, name, def) : def; } + } // namespace /// @brief This the "copy" constructor used in the cluster @@ -96,12 +96,7 @@ static std::string const ReadStringValue(VPackSlice info, /// modifications and can be freed /// Can only be given to V8, cannot be used for functionality. LogicalView::LogicalView(LogicalView const& other) - : _id(other.id()), - _planId(other.planId()), - _type(other.type()), - _name(other.name()), - _isDeleted(other._isDeleted), - _vocbase(other.vocbase()), + : LogicalDataSource(other), _physical(other.getPhysical()->clone(this, other.getPhysical())) { TRI_ASSERT(_physical != nullptr); } @@ -110,12 +105,14 @@ LogicalView::LogicalView(LogicalView const& other) // The Slice contains the part of the plan that // is relevant for this view LogicalView::LogicalView(TRI_vocbase_t* vocbase, VPackSlice const& info) - : _id(ReadId(info)), - _planId(ReadPlanId(info, _id)), - _type(ReadStringValue(info, "type", "")), - _name(ReadStringValue(info, "name", "")), - _isDeleted(Helper::readBooleanValue(info, "deleted", false)), - _vocbase(vocbase), + : LogicalDataSource( + LogicalDataSource::Type::emplace(ReadStringValue(info, "type", "")), + vocbase, + ReadId(info), + ReadPlanId(info, ReadId(info)), + ReadStringValue(info, "name", ""), + Helper::readBooleanValue(info, "deleted", false) + ), _physical(EngineSelectorFeature::ENGINE->createPhysicalView(this, info)) { TRI_ASSERT(_physical != nullptr); if (!IsAllowedName(info)) { @@ -123,7 +120,7 @@ LogicalView::LogicalView(TRI_vocbase_t* vocbase, VPackSlice const& info) } // update server's tick value - TRI_UpdateTickServer(static_cast(_id)); + TRI_UpdateTickServer(static_cast(id())); } LogicalView::~LogicalView() {} @@ -164,42 +161,33 @@ bool LogicalView::IsAllowedName(std::string const& name) { return true; } -TRI_voc_cid_t LogicalView::planId() const { return _planId; } +Result LogicalView::rename(std::string&& newName, bool doSync) { + auto oldName = name(); -std::string LogicalView::name() const { - // TODO Activate this lock. Right now we have some locks outside. - // READ_LOCKER(readLocker, _lock); - return _name; -} - -std::string LogicalView::dbName() const { - TRI_ASSERT(_vocbase != nullptr); - return _vocbase->name(); -} - -bool LogicalView::deleted() const { return _isDeleted; } - -void LogicalView::setDeleted(bool newValue) { _isDeleted = newValue; } - -void LogicalView::rename(std::string const& newName, bool doSync) { - std::string oldName = _name; try { - _name = newName; - StorageEngine* engine = EngineSelectorFeature::ENGINE; TRI_ASSERT(engine != nullptr); + name(std::move(newName)); + if (!engine->inRecovery()) { - engine->changeView(_vocbase, _id, this, doSync); + engine->changeView(vocbase(), id(), this, doSync); } + } catch (basics::Exception const& ex) { + name(std::move(oldName)); + + return ex.code(); } catch (...) { - _name = oldName; - throw; + name(std::move(oldName)); + + return TRI_ERROR_INTERNAL; } + + return TRI_ERROR_NO_ERROR; } void LogicalView::drop() { - _isDeleted = true; + deleted(true); if (getImplementation() != nullptr) { getImplementation()->drop(); @@ -226,13 +214,15 @@ void LogicalView::toVelocyPack(VPackBuilder& result, bool includeProperties, // We write into an open object TRI_ASSERT(result.isOpenObject()); // Meta Information - result.add("id", VPackValue(std::to_string(_id))); - result.add("name", VPackValue(_name)); - result.add("type", VPackValue(_type)); + result.add("id", VPackValue(std::to_string(id()))); + result.add("name", VPackValue(name())); + result.add("type", VPackValue(type().name())); + if (includeSystem) { - result.add("deleted", VPackValue(_isDeleted)); + result.add("deleted", VPackValue(deleted())); // Cluster Specific - result.add("planId", VPackValue(std::to_string(_planId))); + result.add("planId", VPackValue(std::to_string(planId()))); + if (getPhysical() != nullptr) { // Physical Information getPhysical()->getPropertiesVPack(result, includeSystem); @@ -272,7 +262,7 @@ arangodb::Result LogicalView::updateProperties(VPackSlice const& slice, getPhysical()->persistProperties(); } - engine->changeView(_vocbase, _id, this, doSync); + engine->changeView(vocbase(), id(), this, doSync); } return implResult; @@ -288,7 +278,7 @@ void LogicalView::persistPhysicalView() { // We have not yet persisted this view TRI_ASSERT(getPhysical()->path().empty()); StorageEngine* engine = EngineSelectorFeature::ENGINE; - engine->createView(_vocbase, _id, this); + engine->createView(vocbase(), id(), this); } void LogicalView::spawnImplementation( @@ -296,3 +286,7 @@ void LogicalView::spawnImplementation( bool isNew) { _implementation = creator(this, parameters.get("properties"), isNew); } + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/arangod/VocBase/LogicalView.h b/arangod/VocBase/LogicalView.h index ff16069f7a..ee15f20060 100644 --- a/arangod/VocBase/LogicalView.h +++ b/arangod/VocBase/LogicalView.h @@ -24,11 +24,12 @@ #ifndef ARANGOD_VOCBASE_LOGICAL_VIEW_H #define ARANGOD_VOCBASE_LOGICAL_VIEW_H 1 +#include "LogicalDataSource.h" #include "Basics/Common.h" +#include "Basics/ReadWriteLock.h" #include "Basics/Result.h" #include "VocBase/ViewImplementation.h" #include "VocBase/voc-types.h" -#include "VocBase/vocbase.h" #include @@ -45,7 +46,7 @@ struct ExecutionContext; class PhysicalView; -class LogicalView { +class LogicalView final: public LogicalDataSource { friend struct ::TRI_vocbase_t; public: @@ -76,25 +77,13 @@ class LogicalView { return std::unique_ptr(p); } - inline TRI_voc_cid_t id() const { return _id; } - - TRI_voc_cid_t planId() const; - - std::string type() const { return _type; } - std::string name() const; - std::string dbName() const; - - bool deleted() const; - void setDeleted(bool); - - void rename(std::string const& newName, bool doSync); - PhysicalView* getPhysical() const { return _physical.get(); } ViewImplementation* getImplementation() const { return _implementation.get(); } - void drop(); + virtual void drop() override; + virtual Result rename(std::string&& newName, bool doSync) override; // SECTION: Serialization velocypack::Builder toVelocyPack(bool includeProperties = false, @@ -103,8 +92,6 @@ class LogicalView { void toVelocyPack(velocypack::Builder&, bool includeProperties = false, bool includeSystem = false) const; - inline TRI_vocbase_t* vocbase() const { return _vocbase; } - // Update this view. arangodb::Result updateProperties(velocypack::Slice const&, bool, bool); @@ -123,23 +110,6 @@ class LogicalView { private: // SECTION: Meta Information - // - // @brief Local view id - TRI_voc_cid_t const _id; - - // @brief Global view id - TRI_voc_cid_t const _planId; - - // @brief view type - std::string const _type; - - // @brief view Name - std::string _name; - - bool _isDeleted; - - TRI_vocbase_t* _vocbase; - std::unique_ptr _physical; std::unique_ptr _implementation; diff --git a/arangod/VocBase/vocbase.cpp b/arangod/VocBase/vocbase.cpp index 273cd0b06b..2883de4e93 100644 --- a/arangod/VocBase/vocbase.cpp +++ b/arangod/VocBase/vocbase.cpp @@ -728,15 +728,15 @@ int TRI_vocbase_t::dropCollectionWorker(arangodb::LogicalCollection* collection, ->forceSyncProperties(); if (!collection->deleted()) { - collection->setDeleted(true); + collection->deleted(true); try { engine->changeCollection(this, collection->cid(), collection, doSync); } catch (arangodb::basics::Exception const& ex) { - collection->setDeleted(false); + collection->deleted(false); events::DropCollection(colName, ex.code()); return ex.code(); } catch (std::exception const&) { - collection->setDeleted(false); + collection->deleted(false); events::DropCollection(colName, TRI_ERROR_INTERNAL); return TRI_ERROR_INTERNAL; } @@ -758,7 +758,7 @@ int TRI_vocbase_t::dropCollectionWorker(arangodb::LogicalCollection* collection, case TRI_VOC_COL_STATUS_LOADED: case TRI_VOC_COL_STATUS_UNLOADING: { // collection is loaded - collection->setDeleted(true); + collection->deleted(true); StorageEngine* engine = EngineSelectorFeature::ENGINE; bool doSync = @@ -1289,18 +1289,22 @@ int TRI_vocbase_t::renameView(std::shared_ptr view, _viewsByName.emplace(newName, view); _viewsByName.erase(oldName); - + // stores the parameters on disk - bool const doSync = - application_features::ApplicationServer::getFeature( - "Database") - ->forceSyncProperties(); - view->rename(newName, doSync); + auto* databaseFeature = + application_features::ApplicationServer::getFeature("Database"); + TRI_ASSERT(databaseFeature); + auto doSync = databaseFeature->forceSyncProperties(); + auto res = view->rename(std::string(newName), doSync); + + if (!res.ok()) { + return res.errorNumber(); // rename failed + } // Tell the engine. StorageEngine* engine = EngineSelectorFeature::ENGINE; TRI_ASSERT(engine != nullptr); - arangodb::Result res = engine->renameView(this, view, oldName); + res = engine->renameView(this, view, oldName); return res.errorNumber(); } @@ -1383,11 +1387,14 @@ int TRI_vocbase_t::renameCollection(arangodb::LogicalCollection* collection, return TRI_ERROR_ARANGO_DUPLICATE_NAME; } - int res = collection->rename(newName); + auto* databaseFeature = + application_features::ApplicationServer::getFeature("Database"); + TRI_ASSERT(databaseFeature); + auto doSync = databaseFeature->forceSyncProperties(); + auto res = collection->rename(std::string(newName), doSync); - if (res != TRI_ERROR_NO_ERROR) { - // Renaming failed - return res; + if (!res.ok()) { + res.errorNumber(); // rename failed } // The collection is renamed. Now swap cache entries. @@ -1999,4 +2006,4 @@ TRI_voc_rid_t TRI_StringToRid(char const* p, size_t len, bool& isOld, // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/tests/Cluster/ShardDistributionReporterTest.cpp b/tests/Cluster/ShardDistributionReporterTest.cpp index 076449df63..6beaa28a0e 100644 --- a/tests/Cluster/ShardDistributionReporterTest.cpp +++ b/tests/Cluster/ShardDistributionReporterTest.cpp @@ -166,7 +166,7 @@ SCENARIO("The shard distribution can be reported", "[cluster][shards]") { return cic; }); - fakeit::When(Method(colMock, name)).AlwaysReturn(colName); + const_cast(col.name()).assign(colName); fakeit::When( ConstOverloadedMethod(colMock, shardIds, std::shared_ptr())) .AlwaysReturn(shards); @@ -1916,3 +1916,7 @@ SCENARIO("The shard distribution can be reported", "[cluster][shards]") { } } } + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- \ No newline at end of file