mirror of https://gitee.com/bigwinds/arangodb
moved database lookup functions into DatabaseFeature
This commit is contained in:
parent
b288d3e4dd
commit
33c94e5041
|
@ -470,6 +470,8 @@ void HeartbeatThread::removeDispatchedJob(DBServerAgencySyncResult result) {
|
|||
|
||||
static std::string const prefixPlanChangeCoordinator = "Plan/Databases";
|
||||
bool HeartbeatThread::handlePlanChangeCoordinator(uint64_t currentPlanVersion) {
|
||||
DatabaseFeature* databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
|
||||
LOG_TOPIC(TRACE, Logger::HEARTBEAT) << "found a plan update";
|
||||
AgencyCommResult result = _agency.getValues(prefixPlanChangeCoordinator);
|
||||
|
||||
|
@ -516,8 +518,7 @@ bool HeartbeatThread::handlePlanChangeCoordinator(uint64_t currentPlanVersion) {
|
|||
ids.push_back(id);
|
||||
}
|
||||
|
||||
TRI_vocbase_t* vocbase =
|
||||
TRI_UseCoordinatorDatabaseServer(_server, name.c_str());
|
||||
TRI_vocbase_t* vocbase = databaseFeature->useDatabaseCoordinator(name);
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
// database does not yet exist, create it now
|
||||
|
@ -528,7 +529,6 @@ bool HeartbeatThread::handlePlanChangeCoordinator(uint64_t currentPlanVersion) {
|
|||
}
|
||||
|
||||
// create a local database object...
|
||||
DatabaseFeature* databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
int res = databaseFeature->createDatabaseCoordinator(id, name, vocbase);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
|
@ -542,15 +542,13 @@ bool HeartbeatThread::handlePlanChangeCoordinator(uint64_t currentPlanVersion) {
|
|||
}
|
||||
|
||||
// get the list of databases that we know about locally
|
||||
std::vector<TRI_voc_tick_t> localIds =
|
||||
TRI_GetIdsCoordinatorDatabaseServer(_server);
|
||||
std::vector<TRI_voc_tick_t> localIds = databaseFeature->getDatabaseIdsCoordinator(false);
|
||||
|
||||
for (auto id : localIds) {
|
||||
auto r = std::find(ids.begin(), ids.end(), id);
|
||||
|
||||
if (r == ids.end()) {
|
||||
// local database not found in the plan...
|
||||
DatabaseFeature* databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
databaseFeature->dropDatabaseCoordinator(id, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,31 +216,30 @@ void GeneralServerFeature::validateOptions(std::shared_ptr<ProgramOptions>) {
|
|||
}
|
||||
}
|
||||
|
||||
static TRI_vocbase_t* LookupDatabaseFromRequest(GeneralRequest* request,
|
||||
TRI_server_t* server) {
|
||||
static TRI_vocbase_t* LookupDatabaseFromRequest(GeneralRequest* request) {
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
|
||||
// get database name from request
|
||||
std::string const& dbName = request->databaseName();
|
||||
|
||||
char const* p;
|
||||
if (dbName.empty()) {
|
||||
// if no databases was specified in the request, use system database name
|
||||
// as a fallback
|
||||
request->setDatabaseName(StaticStrings::SystemDatabase);
|
||||
p = StaticStrings::SystemDatabase.c_str();
|
||||
} else {
|
||||
p = dbName.c_str();
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
return databaseFeature->useDatabaseCoordinator(StaticStrings::SystemDatabase);
|
||||
}
|
||||
return databaseFeature->useDatabase(StaticStrings::SystemDatabase);
|
||||
}
|
||||
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
return TRI_UseCoordinatorDatabaseServer(server, p);
|
||||
return databaseFeature->useDatabaseCoordinator(dbName);
|
||||
}
|
||||
|
||||
return TRI_UseDatabaseServer(server, p);
|
||||
return databaseFeature->useDatabase(dbName);
|
||||
}
|
||||
|
||||
static bool SetRequestContext(GeneralRequest* request, void* data) {
|
||||
TRI_server_t* server = static_cast<TRI_server_t*>(data);
|
||||
TRI_vocbase_t* vocbase = LookupDatabaseFromRequest(request, server);
|
||||
TRI_vocbase_t* vocbase = LookupDatabaseFromRequest(request);
|
||||
|
||||
// invalid database name specified, database not found etc.
|
||||
if (vocbase == nullptr) {
|
||||
|
@ -284,8 +283,7 @@ void GeneralServerFeature::start() {
|
|||
|
||||
JOB_MANAGER = _jobManager.get();
|
||||
|
||||
_handlerFactory.reset(new RestHandlerFactory(&SetRequestContext,
|
||||
DatabaseFeature::SERVER));
|
||||
_handlerFactory.reset(new RestHandlerFactory(&SetRequestContext, nullptr));
|
||||
|
||||
HANDLER_FACTORY = _handlerFactory.get();
|
||||
|
||||
|
|
|
@ -68,10 +68,10 @@ class RestHandlerFactory {
|
|||
RestHandler* createHandler(GeneralRequest*, GeneralResponse*);
|
||||
|
||||
// adds a path and constructor to the factory
|
||||
void addHandler(std::string const& path, create_fptr, void* data = 0);
|
||||
void addHandler(std::string const& path, create_fptr, void* data = nullptr);
|
||||
|
||||
// adds a prefix path and constructor to the factory
|
||||
void addPrefixHandler(std::string const& path, create_fptr, void* data = 0);
|
||||
void addPrefixHandler(std::string const& path, create_fptr, void* data = nullptr);
|
||||
|
||||
// adds a path and constructor to the factory
|
||||
void addNotFoundHandler(create_fptr);
|
||||
|
|
|
@ -168,12 +168,11 @@ void BootstrapFeature::start() {
|
|||
|
||||
void BootstrapFeature::unprepare() {
|
||||
// notify all currently running queries about the shutdown
|
||||
TRI_server_t* s = DatabaseFeature::SERVER;
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
std::vector<TRI_voc_tick_t> ids =
|
||||
TRI_GetIdsCoordinatorDatabaseServer(s, true);
|
||||
for (auto& id : ids) {
|
||||
TRI_vocbase_t* vocbase = TRI_UseByIdCoordinatorDatabaseServer(s, id);
|
||||
for (auto& id : databaseFeature->getDatabaseIdsCoordinator(true)) {
|
||||
TRI_vocbase_t* vocbase = databaseFeature->useDatabase(id);
|
||||
|
||||
if (vocbase != nullptr) {
|
||||
vocbase->_queries->killAll(true);
|
||||
|
@ -181,16 +180,13 @@ void BootstrapFeature::unprepare() {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
std::vector<std::string> names;
|
||||
int res = TRI_GetDatabaseNamesServer(s, names);
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
for (auto& name : names) {
|
||||
TRI_vocbase_t* vocbase = TRI_UseDatabaseServer(s, name.c_str());
|
||||
std::vector<std::string> names = databaseFeature->getDatabaseNames();
|
||||
for (auto& name : databaseFeature->getDatabaseNames()) {
|
||||
TRI_vocbase_t* vocbase = databaseFeature->useDatabase(name);
|
||||
|
||||
if (vocbase != nullptr) {
|
||||
vocbase->_queries->killAll(true);
|
||||
TRI_ReleaseVocBase(vocbase);
|
||||
}
|
||||
if (vocbase != nullptr) {
|
||||
vocbase->_queries->killAll(true);
|
||||
TRI_ReleaseVocBase(vocbase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "V8Server/V8DealerFeature.h"
|
||||
#include "V8Server/v8-query.h"
|
||||
#include "V8Server/v8-vocbase.h"
|
||||
#include "VocBase/AuthInfo.h"
|
||||
#include "VocBase/KeyGenerator.h"
|
||||
#include "VocBase/replication-applier.h"
|
||||
#include "VocBase/server.h"
|
||||
|
@ -710,16 +711,145 @@ int DatabaseFeature::dropDatabase(TRI_voc_tick_t id, bool writeMarker, bool wait
|
|||
// and call the regular drop function
|
||||
return dropDatabase(name, writeMarker, waitForDeletion, removeAppsDirectory);
|
||||
}
|
||||
|
||||
std::vector<TRI_voc_tick_t> DatabaseFeature::getDatabaseIdsCoordinator(bool includeSystem) {
|
||||
std::vector<TRI_voc_tick_t> ids;
|
||||
{
|
||||
auto unuser(_databasesProtector.use());
|
||||
auto theLists = _databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_coordinatorDatabases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
TRI_ASSERT(vocbase != nullptr);
|
||||
|
||||
if (includeSystem || std::string(vocbase->_name) != TRI_VOC_SYSTEM_DATABASE) {
|
||||
ids.emplace_back(vocbase->_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::vector<TRI_voc_tick_t> DatabaseFeature::getDatabaseIds(bool includeSystem) {
|
||||
std::vector<TRI_voc_tick_t> ids;
|
||||
|
||||
{
|
||||
auto unuser(_databasesProtector.use());
|
||||
auto theLists = _databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_databases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
TRI_ASSERT(vocbase != nullptr);
|
||||
if (includeSystem || std::string(vocbase->_name) != TRI_VOC_SYSTEM_DATABASE) {
|
||||
ids.emplace_back(vocbase->_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// @brief return the list of all database names
|
||||
std::vector<std::string> DatabaseFeature::getDatabaseNames() {
|
||||
std::vector<std::string> names;
|
||||
|
||||
{
|
||||
auto unuser(_databasesProtector.use());
|
||||
auto theLists = _databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_databases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
TRI_ASSERT(vocbase != nullptr);
|
||||
TRI_ASSERT(vocbase->_name != nullptr);
|
||||
|
||||
names.emplace_back(vocbase->_name);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(
|
||||
names.begin(), names.end(),
|
||||
[](std::string const& l, std::string const& r) -> bool { return l < r; });
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
/// @brief return the list of all database names for a user
|
||||
std::vector<std::string> DatabaseFeature::getDatabaseNamesForUser(std::string const& username) {
|
||||
std::vector<std::string> names;
|
||||
|
||||
{
|
||||
auto unuser(_databasesProtector.use());
|
||||
auto theLists = _databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_databases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
TRI_ASSERT(vocbase != nullptr);
|
||||
TRI_ASSERT(vocbase->_name != nullptr);
|
||||
|
||||
auto level =
|
||||
GeneralServerFeature::AUTH_INFO.canUseDatabase(username, vocbase->_name);
|
||||
|
||||
if (level == AuthLevel::NONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
names.emplace_back(vocbase->_name);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(
|
||||
names.begin(), names.end(),
|
||||
[](std::string const& l, std::string const& r) -> bool { return l < r; });
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
void DatabaseFeature::useSystemDatabase() {
|
||||
useDatabase(TRI_VOC_SYSTEM_DATABASE);
|
||||
}
|
||||
|
||||
/// @brief get a coordinator database by its id
|
||||
/// this will increase the reference-counter for the database
|
||||
TRI_vocbase_t* DatabaseFeature::useDatabaseCoordinator(TRI_voc_tick_t id) {
|
||||
auto unuser(_databasesProtector.use());
|
||||
auto theLists = _databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_coordinatorDatabases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
|
||||
if (vocbase->_id == id) {
|
||||
bool result TRI_UNUSED = TRI_UseVocBase(vocbase);
|
||||
|
||||
// if we got here, no one else can have deleted the database
|
||||
TRI_ASSERT(result == true);
|
||||
return vocbase;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return vocbase;
|
||||
}
|
||||
|
||||
TRI_vocbase_t* DatabaseFeature::useDatabase(std::string const& name) {
|
||||
auto unuser(_databasesProtector.use());
|
||||
auto theLists = _databasesLists.load();
|
||||
auto it = theLists->_databases.find(name);
|
||||
|
||||
TRI_vocbase_t* vocbase = nullptr;
|
||||
auto it = theLists->_databases.find(name);
|
||||
|
||||
if (it != theLists->_databases.end()) {
|
||||
vocbase = it->second;
|
||||
|
@ -729,6 +859,44 @@ TRI_vocbase_t* DatabaseFeature::useDatabase(std::string const& name) {
|
|||
return vocbase;
|
||||
}
|
||||
|
||||
TRI_vocbase_t* DatabaseFeature::useDatabase(TRI_voc_tick_t id) {
|
||||
auto unuser(_databasesProtector.use());
|
||||
auto theLists = _databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_databases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
|
||||
if (vocbase->_id == id) {
|
||||
TRI_UseVocBase(vocbase);
|
||||
return vocbase;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
TRI_vocbase_t* DatabaseFeature::lookupDatabase(std::string const& name) {
|
||||
auto unuser(_databasesProtector.use());
|
||||
auto theLists = _databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_databases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
|
||||
if (name == vocbase->_name) {
|
||||
return vocbase;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DatabaseFeature::updateContexts() {
|
||||
TRI_ASSERT(_vocbase != nullptr);
|
||||
|
||||
|
|
|
@ -77,14 +77,27 @@ class DatabaseFeature final : public application_features::ApplicationFeature {
|
|||
void unprepare() override final;
|
||||
|
||||
public:
|
||||
/// @brief get the ids of all local coordinator databases
|
||||
std::vector<TRI_voc_tick_t> getDatabaseIdsCoordinator(bool includeSystem);
|
||||
std::vector<TRI_voc_tick_t> getDatabaseIds(bool includeSystem);
|
||||
std::vector<std::string> getDatabaseNames();
|
||||
std::vector<std::string> getDatabaseNamesForUser(std::string const& user);
|
||||
|
||||
int createDatabaseCoordinator(TRI_voc_tick_t id, std::string const& name, TRI_vocbase_t*& result);
|
||||
int createDatabase(TRI_voc_tick_t id, std::string const& name, bool writeMarker, TRI_vocbase_t*& result);
|
||||
int dropDatabaseCoordinator(TRI_voc_tick_t id, bool force);
|
||||
int dropDatabase(std::string const& name, bool writeMarker, bool waitForDeletion, bool removeAppsDirectory);
|
||||
int dropDatabase(TRI_voc_tick_t id, bool writeMarker, bool waitForDeletion, bool removeAppsDirectory);
|
||||
|
||||
void useSystemDatabase();
|
||||
TRI_vocbase_t* useDatabaseCoordinator(std::string const& name);
|
||||
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);
|
||||
|
||||
void useSystemDatabase();
|
||||
TRI_vocbase_t* systemDatabase() const { return _vocbase; }
|
||||
bool ignoreDatafileErrors() const { return _ignoreDatafileErrors; }
|
||||
bool isInitiallyEmpty() const { return _isInitiallyEmpty; }
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
#ifndef ARANGOD_UTILS_DATABASE_GUARD_H
|
||||
#define ARANGOD_UTILS_DATABASE_GUARD_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "ApplicationFeatures/ApplicationServer.h"
|
||||
#include "Basics/Exceptions.h"
|
||||
#include "RestServer/DatabaseFeature.h"
|
||||
#include "VocBase/server.h"
|
||||
|
||||
struct TRI_vocbase_t;
|
||||
|
@ -43,7 +44,9 @@ class DatabaseGuard {
|
|||
|
||||
DatabaseGuard(TRI_server_t* server, TRI_voc_tick_t id)
|
||||
: _server(server), _database(nullptr) {
|
||||
_database = TRI_UseDatabaseByIdServer(server, id);
|
||||
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
_database = databaseFeature->useDatabase(id);
|
||||
|
||||
if (_database == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
|
@ -56,7 +59,9 @@ class DatabaseGuard {
|
|||
|
||||
DatabaseGuard(TRI_server_t* server, char const* name)
|
||||
: _server(server), _database(nullptr) {
|
||||
_database = TRI_UseDatabaseServer(server, name);
|
||||
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
_database = databaseFeature->useDatabase(name);
|
||||
|
||||
if (_database == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
|
@ -69,7 +74,8 @@ class DatabaseGuard {
|
|||
|
||||
~DatabaseGuard() {
|
||||
if (_database != nullptr) {
|
||||
TRI_ReleaseDatabaseServer(_server, _database);
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
databaseFeature->releaseDatabase(_database);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#ifndef ARANGOD_UTILS_REPLICATION_TRANSACTION_H
|
||||
#define ARANGOD_UTILS_REPLICATION_TRANSACTION_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "ApplicationFeatures/ApplicationServer.h"
|
||||
#include "RestServer/DatabaseFeature.h"
|
||||
#include "Utils/StandaloneTransactionContext.h"
|
||||
#include "Utils/Transaction.h"
|
||||
|
@ -44,7 +44,8 @@ class ReplicationTransaction : public Transaction {
|
|||
ReplicationTransaction(TRI_vocbase_t* vocbase)
|
||||
: Transaction(StandaloneTransactionContext::Create(vocbase)) {
|
||||
|
||||
TRI_UseDatabaseServer(DatabaseFeature::SERVER, vocbase->_name);
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
databaseFeature->useDatabase(vocbase->_name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -52,7 +53,8 @@ class ReplicationTransaction : public Transaction {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
~ReplicationTransaction() {
|
||||
TRI_ReleaseDatabaseServer(DatabaseFeature::SERVER, vocbase());
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
databaseFeature->releaseDatabase(vocbase());
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -2031,7 +2031,8 @@ static void JS_UseDatabase(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_FORBIDDEN);
|
||||
}
|
||||
|
||||
std::string name = TRI_ObjectToString(args[0]);
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
std::string const name = TRI_ObjectToString(args[0]);
|
||||
|
||||
TRI_vocbase_t* vocbase = GetContextVocBase(isolate);
|
||||
|
||||
|
@ -2049,12 +2050,10 @@ static void JS_UseDatabase(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
}
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
vocbase = TRI_UseCoordinatorDatabaseServer(
|
||||
static_cast<TRI_server_t*>(v8g->_server), name.c_str());
|
||||
vocbase = databaseFeature->useDatabaseCoordinator(name);
|
||||
} else {
|
||||
// check if the other database exists, and increase its refcount
|
||||
vocbase = TRI_UseDatabaseServer(static_cast<TRI_server_t*>(v8g->_server),
|
||||
name.c_str());
|
||||
vocbase = databaseFeature->useDatabase(name);
|
||||
}
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
|
@ -2067,8 +2066,7 @@ static void JS_UseDatabase(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
|
||||
v8g->_vocbase = vocbase;
|
||||
TRI_ASSERT(orig != vocbase);
|
||||
TRI_ReleaseDatabaseServer(static_cast<TRI_server_t*>(v8g->_server),
|
||||
static_cast<TRI_vocbase_t*>(orig));
|
||||
databaseFeature->releaseDatabase(static_cast<TRI_vocbase_t*>(orig));
|
||||
|
||||
TRI_V8_RETURN(WrapVocBase(isolate, vocbase));
|
||||
}
|
||||
|
@ -2171,26 +2169,15 @@ static void JS_Databases(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
return;
|
||||
}
|
||||
|
||||
TRI_GET_GLOBALS();
|
||||
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
std::vector<std::string> names;
|
||||
|
||||
int res;
|
||||
|
||||
if (argc == 0) {
|
||||
// return all databases
|
||||
res = TRI_GetDatabaseNamesServer(static_cast<TRI_server_t*>(v8g->_server),
|
||||
names);
|
||||
names = databaseFeature->getDatabaseNames();
|
||||
} else {
|
||||
// return all databases for a specific user
|
||||
std::string&& username = TRI_ObjectToString(args[0]);
|
||||
|
||||
res = TRI_GetUserDatabasesServer(static_cast<TRI_server_t*>(v8g->_server),
|
||||
username.c_str(), names);
|
||||
}
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_V8_THROW_EXCEPTION(res);
|
||||
names = databaseFeature->getDatabaseNamesForUser(TRI_ObjectToString(args[0]));
|
||||
}
|
||||
|
||||
v8::Handle<v8::Array> result = v8::Array::New(isolate, (int)names.size());
|
||||
|
@ -2267,10 +2254,11 @@ static void CreateDatabaseCoordinator(
|
|||
// now wait for heartbeat thread to create the database object
|
||||
TRI_vocbase_t* vocbase = nullptr;
|
||||
int tries = 0;
|
||||
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
|
||||
while (++tries <= 6000) {
|
||||
vocbase = TRI_UseByIdCoordinatorDatabaseServer(
|
||||
static_cast<TRI_server_t*>(v8g->_server), id);
|
||||
vocbase = databaseFeature->useDatabaseCoordinator(id);
|
||||
|
||||
if (vocbase != nullptr) {
|
||||
break;
|
||||
|
@ -2418,12 +2406,10 @@ static void DropDatabaseCoordinator(
|
|||
v8::Isolate* isolate = args.GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
TRI_GET_GLOBALS();
|
||||
|
||||
// Arguments are already checked, there is exactly one argument
|
||||
auto databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
std::string const name = TRI_ObjectToString(args[0]);
|
||||
TRI_vocbase_t* vocbase = TRI_UseCoordinatorDatabaseServer(
|
||||
static_cast<TRI_server_t*>(v8g->_server), name.c_str());
|
||||
TRI_vocbase_t* vocbase = databaseFeature->useDatabaseCoordinator(name);
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
// no such database
|
||||
|
@ -2446,8 +2432,7 @@ static void DropDatabaseCoordinator(
|
|||
int tries = 0;
|
||||
|
||||
while (++tries <= 6000) {
|
||||
TRI_vocbase_t* vocbase = TRI_UseByIdCoordinatorDatabaseServer(
|
||||
static_cast<TRI_server_t*>(v8g->_server), id);
|
||||
TRI_vocbase_t* vocbase = databaseFeature->useDatabaseCoordinator(id);
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
// object has vanished
|
||||
|
|
|
@ -173,215 +173,6 @@ int TRI_InitDatabasesServer(TRI_server_t* server) {
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the ids of all local coordinator databases
|
||||
/// the caller is responsible for freeing the result
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<TRI_voc_tick_t> TRI_GetIdsCoordinatorDatabaseServer(
|
||||
TRI_server_t* server, bool includeSystem) {
|
||||
std::vector<TRI_voc_tick_t> v;
|
||||
{
|
||||
auto unuser(server->_databasesProtector.use());
|
||||
auto theLists = server->_databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_coordinatorDatabases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
TRI_ASSERT(vocbase != nullptr);
|
||||
|
||||
if (includeSystem ||
|
||||
!TRI_EqualString(vocbase->_name, TRI_VOC_SYSTEM_DATABASE)) {
|
||||
v.emplace_back(vocbase->_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a coordinator database by its id
|
||||
/// this will increase the reference-counter for the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* TRI_UseByIdCoordinatorDatabaseServer(TRI_server_t* server,
|
||||
TRI_voc_tick_t id) {
|
||||
auto unuser(server->_databasesProtector.use());
|
||||
auto theLists = server->_databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_coordinatorDatabases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
|
||||
if (vocbase->_id == id) {
|
||||
bool result TRI_UNUSED = TRI_UseVocBase(vocbase);
|
||||
|
||||
// if we got here, no one else can have deleted the database
|
||||
TRI_ASSERT(result == true);
|
||||
return vocbase;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a coordinator database by its name
|
||||
/// this will increase the reference-counter for the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* TRI_UseCoordinatorDatabaseServer(TRI_server_t* server,
|
||||
char const* name) {
|
||||
auto unuser(server->_databasesProtector.use());
|
||||
auto theLists = server->_databasesLists.load();
|
||||
auto it = theLists->_coordinatorDatabases.find(std::string(name));
|
||||
TRI_vocbase_t* vocbase = nullptr;
|
||||
|
||||
if (it != theLists->_coordinatorDatabases.end()) {
|
||||
vocbase = it->second;
|
||||
TRI_UseVocBase(vocbase);
|
||||
}
|
||||
|
||||
return vocbase;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a database by its name
|
||||
/// this will increase the reference-counter for the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* TRI_UseDatabaseServer(TRI_server_t* server, char const* name) {
|
||||
auto unuser(server->_databasesProtector.use());
|
||||
auto theLists = server->_databasesLists.load();
|
||||
auto it = theLists->_databases.find(std::string(name));
|
||||
TRI_vocbase_t* vocbase = nullptr;
|
||||
|
||||
if (it != theLists->_databases.end()) {
|
||||
vocbase = it->second;
|
||||
TRI_UseVocBase(vocbase);
|
||||
}
|
||||
|
||||
return vocbase;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lookup a database by its name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* TRI_LookupDatabaseByNameServer(TRI_server_t* server,
|
||||
char const* name) {
|
||||
auto unuser(server->_databasesProtector.use());
|
||||
auto theLists = server->_databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_databases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
|
||||
if (TRI_EqualString(vocbase->_name, name)) {
|
||||
return vocbase;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a database by its id
|
||||
/// this will increase the reference-counter for the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* TRI_UseDatabaseByIdServer(TRI_server_t* server,
|
||||
TRI_voc_tick_t id) {
|
||||
auto unuser(server->_databasesProtector.use());
|
||||
auto theLists = server->_databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_databases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
|
||||
if (vocbase->_id == id) {
|
||||
TRI_UseVocBase(vocbase);
|
||||
return vocbase;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief release a previously used database
|
||||
/// this will decrease the reference-counter for the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_ReleaseDatabaseServer(TRI_server_t* server, TRI_vocbase_t* vocbase) {
|
||||
TRI_ReleaseVocBase(vocbase);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the list of all databases a user can see
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_GetUserDatabasesServer(TRI_server_t* server, char const* username,
|
||||
std::vector<std::string>& names) {
|
||||
int res = TRI_ERROR_NO_ERROR;
|
||||
|
||||
{
|
||||
auto unuser(server->_databasesProtector.use());
|
||||
auto theLists = server->_databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_databases) {
|
||||
char const* dbName = p.second->_name;
|
||||
TRI_ASSERT(dbName != nullptr);
|
||||
|
||||
auto level =
|
||||
GeneralServerFeature::AUTH_INFO.canUseDatabase(username, dbName);
|
||||
|
||||
if (level == AuthLevel::NONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
names.emplace_back(dbName);
|
||||
} catch (...) {
|
||||
return TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(
|
||||
names.begin(), names.end(),
|
||||
[](std::string const& l, std::string const& r) -> bool { return l < r; });
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the list of all database names
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_GetDatabaseNamesServer(TRI_server_t* server,
|
||||
std::vector<std::string>& names) {
|
||||
int res = TRI_ERROR_NO_ERROR;
|
||||
|
||||
{
|
||||
auto unuser(server->_databasesProtector.use());
|
||||
auto theLists = server->_databasesLists.load();
|
||||
|
||||
for (auto& p : theLists->_databases) {
|
||||
TRI_vocbase_t* vocbase = p.second;
|
||||
TRI_ASSERT(vocbase != nullptr);
|
||||
TRI_ASSERT(vocbase->_name != nullptr);
|
||||
|
||||
try {
|
||||
names.emplace_back(vocbase->_name);
|
||||
} catch (...) {
|
||||
return TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(
|
||||
names.begin(), names.end(),
|
||||
[](std::string const& l, std::string const& r) -> bool { return l < r; });
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the current operation mode of the server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -69,68 +69,6 @@ struct TRI_server_t {
|
|||
|
||||
int TRI_InitDatabasesServer(TRI_server_t*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the ids of all local coordinator databases
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<TRI_voc_tick_t> TRI_GetIdsCoordinatorDatabaseServer(TRI_server_t*,
|
||||
bool includeSystem = false);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a coordinator database by its id
|
||||
/// this will increase the reference-counter for the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* TRI_UseByIdCoordinatorDatabaseServer(TRI_server_t*,
|
||||
TRI_voc_tick_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief use a coordinator database by its name
|
||||
/// this will increase the reference-counter for the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* TRI_UseCoordinatorDatabaseServer(TRI_server_t*, char const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief use a database by its name
|
||||
/// this will increase the reference-counter for the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* TRI_UseDatabaseServer(TRI_server_t*, char const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lookup a database by its name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* TRI_LookupDatabaseByNameServer(TRI_server_t*, char const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief use a database by its id
|
||||
/// this will increase the reference-counter for the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vocbase_t* TRI_UseDatabaseByIdServer(TRI_server_t*, TRI_voc_tick_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief release a previously used database
|
||||
/// this will decrease the reference-counter for the database
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_ReleaseDatabaseServer(TRI_server_t*, TRI_vocbase_t*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the list of all databases a user can see
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_GetUserDatabasesServer(TRI_server_t*, char const*,
|
||||
std::vector<std::string>&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the list of all database names
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_GetDatabaseNamesServer(TRI_server_t*, std::vector<std::string>&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the current operation mode of the server
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -303,7 +303,7 @@ void LogfileManager::start() {
|
|||
|
||||
// initialize some objects
|
||||
_slots = new Slots(this, _numberOfSlots, 0);
|
||||
_recoverState = new RecoverState(_server, _ignoreRecoveryErrors);
|
||||
_recoverState = new RecoverState(_ignoreRecoveryErrors);
|
||||
|
||||
TRI_ASSERT(!_allowWrites);
|
||||
|
||||
|
|
|
@ -69,8 +69,8 @@ static inline T NumericValue(VPackSlice const& slice, char const* attribute) {
|
|||
}
|
||||
|
||||
/// @brief creates the recover state
|
||||
RecoverState::RecoverState(TRI_server_t* server, bool ignoreRecoveryErrors)
|
||||
: server(server),
|
||||
RecoverState::RecoverState(bool ignoreRecoveryErrors)
|
||||
: databaseFeature(nullptr),
|
||||
failedTransactions(),
|
||||
lastTick(0),
|
||||
logfilesToProcess(),
|
||||
|
@ -80,7 +80,10 @@ RecoverState::RecoverState(TRI_server_t* server, bool ignoreRecoveryErrors)
|
|||
ignoreRecoveryErrors(ignoreRecoveryErrors),
|
||||
errorCount(0),
|
||||
lastDatabaseId(0),
|
||||
lastCollectionId(0) {}
|
||||
lastCollectionId(0) {
|
||||
|
||||
databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
}
|
||||
|
||||
/// @brief destroys the recover state
|
||||
RecoverState::~RecoverState() { releaseResources(); }
|
||||
|
@ -99,8 +102,7 @@ void RecoverState::releaseResources() {
|
|||
|
||||
// release all databases
|
||||
for (auto it = openedDatabases.begin(); it != openedDatabases.end(); ++it) {
|
||||
TRI_vocbase_t* vocbase = (*it).second;
|
||||
TRI_ReleaseDatabaseServer(server, vocbase);
|
||||
databaseFeature->releaseDatabase((*it).second);
|
||||
}
|
||||
|
||||
openedDatabases.clear();
|
||||
|
@ -114,7 +116,7 @@ TRI_vocbase_t* RecoverState::useDatabase(TRI_voc_tick_t databaseId) {
|
|||
return (*it).second;
|
||||
}
|
||||
|
||||
TRI_vocbase_t* vocbase = TRI_UseDatabaseByIdServer(server, databaseId);
|
||||
TRI_vocbase_t* vocbase = databaseFeature->useDatabase(databaseId);
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
return nullptr;
|
||||
|
@ -157,7 +159,7 @@ TRI_vocbase_t* RecoverState::releaseDatabase(TRI_voc_tick_t databaseId) {
|
|||
}
|
||||
}
|
||||
|
||||
TRI_ReleaseDatabaseServer(server, vocbase);
|
||||
databaseFeature->releaseDatabase(vocbase);
|
||||
openedDatabases.erase(databaseId);
|
||||
|
||||
return vocbase;
|
||||
|
@ -818,11 +820,10 @@ bool RecoverState::ReplayMarker(TRI_df_marker_t const* marker, void* data,
|
|||
if (state->willBeDropped(collectionId)) {
|
||||
// in case we detect that this collection is going to be deleted anyway,
|
||||
// set the sync properties to false temporarily
|
||||
auto database = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
bool oldSync = database->forceSyncProperties();
|
||||
database->forceSyncProperties(false);
|
||||
bool oldSync = state->databaseFeature->forceSyncProperties();
|
||||
state->databaseFeature->forceSyncProperties(false);
|
||||
collection = TRI_CreateCollectionVocBase(vocbase, info, collectionId, false);
|
||||
database->forceSyncProperties(oldSync);
|
||||
state->databaseFeature->forceSyncProperties(oldSync);
|
||||
} else {
|
||||
// collection will be kept
|
||||
collection =
|
||||
|
@ -855,9 +856,8 @@ bool RecoverState::ReplayMarker(TRI_df_marker_t const* marker, void* data,
|
|||
|
||||
if (vocbase != nullptr) {
|
||||
// remove already existing database
|
||||
DatabaseFeature* databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
// TODO: how to signal a dropDatabase failure here?
|
||||
databaseFeature->dropDatabase(databaseId, false, true, false);
|
||||
state->databaseFeature->dropDatabase(databaseId, false, true, false);
|
||||
}
|
||||
|
||||
VPackSlice const nameSlice = payloadSlice.get("name");
|
||||
|
@ -871,16 +871,14 @@ bool RecoverState::ReplayMarker(TRI_df_marker_t const* marker, void* data,
|
|||
std::string nameString = nameSlice.copyString();
|
||||
|
||||
// remove already existing database with same name
|
||||
vocbase =
|
||||
TRI_LookupDatabaseByNameServer(state->server, nameString.c_str());
|
||||
vocbase = state->databaseFeature->lookupDatabase(nameString);
|
||||
|
||||
if (vocbase != nullptr) {
|
||||
TRI_voc_tick_t otherId = vocbase->_id;
|
||||
|
||||
state->releaseDatabase(otherId);
|
||||
DatabaseFeature* databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
// TODO: how to signal a dropDatabase failure here?
|
||||
databaseFeature->dropDatabase(nameString, false, true, false);
|
||||
state->databaseFeature->dropDatabase(nameString, false, true, false);
|
||||
}
|
||||
|
||||
vocbase = nullptr;
|
||||
|
@ -888,8 +886,7 @@ bool RecoverState::ReplayMarker(TRI_df_marker_t const* marker, void* data,
|
|||
WaitForDeletion(state->server, databaseId,
|
||||
TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
*/
|
||||
DatabaseFeature* databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
int res = databaseFeature->createDatabase(databaseId, nameString, false, vocbase);
|
||||
int res = state->databaseFeature->createDatabase(databaseId, nameString, false, vocbase);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
LOG(WARN) << "cannot create database " << databaseId << ": " << TRI_errno_string(res);
|
||||
|
@ -1005,8 +1002,7 @@ bool RecoverState::ReplayMarker(TRI_df_marker_t const* marker, void* data,
|
|||
|
||||
if (vocbase != nullptr) {
|
||||
// ignore any potential error returned by this call
|
||||
DatabaseFeature* databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
databaseFeature->dropDatabase(databaseId, false, true, false);
|
||||
state->databaseFeature->dropDatabase(databaseId, false, true, false);
|
||||
}
|
||||
|
||||
#ifdef ARANGODB_ENABLE_ROCKSDB
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include "Wal/Marker.h"
|
||||
|
||||
namespace arangodb {
|
||||
class DatabaseFeature;
|
||||
|
||||
namespace wal {
|
||||
|
||||
/// @brief state that is built up when scanning a WAL logfile during recovery
|
||||
|
@ -43,7 +45,7 @@ struct RecoverState {
|
|||
RecoverState& operator=(RecoverState const&) = delete;
|
||||
|
||||
/// @brief creates the recover state
|
||||
RecoverState(TRI_server_t*, bool);
|
||||
explicit RecoverState(bool);
|
||||
|
||||
/// @brief destroys the recover state
|
||||
~RecoverState();
|
||||
|
@ -152,7 +154,7 @@ struct RecoverState {
|
|||
/// @brief fill the secondary indexes of all collections used in recovery
|
||||
int fillIndexes();
|
||||
|
||||
TRI_server_t* server;
|
||||
DatabaseFeature* databaseFeature;
|
||||
std::unordered_map<TRI_voc_tid_t, std::pair<TRI_voc_tick_t, bool>>
|
||||
failedTransactions;
|
||||
std::unordered_set<TRI_voc_cid_t> droppedCollections;
|
||||
|
|
Loading…
Reference in New Issue