diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index 237415f8a4..d87a8eb75e 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -82,13 +82,11 @@ static_assert(sizeof(StateNames) / sizeof(std::string) == /// @brief create a profile Profile::Profile(Query* query) : query(query), results(), stamp(query->startTime()), tracked(false) { - auto queryList = static_cast(query->vocbase()->_queries); + auto queryList = query->vocbase()->queryList(); - if (queryList != nullptr) { - try { - tracked = queryList->insert(query, stamp); - } catch (...) { - } + try { + tracked = queryList->insert(query, stamp); + } catch (...) { } } @@ -96,13 +94,11 @@ Profile::Profile(Query* query) Profile::~Profile() { // only remove from list when the query was inserted into it... if (tracked) { - auto queryList = static_cast(query->vocbase()->_queries); + auto queryList = query->vocbase()->queryList(); - if (queryList != nullptr) { - try { - queryList->remove(query, stamp); - } catch (...) { - } + try { + queryList->remove(query, stamp); + } catch (...) { } } } diff --git a/arangod/Cluster/DBServerAgencySync.cpp b/arangod/Cluster/DBServerAgencySync.cpp index 722c992e20..aafad7f520 100644 --- a/arangod/Cluster/DBServerAgencySync.cpp +++ b/arangod/Cluster/DBServerAgencySync.cpp @@ -106,8 +106,7 @@ DBServerAgencySyncResult DBServerAgencySync::execute() { auto plan = clusterInfo->getPlan(); auto current = clusterInfo->getCurrent(); - TRI_UseVocBase(vocbase); - TRI_DEFER(TRI_ReleaseVocBase(vocbase)); + VocbaseGuard guard(vocbase); V8Context* context = V8DealerFeature::DEALER->enterContext(vocbase, true); diff --git a/arangod/Cluster/HeartbeatThread.cpp b/arangod/Cluster/HeartbeatThread.cpp index 97d68708f6..1e7478696b 100644 --- a/arangod/Cluster/HeartbeatThread.cpp +++ b/arangod/Cluster/HeartbeatThread.cpp @@ -534,7 +534,7 @@ bool HeartbeatThread::handlePlanChangeCoordinator(uint64_t currentPlanVersion) { HasRunOnce = true; } } else { - TRI_ReleaseVocBase(vocbase); + vocbase->release(); } } diff --git a/arangod/RestHandler/RestCursorHandler.cpp b/arangod/RestHandler/RestCursorHandler.cpp index e77ecf1526..8e4f1f6fce 100644 --- a/arangod/RestHandler/RestCursorHandler.cpp +++ b/arangod/RestHandler/RestCursorHandler.cpp @@ -215,7 +215,7 @@ void RestCursorHandler::processQuery(VPackSlice const& slice) { } // result is bigger than batchSize, and a cursor will be created - auto cursors = _vocbase->_cursorRepository; + auto cursors = _vocbase->cursorRepository(); TRI_ASSERT(cursors != nullptr); double ttl = arangodb::basics::VelocyPackHelper::getNumericValue( @@ -456,8 +456,7 @@ void RestCursorHandler::modifyCursor() { std::string const& id = suffix[0]; - auto cursors = - static_cast(_vocbase->_cursorRepository); + auto cursors = _vocbase->cursorRepository(); TRI_ASSERT(cursors != nullptr); auto cursorId = static_cast( @@ -526,8 +525,7 @@ void RestCursorHandler::deleteCursor() { std::string const& id = suffix[0]; - auto cursors = - static_cast(_vocbase->_cursorRepository); + auto cursors = _vocbase->cursorRepository(); TRI_ASSERT(cursors != nullptr); auto cursorId = static_cast( diff --git a/arangod/RestHandler/RestExportHandler.cpp b/arangod/RestHandler/RestExportHandler.cpp index 5f12b5af1a..f5de7b82f4 100644 --- a/arangod/RestHandler/RestExportHandler.cpp +++ b/arangod/RestHandler/RestExportHandler.cpp @@ -274,8 +274,7 @@ void RestExportHandler::createCursor() { // TODO: generalize to calling handler setPayload response->setContentType(HttpResponse::ContentType::JSON); - auto cursors = - static_cast(_vocbase->_cursorRepository); + auto cursors = _vocbase->cursorRepository(); TRI_ASSERT(cursors != nullptr); // create a cursor from the result @@ -318,8 +317,7 @@ void RestExportHandler::modifyCursor() { std::string const& id = suffix[0]; - auto cursors = - static_cast(_vocbase->_cursorRepository); + auto cursors = _vocbase->cursorRepository(); TRI_ASSERT(cursors != nullptr); auto cursorId = static_cast( @@ -383,8 +381,7 @@ void RestExportHandler::deleteCursor() { std::string const& id = suffix[0]; - auto cursors = - static_cast(_vocbase->_cursorRepository); + auto cursors = _vocbase->cursorRepository(); TRI_ASSERT(cursors != nullptr); auto cursorId = static_cast( diff --git a/arangod/RestHandler/RestQueryHandler.cpp b/arangod/RestHandler/RestQueryHandler.cpp index 9fc94b5f92..96dd4b310b 100644 --- a/arangod/RestHandler/RestQueryHandler.cpp +++ b/arangod/RestHandler/RestQueryHandler.cpp @@ -92,7 +92,7 @@ RestHandler::status RestQueryHandler::execute() { bool RestQueryHandler::readQueryProperties() { try { - auto queryList = static_cast(_vocbase->_queries); + auto queryList = _vocbase->queryList(); VPackBuilder result; result.add(VPackValue(VPackValueType::Object)); @@ -124,7 +124,7 @@ bool RestQueryHandler::readQueryProperties() { bool RestQueryHandler::readQuery(bool slow) { try { - auto queryList = static_cast(_vocbase->_queries); + auto queryList = _vocbase->queryList(); auto queries = slow ? queryList->listSlow() : queryList->listCurrent(); VPackBuilder result; @@ -192,7 +192,7 @@ bool RestQueryHandler::readQuery() { } bool RestQueryHandler::deleteQuerySlow() { - auto queryList = static_cast(_vocbase->_queries); + auto queryList = _vocbase->queryList(); queryList->clearSlow(); VPackBuilder result; @@ -208,7 +208,7 @@ bool RestQueryHandler::deleteQuerySlow() { bool RestQueryHandler::deleteQuery(std::string const& name) { auto id = StringUtils::uint64(name); - auto queryList = static_cast(_vocbase->_queries); + auto queryList = _vocbase->queryList(); TRI_ASSERT(queryList != nullptr); auto res = queryList->kill(id); @@ -276,7 +276,7 @@ bool RestQueryHandler::replaceProperties() { "expecting a JSON object as body"); }; - auto queryList = static_cast(_vocbase->_queries); + auto queryList = _vocbase->queryList(); try { bool enabled = queryList->enabled(); diff --git a/arangod/RestHandler/RestReplicationHandler.cpp b/arangod/RestHandler/RestReplicationHandler.cpp index bdf308b003..45ea4fa201 100644 --- a/arangod/RestHandler/RestReplicationHandler.cpp +++ b/arangod/RestHandler/RestReplicationHandler.cpp @@ -2798,7 +2798,7 @@ void RestReplicationHandler::handleCommandCreateKeys() { keys->create(tickEnd); size_t const count = keys->count(); - auto keysRepository = _vocbase->_collectionKeys; + auto keysRepository = _vocbase->collectionKeys(); try { keysRepository->store(keys.get()); @@ -2859,7 +2859,7 @@ void RestReplicationHandler::handleCommandGetKeys() { int res = TRI_ERROR_NO_ERROR; try { - auto keysRepository = _vocbase->_collectionKeys; + auto keysRepository = _vocbase->collectionKeys(); TRI_ASSERT(keysRepository != nullptr); auto collectionKeysId = static_cast( @@ -2973,7 +2973,7 @@ void RestReplicationHandler::handleCommandFetchKeys() { int res = TRI_ERROR_NO_ERROR; try { - auto keysRepository = _vocbase->_collectionKeys; + auto keysRepository = _vocbase->collectionKeys(); TRI_ASSERT(keysRepository != nullptr); auto collectionKeysId = static_cast( @@ -3046,7 +3046,7 @@ void RestReplicationHandler::handleCommandRemoveKeys() { std::string const& id = suffix[1]; - auto keys = _vocbase->_collectionKeys; + auto keys = _vocbase->collectionKeys(); TRI_ASSERT(keys != nullptr); auto collectionKeysId = static_cast( diff --git a/arangod/RestServer/BootstrapFeature.cpp b/arangod/RestServer/BootstrapFeature.cpp index 68ab211148..58c92a8c6d 100644 --- a/arangod/RestServer/BootstrapFeature.cpp +++ b/arangod/RestServer/BootstrapFeature.cpp @@ -174,8 +174,8 @@ void BootstrapFeature::unprepare() { TRI_vocbase_t* vocbase = databaseFeature->useDatabase(id); if (vocbase != nullptr) { - vocbase->_queries->killAll(true); - TRI_ReleaseVocBase(vocbase); + vocbase->queryList()->killAll(true); + vocbase->release(); } } } else { @@ -183,8 +183,8 @@ void BootstrapFeature::unprepare() { TRI_vocbase_t* vocbase = databaseFeature->useDatabase(name); if (vocbase != nullptr) { - vocbase->_queries->killAll(true); - TRI_ReleaseVocBase(vocbase); + vocbase->queryList()->killAll(true); + vocbase->release(); } } } diff --git a/arangod/RestServer/DatabaseFeature.cpp b/arangod/RestServer/DatabaseFeature.cpp index d421b902b0..241820641a 100644 --- a/arangod/RestServer/DatabaseFeature.cpp +++ b/arangod/RestServer/DatabaseFeature.cpp @@ -89,7 +89,7 @@ void DatabaseManagerThread::run() { auto theLists = databaseFeature->_databasesLists.load(); for (TRI_vocbase_t* vocbase : theLists->_droppedDatabases) { - if (!TRI_CanRemoveVocBase(vocbase)) { + if (!vocbase->canBeDropped()) { continue; } @@ -205,7 +205,7 @@ void DatabaseManagerThread::run() { for (auto& p : theLists->_coordinatorDatabases) { TRI_vocbase_t* vocbase = p.second; TRI_ASSERT(vocbase != nullptr); - auto cursorRepository = vocbase->_cursorRepository; + auto cursorRepository = vocbase->cursorRepository(); try { cursorRepository->garbageCollect(false); @@ -460,7 +460,7 @@ int DatabaseFeature::createDatabaseCoordinator(TRI_voc_tick_t id, std::string co } // increase reference counter - TRI_UseVocBase(vocbase.get()); + vocbase->use(); vocbase->_state = (sig_atomic_t)TRI_VOCBASE_STATE_NORMAL; { @@ -569,7 +569,7 @@ int DatabaseFeature::createDatabase(TRI_voc_tick_t id, std::string const& name, } // increase reference counter - TRI_UseVocBase(vocbase.get()); + vocbase->use(); } { @@ -634,7 +634,7 @@ int DatabaseFeature::dropDatabaseCoordinator(TRI_voc_tick_t id, bool force) { _databasesProtector.scan(); delete oldLists; - if (TRI_DropVocBase(vocbase)) { + if (vocbase->markAsDropped()) { LOG(INFO) << "dropping coordinator database '" << vocbase->name() << "'"; res = TRI_ERROR_NO_ERROR; } @@ -691,7 +691,7 @@ int DatabaseFeature::dropDatabase(std::string const& name, bool writeMarker, boo // invalidate all entries for the database arangodb::aql::QueryCache::instance()->invalidate(vocbase); - if (!TRI_DropVocBase(vocbase)) { + if (!vocbase->markAsDropped()) { // deleted by someone else? return TRI_ERROR_ARANGO_DATABASE_NOT_FOUND; } @@ -837,7 +837,7 @@ TRI_vocbase_t* DatabaseFeature::useDatabaseCoordinator(TRI_voc_tick_t id) { TRI_vocbase_t* vocbase = p.second; if (vocbase->_id == id) { - bool result TRI_UNUSED = TRI_UseVocBase(vocbase); + bool result TRI_UNUSED = vocbase->use(); // if we got here, no one else can have deleted the database TRI_ASSERT(result == true); @@ -851,30 +851,30 @@ TRI_vocbase_t* DatabaseFeature::useDatabaseCoordinator(std::string const& name) auto unuser(_databasesProtector.use()); auto theLists = _databasesLists.load(); - TRI_vocbase_t* vocbase = nullptr; auto it = theLists->_coordinatorDatabases.find(name); if (it != theLists->_coordinatorDatabases.end()) { - vocbase = it->second; - TRI_UseVocBase(vocbase); + TRI_vocbase_t* vocbase = it->second; + vocbase->use(); + return vocbase; } - - return vocbase; + + return nullptr; } TRI_vocbase_t* DatabaseFeature::useDatabase(std::string const& name) { auto unuser(_databasesProtector.use()); auto theLists = _databasesLists.load(); - TRI_vocbase_t* vocbase = nullptr; auto it = theLists->_databases.find(name); if (it != theLists->_databases.end()) { - vocbase = it->second; - TRI_UseVocBase(vocbase); + TRI_vocbase_t* vocbase = it->second; + vocbase->use(); + return vocbase; } - return vocbase; + return nullptr; } TRI_vocbase_t* DatabaseFeature::useDatabase(TRI_voc_tick_t id) { @@ -885,7 +885,7 @@ TRI_vocbase_t* DatabaseFeature::useDatabase(TRI_voc_tick_t id) { TRI_vocbase_t* vocbase = p.second; if (vocbase->_id == id) { - TRI_UseVocBase(vocbase); + vocbase->use(); return vocbase; } } @@ -893,12 +893,6 @@ TRI_vocbase_t* DatabaseFeature::useDatabase(TRI_voc_tick_t id) { return nullptr; } -/// @brief release a previously used database -/// this will decrease the reference-counter for the database -void DatabaseFeature::releaseDatabase(TRI_vocbase_t* vocbase) { - TRI_ReleaseVocBase(vocbase); -} - /// @brief lookup a database by its name, not increasing its reference count TRI_vocbase_t* DatabaseFeature::lookupDatabase(std::string const& name) { auto unuser(_databasesProtector.use()); diff --git a/arangod/RestServer/DatabaseFeature.h b/arangod/RestServer/DatabaseFeature.h index 415416857a..f53ad8d216 100644 --- a/arangod/RestServer/DatabaseFeature.h +++ b/arangod/RestServer/DatabaseFeature.h @@ -94,7 +94,6 @@ class DatabaseFeature final : public application_features::ApplicationFeature { TRI_vocbase_t* useDatabaseCoordinator(TRI_voc_tick_t id); TRI_vocbase_t* useDatabase(std::string const& name); TRI_vocbase_t* useDatabase(TRI_voc_tick_t id); - void releaseDatabase(TRI_vocbase_t* vocbase); TRI_vocbase_t* lookupDatabase(std::string const& name); diff --git a/arangod/RestServer/VocbaseContext.cpp b/arangod/RestServer/VocbaseContext.cpp index b4837eab2e..10c17bc5fa 100644 --- a/arangod/RestServer/VocbaseContext.cpp +++ b/arangod/RestServer/VocbaseContext.cpp @@ -51,7 +51,7 @@ VocbaseContext::VocbaseContext(GeneralRequest* request, TRI_vocbase_t* vocbase, TRI_ASSERT(_vocbase != nullptr); } -VocbaseContext::~VocbaseContext() { TRI_ReleaseVocBase(_vocbase); } +VocbaseContext::~VocbaseContext() { _vocbase->release(); } //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not to use special cluster authentication diff --git a/arangod/StorageEngine/MMFilesEngine.h b/arangod/StorageEngine/MMFilesEngine.h index bd2b49c41a..abcb7b0881 100644 --- a/arangod/StorageEngine/MMFilesEngine.h +++ b/arangod/StorageEngine/MMFilesEngine.h @@ -79,7 +79,7 @@ class MMFilesEngine final : public StorageEngine { uint64_t getMaxRevision() override; // return the path for a database - std::string databasePath(TRI_vocbase_t* vocbase) const override { return databaseDirectory(vocbase->_id); } + std::string databasePath(TRI_vocbase_t const* vocbase) const override { return databaseDirectory(vocbase->_id); } TRI_vocbase_t* openDatabase(arangodb::velocypack::Slice const& parameters, bool isUpgrade) override; diff --git a/arangod/StorageEngine/OtherEngine.h b/arangod/StorageEngine/OtherEngine.h index c94a53fec6..257fbc8f21 100644 --- a/arangod/StorageEngine/OtherEngine.h +++ b/arangod/StorageEngine/OtherEngine.h @@ -68,7 +68,7 @@ class OtherEngine final : public StorageEngine { uint64_t getMaxRevision() override; // return the path for a database - std::string databasePath(TRI_vocbase_t*) const override { return "none"; } + std::string databasePath(TRI_vocbase_t const*) const override { return "none"; } TRI_vocbase_t* openDatabase(arangodb::velocypack::Slice const& parameters, bool isUpgrade) override { return nullptr; diff --git a/arangod/StorageEngine/StorageEngine.h b/arangod/StorageEngine/StorageEngine.h index e961df3982..cc2b4b9293 100644 --- a/arangod/StorageEngine/StorageEngine.h +++ b/arangod/StorageEngine/StorageEngine.h @@ -85,7 +85,7 @@ class StorageEngine : public application_features::ApplicationFeature { virtual uint64_t getMaxRevision() = 0; // return the path for a database - virtual std::string databasePath(TRI_vocbase_t* vocbase) const = 0; + virtual std::string databasePath(TRI_vocbase_t const* vocbase) const = 0; virtual TRI_vocbase_t* openDatabase(arangodb::velocypack::Slice const& parameters, bool isUpgrade) = 0; diff --git a/arangod/Utils/Cursor.cpp b/arangod/Utils/Cursor.cpp index b80de5506f..5d8a03f9d2 100644 --- a/arangod/Utils/Cursor.cpp +++ b/arangod/Utils/Cursor.cpp @@ -68,16 +68,11 @@ VelocyPackCursor::VelocyPackCursor(TRI_vocbase_t* vocbase, CursorId id, std::shared_ptr extra, double ttl, bool hasCount) : Cursor(id, batchSize, extra, ttl, hasCount), - _vocbase(vocbase), + _vocbaseGuard(vocbase), _result(std::move(result)), _iterator(_result.result->slice()), _cached(_result.cached) { TRI_ASSERT(_result.result->slice().isArray()); - TRI_UseVocBase(vocbase); -} - -VelocyPackCursor::~VelocyPackCursor() { - TRI_ReleaseVocBase(_vocbase); } //////////////////////////////////////////////////////////////////////////////// @@ -200,15 +195,13 @@ ExportCursor::ExportCursor(TRI_vocbase_t* vocbase, CursorId id, arangodb::CollectionExport* ex, size_t batchSize, double ttl, bool hasCount) : Cursor(id, batchSize, nullptr, ttl, hasCount), - _vocbase(vocbase), + _vocbaseGuard(vocbase), _ex(ex), _size(ex->_documents->size()) { - TRI_UseVocBase(vocbase); } ExportCursor::~ExportCursor() { delete _ex; - TRI_ReleaseVocBase(_vocbase); } //////////////////////////////////////////////////////////////////////////////// @@ -272,7 +265,7 @@ static bool IncludeAttribute( //////////////////////////////////////////////////////////////////////////////// void ExportCursor::dump(arangodb::basics::StringBuffer& buffer) { - auto transactionContext = std::make_shared(_vocbase); + auto transactionContext = std::make_shared(_vocbaseGuard.vocbase()); VPackOptions* options = transactionContext->getVPackOptions(); TRI_ASSERT(_ex != nullptr); diff --git a/arangod/Utils/Cursor.h b/arangod/Utils/Cursor.h index d88e3e0d97..9b14c88c84 100644 --- a/arangod/Utils/Cursor.h +++ b/arangod/Utils/Cursor.h @@ -28,11 +28,10 @@ #include "Basics/StringBuffer.h" #include "Aql/QueryResult.h" #include "VocBase/voc-types.h" +#include "VocBase/vocbase.h" #include -struct TRI_vocbase_t; - namespace arangodb { namespace velocypack { class Builder; @@ -116,7 +115,7 @@ class VelocyPackCursor : public Cursor { std::shared_ptr, double, bool); - ~VelocyPackCursor(); + ~VelocyPackCursor() = default; public: bool hasNext() override final; @@ -128,7 +127,7 @@ class VelocyPackCursor : public Cursor { void dump(arangodb::basics::StringBuffer&) override final; private: - TRI_vocbase_t* _vocbase; + VocbaseGuard _vocbaseGuard; aql::QueryResult _result; arangodb::velocypack::ArrayIterator _iterator; bool _cached; @@ -151,7 +150,7 @@ class ExportCursor : public Cursor { void dump(arangodb::basics::StringBuffer&) override final; private: - TRI_vocbase_t* _vocbase; + VocbaseGuard _vocbaseGuard; arangodb::CollectionExport* _ex; size_t const _size; }; diff --git a/arangod/Utils/DatabaseGuard.h b/arangod/Utils/DatabaseGuard.h index 5e3c09ca89..cacac7640b 100644 --- a/arangod/Utils/DatabaseGuard.h +++ b/arangod/Utils/DatabaseGuard.h @@ -21,8 +21,8 @@ /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// -#ifndef ARANGOD_UTILS_DATABASE_GUARD_H -#define ARANGOD_UTILS_DATABASE_GUARD_H 1 +#ifndef ARANGOD_UTILS_vocbase_GUARD_H +#define ARANGOD_UTILS_vocbase_GUARD_H 1 #include "ApplicationFeatures/ApplicationServer.h" #include "Basics/Exceptions.h" @@ -42,12 +42,12 @@ class DatabaseGuard { ////////////////////////////////////////////////////////////////////////////// explicit DatabaseGuard(TRI_voc_tick_t id) - : _database(nullptr) { + : _vocbase(nullptr) { auto databaseFeature = application_features::ApplicationServer::getFeature("Database"); - _database = databaseFeature->useDatabase(id); + _vocbase = databaseFeature->useDatabase(id); - if (_database == nullptr) { + if (_vocbase == nullptr) { THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } } @@ -56,13 +56,13 @@ class DatabaseGuard { /// @brief create the guard, using a database name ////////////////////////////////////////////////////////////////////////////// - explicit DatabaseGuard(char const* name) - : _database(nullptr) { + explicit DatabaseGuard(std::string const& name) + : _vocbase(nullptr) { auto databaseFeature = application_features::ApplicationServer::getFeature("Database"); - _database = databaseFeature->useDatabase(name); + _vocbase = databaseFeature->useDatabase(name); - if (_database == nullptr) { + if (_vocbase == nullptr) { THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } } @@ -72,10 +72,8 @@ class DatabaseGuard { ////////////////////////////////////////////////////////////////////////////// ~DatabaseGuard() { - if (_database != nullptr) { - auto databaseFeature = application_features::ApplicationServer::getFeature("Database"); - databaseFeature->releaseDatabase(_database); - } + TRI_ASSERT(_vocbase != nullptr); + _vocbase->release(); } public: @@ -83,7 +81,7 @@ class DatabaseGuard { /// @brief return the database pointer ////////////////////////////////////////////////////////////////////////////// - inline TRI_vocbase_t* database() const { return _database; } + inline TRI_vocbase_t* database() const { return _vocbase; } private: @@ -91,7 +89,7 @@ class DatabaseGuard { /// @brief pointer to database ////////////////////////////////////////////////////////////////////////////// - TRI_vocbase_t* _database; + TRI_vocbase_t* _vocbase; }; } diff --git a/arangod/Utils/ReplicationTransaction.h b/arangod/Utils/ReplicationTransaction.h index 37719b0107..7bf9dd1dcb 100644 --- a/arangod/Utils/ReplicationTransaction.h +++ b/arangod/Utils/ReplicationTransaction.h @@ -24,8 +24,6 @@ #ifndef ARANGOD_UTILS_REPLICATION_TRANSACTION_H #define ARANGOD_UTILS_REPLICATION_TRANSACTION_H 1 -#include "ApplicationFeatures/ApplicationServer.h" -#include "RestServer/DatabaseFeature.h" #include "Utils/StandaloneTransactionContext.h" #include "Utils/Transaction.h" #include "VocBase/ticks.h" @@ -37,25 +35,15 @@ namespace arangodb { class ReplicationTransaction : public Transaction { public: - ////////////////////////////////////////////////////////////////////////////// /// @brief create the transaction - ////////////////////////////////////////////////////////////////////////////// - ReplicationTransaction(TRI_vocbase_t* vocbase) : Transaction(StandaloneTransactionContext::Create(vocbase)) { - auto databaseFeature = application_features::ApplicationServer::getFeature("Database"); - databaseFeature->useDatabase(vocbase->name()); + _vocbase->use(); } - ////////////////////////////////////////////////////////////////////////////// /// @brief end the transaction - ////////////////////////////////////////////////////////////////////////////// - - ~ReplicationTransaction() { - auto databaseFeature = application_features::ApplicationServer::getFeature("Database"); - databaseFeature->releaseDatabase(vocbase()); - } + ~ReplicationTransaction() { _vocbase->release(); } public: diff --git a/arangod/Utils/WorkMonitorArangod.cpp b/arangod/Utils/WorkMonitorArangod.cpp index c7861eb698..13531ac8ab 100644 --- a/arangod/Utils/WorkMonitorArangod.cpp +++ b/arangod/Utils/WorkMonitorArangod.cpp @@ -95,7 +95,7 @@ bool WorkMonitor::cancelAql(WorkDescription* desc) { LOG(WARN) << "cancel query " << id << " in " << vocbase; - auto queryList = static_cast(vocbase->_queries); + auto queryList = vocbase->queryList(); auto res = queryList->kill(id); if (res != TRI_ERROR_NO_ERROR) { diff --git a/arangod/V8Server/V8Context.cpp b/arangod/V8Server/V8Context.cpp index e82e909a24..56eeaefdb2 100644 --- a/arangod/V8Server/V8Context.cpp +++ b/arangod/V8Server/V8Context.cpp @@ -87,7 +87,7 @@ void V8Context::handleGlobalContextMethods() { } for (auto& type : copy) { - std::string func = GlobalContextMethods::code(type); + std::string const& func = GlobalContextMethods::code(type); LOG(DEBUG) << "executing global context method '" << func << "' for context " << _id; diff --git a/arangod/V8Server/V8Context.h b/arangod/V8Server/V8Context.h index 94837b3add..7178cbb99b 100644 --- a/arangod/V8Server/V8Context.h +++ b/arangod/V8Server/V8Context.h @@ -29,6 +29,7 @@ #include #include "Basics/Mutex.h" +#include "Basics/StaticStrings.h" namespace arangodb { class GlobalContextMethods { @@ -81,7 +82,7 @@ class GlobalContextMethods { } } - static std::string const code(MethodType type) { + static std::string const& code(MethodType type) { switch (type) { case MethodType::RELOAD_ROUTING: return CodeReloadRouting; @@ -95,7 +96,7 @@ class GlobalContextMethods { return CodeWarmupExports; case MethodType::UNKNOWN: default: - return ""; + return StaticStrings::Empty; } } diff --git a/arangod/V8Server/V8DealerFeature.cpp b/arangod/V8Server/V8DealerFeature.cpp index 32d3a551a3..4cadd10653 100644 --- a/arangod/V8Server/V8DealerFeature.cpp +++ b/arangod/V8Server/V8DealerFeature.cpp @@ -545,10 +545,14 @@ V8Context* V8DealerFeature::enterContext(TRI_vocbase_t* vocbase, v8g->_vocbase = vocbase; v8g->_allowUseDatabase = allowUseDatabase; - TRI_UseVocBase(vocbase); + vocbase->use(); - LOG(TRACE) << "entering V8 context " << context->_id; - context->handleGlobalContextMethods(); + try { + LOG(TRACE) << "entering V8 context " << context->_id; + context->handleGlobalContextMethods(); + } catch (...) { + // ignore errors here + } } } @@ -578,7 +582,7 @@ void V8DealerFeature::exitContext(V8Context* context) { TRI_ASSERT(vocbase != nullptr); // release last recently used vocbase - TRI_ReleaseVocBase(vocbase); + vocbase->release(); // check for cancelation requests canceled = v8g->_canceled; diff --git a/arangod/V8Server/V8Job.cpp b/arangod/V8Server/V8Job.cpp index db138f0039..d0b68e217f 100644 --- a/arangod/V8Server/V8Job.cpp +++ b/arangod/V8Server/V8Job.cpp @@ -34,7 +34,6 @@ #include "V8Server/V8Context.h" #include "V8Server/V8DealerFeature.h" #include "V8Server/V8PeriodicTask.h" -#include "VocBase/vocbase.h" using namespace arangodb; using namespace arangodb::basics; @@ -48,13 +47,12 @@ V8Job::V8Job(TRI_vocbase_t* vocbase, std::string const& command, std::shared_ptr parameters, bool allowUseDatabase, Task* task) : Job("V8 Job"), - _vocbase(vocbase), + _vocbaseGuard(vocbase), _command(command), _parameters(parameters), _canceled(false), _allowUseDatabase(allowUseDatabase), _task(task) { - TRI_UseVocBase(vocbase); } //////////////////////////////////////////////////////////////////////////////// @@ -62,8 +60,6 @@ V8Job::V8Job(TRI_vocbase_t* vocbase, std::string const& command, //////////////////////////////////////////////////////////////////////////////// V8Job::~V8Job() { - TRI_ReleaseVocBase(_vocbase); - if (_task != nullptr) { V8PeriodicTask::jobDone(_task); } @@ -75,7 +71,7 @@ void V8Job::work() { } auto context = - V8DealerFeature::DEALER->enterContext(_vocbase, _allowUseDatabase); + V8DealerFeature::DEALER->enterContext(_vocbaseGuard.vocbase(), _allowUseDatabase); // note: the context might be 0 in case of shut-down if (context == nullptr) { diff --git a/arangod/V8Server/V8Job.h b/arangod/V8Server/V8Job.h index ba678baa47..f6746ad09d 100644 --- a/arangod/V8Server/V8Job.h +++ b/arangod/V8Server/V8Job.h @@ -26,8 +26,7 @@ #include "Basics/Common.h" #include "Dispatcher/Job.h" - -struct TRI_vocbase_t; +#include "VocBase/vocbase.h" namespace arangodb { namespace rest { @@ -53,7 +52,8 @@ class V8Job : public rest::Job { virtual std::string const& getName() const override { return _command; } private: - TRI_vocbase_t* _vocbase; + /// @brief guard to make sure the database is not dropped while used by us + VocbaseGuard _vocbaseGuard; std::string const _command; std::shared_ptr _parameters; std::atomic _canceled; diff --git a/arangod/V8Server/V8PeriodicTask.cpp b/arangod/V8Server/V8PeriodicTask.cpp index ae81bf773a..0d65f615f8 100644 --- a/arangod/V8Server/V8PeriodicTask.cpp +++ b/arangod/V8Server/V8PeriodicTask.cpp @@ -54,20 +54,11 @@ V8PeriodicTask::V8PeriodicTask(std::string const& id, std::string const& name, bool allowUseDatabase) : Task(id, name), PeriodicTask(id, offset, period), - _vocbase(vocbase), + _vocbaseGuard(vocbase), _command(command), _parameters(parameters), _created(TRI_microtime()), _allowUseDatabase(allowUseDatabase) { - TRI_ASSERT(vocbase != nullptr); - - // increase reference counter for the database used - TRI_UseVocBase(_vocbase); -} - -V8PeriodicTask::~V8PeriodicTask() { - // decrease reference counter for the database used - TRI_ReleaseVocBase(_vocbase); } // get a task specific description in JSON format @@ -77,7 +68,7 @@ void V8PeriodicTask::getDescription(VPackBuilder& builder) const { builder.add("created", VPackValue(_created)); builder.add("command", VPackValue(_command)); - builder.add("database", VPackValue(_vocbase->name())); + builder.add("database", VPackValue(_vocbaseGuard.vocbase()->name())); } // handles the next tick @@ -99,7 +90,7 @@ bool V8PeriodicTask::handlePeriod() { } std::unique_ptr job(new V8Job( - _vocbase, "(function (params) { " + _command + " } )(params);", + _vocbaseGuard.vocbase(), "(function (params) { " + _command + " } )(params);", _parameters, _allowUseDatabase, this)); DispatcherFeature::DISPATCHER->addJob(job, false); diff --git a/arangod/V8Server/V8PeriodicTask.h b/arangod/V8Server/V8PeriodicTask.h index 177f165899..3a3e2428f0 100644 --- a/arangod/V8Server/V8PeriodicTask.h +++ b/arangod/V8Server/V8PeriodicTask.h @@ -39,7 +39,7 @@ class V8PeriodicTask : public rest::PeriodicTask { double, std::string const&, std::shared_ptr, bool); - ~V8PeriodicTask(); + ~V8PeriodicTask() = default; public: static void jobDone(Task*); @@ -56,7 +56,8 @@ class V8PeriodicTask : public rest::PeriodicTask { static std::unordered_set RUNNING; private: - TRI_vocbase_t* _vocbase; + /// @brief guard to make sure the database is not dropped while used by us + VocbaseGuard _vocbaseGuard; std::string const _command; std::shared_ptr _parameters; double _created; diff --git a/arangod/V8Server/V8TimerTask.cpp b/arangod/V8Server/V8TimerTask.cpp index c54804304a..1041bbcbbf 100644 --- a/arangod/V8Server/V8TimerTask.cpp +++ b/arangod/V8Server/V8TimerTask.cpp @@ -46,20 +46,11 @@ V8TimerTask::V8TimerTask(std::string const& id, std::string const& name, // greater than zero, // otherwise // the timertask will not execute the task at all - _vocbase(vocbase), + _vocbaseGuard(vocbase), _command(command), _parameters(parameters), _created(TRI_microtime()), _allowUseDatabase(allowUseDatabase) { - TRI_ASSERT(vocbase != nullptr); - - // increase reference counter for the database used - TRI_UseVocBase(_vocbase); -} - -V8TimerTask::~V8TimerTask() { - // decrease reference counter for the database used - TRI_ReleaseVocBase(_vocbase); } //////////////////////////////////////////////////////////////////////////////// @@ -70,7 +61,7 @@ void V8TimerTask::getDescription(VPackBuilder& builder) const { TimerTask::getDescription(builder); builder.add("created", VPackValue(_created)); builder.add("command", VPackValue(_command)); - builder.add("database", VPackValue(_vocbase->name())); + builder.add("database", VPackValue(_vocbaseGuard.vocbase()->name())); } //////////////////////////////////////////////////////////////////////////////// @@ -81,7 +72,7 @@ bool V8TimerTask::handleTimeout() { TRI_ASSERT(DispatcherFeature::DISPATCHER != nullptr); std::unique_ptr job( - new V8Job(_vocbase, "(function (params) { " + _command + " } )(params);", + new V8Job(_vocbaseGuard.vocbase(), "(function (params) { " + _command + " } )(params);", _parameters, _allowUseDatabase, nullptr)); if (DispatcherFeature::DISPATCHER == nullptr) { diff --git a/arangod/V8Server/V8TimerTask.h b/arangod/V8Server/V8TimerTask.h index 9fa024f4e2..808a934336 100644 --- a/arangod/V8Server/V8TimerTask.h +++ b/arangod/V8Server/V8TimerTask.h @@ -44,7 +44,7 @@ class V8TimerTask : public rest::TimerTask { std::string const&, std::shared_ptr, bool); - ~V8TimerTask(); + ~V8TimerTask() = default; protected: ////////////////////////////////////////////////////////////////////////////// @@ -67,11 +67,8 @@ class V8TimerTask : public rest::TimerTask { bool handleTimeout() override; private: - ////////////////////////////////////////////////////////////////////////////// - /// @brief system vocbase - ////////////////////////////////////////////////////////////////////////////// - - TRI_vocbase_t* _vocbase; + /// @brief guard to make sure the database is not dropped while used by us + VocbaseGuard _vocbaseGuard; ////////////////////////////////////////////////////////////////////////////// /// @brief command to execute diff --git a/arangod/V8Server/v8-collection-util.cpp b/arangod/V8Server/v8-collection-util.cpp index 4bc00901b6..0a879218d6 100644 --- a/arangod/V8Server/v8-collection-util.cpp +++ b/arangod/V8Server/v8-collection-util.cpp @@ -115,7 +115,7 @@ static void WeakCollectionCallback(const v8::WeakCallbackData< v8g->decreaseActiveExternals(); // decrease the reference-counter for the database - TRI_ReleaseVocBase(collection->_vocbase); + collection->_vocbase->release(); // find the persistent handle #if ARANGODB_ENABLE_MAINTAINER_MODE @@ -157,15 +157,20 @@ v8::Handle WrapCollection(v8::Isolate* isolate, if (it == v8g->JSCollections.end()) { // increase the reference-counter for the database - TRI_UseVocBase(collection->_vocbase); - auto externalCollection = v8::External::New(isolate, nonconstCollection); + collection->_vocbase->use(); + try { + auto externalCollection = v8::External::New(isolate, nonconstCollection); - result->SetInternalField(SLOT_COLLECTION, externalCollection); + result->SetInternalField(SLOT_COLLECTION, externalCollection); - v8g->JSCollections[nonconstCollection].Reset(isolate, externalCollection); - v8g->JSCollections[nonconstCollection].SetWeak( - &v8g->JSCollections[nonconstCollection], WeakCollectionCallback); - v8g->increaseActiveExternals(); + v8g->JSCollections[nonconstCollection].Reset(isolate, externalCollection); + v8g->JSCollections[nonconstCollection].SetWeak( + &v8g->JSCollections[nonconstCollection], WeakCollectionCallback); + v8g->increaseActiveExternals(); + } catch (...) { + collection->_vocbase->release(); + throw; + } } else { auto myCollection = v8::Local::New(isolate, it->second); diff --git a/arangod/V8Server/v8-collection.cpp b/arangod/V8Server/v8-collection.cpp index 822228d80e..836426781a 100644 --- a/arangod/V8Server/v8-collection.cpp +++ b/arangod/V8Server/v8-collection.cpp @@ -2097,7 +2097,7 @@ static void JS_SaveVocbase(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } - if (TRI_IsDeletedVocBase(vocbase)) { + if (vocbase->isDropped()) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } @@ -2688,7 +2688,7 @@ static void JS_CollectionVocbase( TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } - if (TRI_IsDeletedVocBase(vocbase)) { + if (vocbase->isDropped()) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index 9b32784520..c88d8e181b 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -1366,7 +1366,7 @@ static void JS_QueriesPropertiesAql( TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } - auto queryList = static_cast(vocbase->_queries); + auto queryList = vocbase->queryList(); TRI_ASSERT(queryList != nullptr); if (args.Length() > 1) { @@ -1442,7 +1442,7 @@ static void JS_QueriesCurrentAql( TRI_V8_THROW_EXCEPTION_USAGE("AQL_QUERIES_CURRENT()"); } - auto queryList = static_cast(vocbase->_queries); + auto queryList = vocbase->queryList(); TRI_ASSERT(queryList != nullptr); try { @@ -1486,7 +1486,7 @@ static void JS_QueriesSlowAql(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } - auto queryList = static_cast(vocbase->_queries); + auto queryList = vocbase->queryList(); TRI_ASSERT(queryList != nullptr); if (args.Length() == 1) { @@ -1545,7 +1545,7 @@ static void JS_QueriesKillAql(v8::FunctionCallbackInfo const& args) { auto id = TRI_ObjectToUInt64(args[0], true); - auto queryList = static_cast(vocbase->_queries); + auto queryList = vocbase->queryList(); TRI_ASSERT(queryList != nullptr); auto res = queryList->kill(id); @@ -2042,7 +2042,7 @@ static void JS_UseDatabase(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_INTERNAL); } - if (TRI_IsDeletedVocBase(vocbase)) { + if (vocbase->isDropped()) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } @@ -2068,7 +2068,7 @@ static void JS_UseDatabase(v8::FunctionCallbackInfo const& args) { v8g->_vocbase = vocbase; TRI_ASSERT(orig != vocbase); - databaseFeature->releaseDatabase(static_cast(orig)); + static_cast(orig)->release(); TRI_V8_RETURN(WrapVocBase(isolate, vocbase)); } @@ -2305,7 +2305,7 @@ static void CreateDatabaseCoordinator( // and switch back v8g->_vocbase = orig; - TRI_ReleaseVocBase(vocbase); + vocbase->release(); TRI_V8_RETURN_TRUE(); } @@ -2394,7 +2394,7 @@ static void JS_CreateDatabase(v8::FunctionCallbackInfo const& args) { v8g->_vocbase = orig; // finally decrease the reference-counter - TRI_ReleaseVocBase(database); + database->release(); TRI_V8_RETURN_TRUE(); } @@ -2419,7 +2419,7 @@ static void DropDatabaseCoordinator( } TRI_voc_tick_t const id = vocbase->_id; - TRI_ReleaseVocBase(vocbase); + vocbase->release(); ClusterInfo* ci = ClusterInfo::instance(); std::string errorMsg; @@ -2441,7 +2441,7 @@ static void DropDatabaseCoordinator( break; } - TRI_ReleaseVocBase(vocbase); + vocbase->release(); // sleep usleep(10000); } diff --git a/arangod/V8Server/v8-voccursor.cpp b/arangod/V8Server/v8-voccursor.cpp index 4504a29358..c4727be5ad 100644 --- a/arangod/V8Server/v8-voccursor.cpp +++ b/arangod/V8Server/v8-voccursor.cpp @@ -86,8 +86,7 @@ static void JS_CreateCursor(v8::FunctionCallbackInfo const& args) { } // create a cursor - auto cursors = - static_cast(vocbase->_cursorRepository); + auto cursors = vocbase->cursorRepository(); arangodb::aql::QueryResult result(TRI_ERROR_NO_ERROR); result.result = builder; @@ -134,8 +133,7 @@ static void JS_JsonCursor(v8::FunctionCallbackInfo const& args) { arangodb::basics::StringUtils::uint64(id)); // find the cursor - auto cursors = - static_cast(vocbase->_cursorRepository); + auto cursors = vocbase->cursorRepository(); TRI_ASSERT(cursors != nullptr); bool busy; diff --git a/arangod/VocBase/CleanupThread.cpp b/arangod/VocBase/CleanupThread.cpp index 63f866db80..2bbdf94e59 100644 --- a/arangod/VocBase/CleanupThread.cpp +++ b/arangod/VocBase/CleanupThread.cpp @@ -140,8 +140,7 @@ void CleanupThread::run() { /// @brief clean up cursors void CleanupThread::cleanupCursors(bool force) { // clean unused cursors - auto cursors = - static_cast(_vocbase->_cursorRepository); + auto cursors = _vocbase->cursorRepository(); TRI_ASSERT(cursors != nullptr); try { @@ -242,7 +241,7 @@ void CleanupThread::cleanupCollection(TRI_vocbase_col_t* collection, } } - if (!isDeleted && TRI_IsDeletedVocBase(document->_vocbase)) { + if (!isDeleted && document->_vocbase->isDropped()) { // the collection was not marked as deleted, but the database was isDeleted = true; } diff --git a/arangod/VocBase/vocbase.cpp b/arangod/VocBase/vocbase.cpp index d46e6497cd..e5878c6452 100644 --- a/arangod/VocBase/vocbase.cpp +++ b/arangod/VocBase/vocbase.cpp @@ -1087,15 +1087,11 @@ void TRI_vocbase_t::shutdown() { } // mark all cursors as deleted so underlying collections can be freed soon - if (_cursorRepository != nullptr) { - _cursorRepository->garbageCollect(true); - } + _cursorRepository->garbageCollect(true); // mark all collection keys as deleted so underlying collections can be freed // soon - if (_collectionKeys != nullptr) { - _collectionKeys->garbageCollect(true); - } + _collectionKeys->garbageCollect(true); std::vector collections; @@ -1678,68 +1674,6 @@ void TRI_ReleaseCollectionVocBase(TRI_vocbase_t* vocbase, TRI_READ_UNLOCK_STATUS_VOCBASE_COL(collection); } -//////////////////////////////////////////////////////////////////////////////// -/// @brief whether or not the vocbase has been marked as deleted -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_IsDeletedVocBase(TRI_vocbase_t* vocbase) { - auto refCount = vocbase->_refCount.load(); - // if the stored value is odd, it means the database has been marked as - // deleted - return (refCount % 2 == 1); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief increase the reference counter for a database -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_UseVocBase(TRI_vocbase_t* vocbase) { - // increase the reference counter by 2. - // this is because we use odd values to indicate that the database has been - // marked as deleted - auto oldValue = vocbase->_refCount.fetch_add(2, std::memory_order_release); - // check if the deleted bit is set - return (oldValue % 2 != 1); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief decrease the reference counter for a database -//////////////////////////////////////////////////////////////////////////////// - -void TRI_ReleaseVocBase(TRI_vocbase_t* vocbase) { -// decrease the reference counter by 2. -// this is because we use odd values to indicate that the database has been -// marked as deleted -#ifdef ARANGODB_ENABLE_MAINTAINER_MODE - auto oldValue = vocbase->_refCount.fetch_sub(2, std::memory_order_release); - TRI_ASSERT(oldValue >= 2); -#else - vocbase->_refCount.fetch_sub(2, std::memory_order_release); -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief marks a database as deleted -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_DropVocBase(TRI_vocbase_t* vocbase) { - auto oldValue = vocbase->_refCount.fetch_or(1, std::memory_order_release); - // if the previously stored value is odd, it means the database has already - // been marked as deleted - return (oldValue % 2 == 0); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns whether the database can be removed -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_CanRemoveVocBase(TRI_vocbase_t* vocbase) { - auto refCount = vocbase->_refCount.load(); - // we are intentionally comparing with exactly 1 here, because a 1 means - // that noone else references the database but it has been marked as deleted - return (refCount == 1); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief gets the "throw collection not loaded error" //////////////////////////////////////////////////////////////////////////////// @@ -1768,14 +1702,11 @@ TRI_vocbase_t::TRI_vocbase_t(TRI_vocbase_type_e type, TRI_voc_tick_t id, _refCount(0), _deadlockDetector(false), _userStructures(nullptr), - _queries(nullptr), - _cursorRepository(nullptr), - _collectionKeys(nullptr), _hasCompactor(false), _isOwnAppsDirectory(true) { - _queries = new arangodb::aql::QueryList(this); - _cursorRepository = new arangodb::CursorRepository(this); - _collectionKeys = new arangodb::CollectionKeysRepository(); + _queries.reset(new arangodb::aql::QueryList(this)); + _cursorRepository.reset(new arangodb::CursorRepository(this)); + _collectionKeys.reset(new arangodb::CollectionKeysRepository()); // init collections _collections.reserve(32); @@ -1801,13 +1732,9 @@ TRI_vocbase_t::~TRI_vocbase_t() { _cleanupThread.reset(); TRI_DestroyCondition(&_compactorCondition); - - delete _cursorRepository; - delete _collectionKeys; - delete _queries; } -std::string const TRI_vocbase_t::path() { +std::string TRI_vocbase_t::path() const { StorageEngine* engine = EngineSelectorFeature::ENGINE; return engine->databasePath(this); } diff --git a/arangod/VocBase/vocbase.h b/arangod/VocBase/vocbase.h index dc2042cbb1..74ea97467a 100644 --- a/arangod/VocBase/vocbase.h +++ b/arangod/VocBase/vocbase.h @@ -27,6 +27,7 @@ #include "Basics/Common.h" #include "Basics/ConditionVariable.h" #include "Basics/DeadlockDetector.h" +#include "Basics/Exceptions.h" #include "Basics/ReadWriteLock.h" #include "Basics/StringUtils.h" #include "Basics/threads.h" @@ -267,10 +268,11 @@ struct TRI_vocbase_t { // structures for user-defined volatile data void* _userStructures; - arangodb::aql::QueryList* _queries; - arangodb::CursorRepository* _cursorRepository; - arangodb::CollectionKeysRepository* _collectionKeys; - + private: + std::unique_ptr _queries; + std::unique_ptr _cursorRepository; + std::unique_ptr _collectionKeys; + public: bool _hasCompactor; bool _isOwnAppsDirectory; @@ -303,14 +305,68 @@ struct TRI_vocbase_t { /// @brief checks if a database name is allowed /// returns true if the name is allowed and false otherwise static bool IsAllowedName(bool allowSystem, std::string const& name); - std::string const name() { return _name; } - std::string const path(); + std::string const& name() const { return _name; } + std::string path() const; void updateReplicationClient(TRI_server_id_t, TRI_voc_tick_t); std::vector> getReplicationClients(); + arangodb::aql::QueryList* queryList() const { return _queries.get(); } + arangodb::CursorRepository* cursorRepository() const { return _cursorRepository.get(); } + arangodb::CollectionKeysRepository* collectionKeys() const { return _collectionKeys.get(); } + + /// @brief whether or not the vocbase has been marked as deleted + inline bool isDropped() const { + auto refCount = _refCount.load(); + // if the stored value is odd, it means the database has been marked as + // deleted + return (refCount % 2 == 1); + } + + /// @brief increase the reference counter for a database + bool use() { + // increase the reference counter by 2. + // this is because we use odd values to indicate that the database has been + // marked as deleted + auto oldValue = _refCount.fetch_add(2, std::memory_order_release); + // check if the deleted bit is set + return (oldValue % 2 != 1); + } + + /// @brief decrease the reference counter for a database + void release() { + // decrease the reference counter by 2. + // this is because we use odd values to indicate that the database has been + // marked as deleted +#ifdef ARANGODB_ENABLE_MAINTAINER_MODE + auto oldValue = _refCount.fetch_sub(2, std::memory_order_release); + TRI_ASSERT(oldValue >= 2); +#else + _refCount.fetch_sub(2, std::memory_order_release); +#endif + } + + /// @brief returns whether the database can be dropped + bool canBeDropped() const { + if (isSystem()) { + return false; + } + auto refCount = _refCount.load(); + // we are intentionally comparing with exactly 1 here, because a 1 means + // that noone else references the database but it has been marked as deleted + return (refCount == 1); + } + + /// @brief marks a database as deleted + bool markAsDropped() { + auto oldValue = _refCount.fetch_or(1, std::memory_order_release); + // if the previously stored value is odd, it means the database has already + // been marked as deleted + return (oldValue % 2 == 0); + } + /// @brief returns whether the database is the system database - bool isSystem() { return name() == TRI_VOC_SYSTEM_DATABASE; } + bool isSystem() const { return name() == TRI_VOC_SYSTEM_DATABASE; } /// @brief closes a database and all collections void shutdown(); @@ -343,6 +399,27 @@ struct TRI_vocbase_t { bool doOverride, bool writeMarker); }; +// scope guard for a database +// ensures that a database +class VocbaseGuard { + public: + VocbaseGuard() = delete; + VocbaseGuard(VocbaseGuard const&) = delete; + VocbaseGuard& operator=(VocbaseGuard const&) = delete; + + explicit VocbaseGuard(TRI_vocbase_t* vocbase) : _vocbase(vocbase) { + if (!_vocbase->use()) { + // database already dropped + THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); + } + } + ~VocbaseGuard() { _vocbase->release(); } + TRI_vocbase_t* vocbase() const { return _vocbase; } + + private: + TRI_vocbase_t* _vocbase; +}; + //////////////////////////////////////////////////////////////////////////////// /// @brief status of a collection /// @@ -518,36 +595,6 @@ TRI_vocbase_col_t* TRI_UseCollectionByNameVocBase(TRI_vocbase_t*, char const*, void TRI_ReleaseCollectionVocBase(TRI_vocbase_t*, TRI_vocbase_col_t*); -//////////////////////////////////////////////////////////////////////////////// -/// @brief whether or not the vocbase has been marked as deleted -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_IsDeletedVocBase(TRI_vocbase_t*); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief increase the reference counter for a database -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_UseVocBase(TRI_vocbase_t*); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief decrease the reference counter for a database -//////////////////////////////////////////////////////////////////////////////// - -void TRI_ReleaseVocBase(TRI_vocbase_t*); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief marks a database as deleted -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_DropVocBase(TRI_vocbase_t*); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns whether the database can be removed -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_CanRemoveVocBase(TRI_vocbase_t*); - //////////////////////////////////////////////////////////////////////////////// /// @brief gets the "throw collection not loaded error" //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Wal/RecoverState.cpp b/arangod/Wal/RecoverState.cpp index 7f75aa6751..788badcfd9 100644 --- a/arangod/Wal/RecoverState.cpp +++ b/arangod/Wal/RecoverState.cpp @@ -102,7 +102,7 @@ void RecoverState::releaseResources() { // release all databases for (auto it = openedDatabases.begin(); it != openedDatabases.end(); ++it) { - databaseFeature->releaseDatabase((*it).second); + (*it).second->release(); } openedDatabases.clear(); @@ -159,7 +159,7 @@ TRI_vocbase_t* RecoverState::releaseDatabase(TRI_voc_tick_t databaseId) { } } - databaseFeature->releaseDatabase(vocbase); + vocbase->release(); openedDatabases.erase(databaseId); return vocbase;