diff --git a/arangod/Agency/MoveShard.cpp b/arangod/Agency/MoveShard.cpp index f3102a3f55..c128905e64 100644 --- a/arangod/Agency/MoveShard.cpp +++ b/arangod/Agency/MoveShard.cpp @@ -855,7 +855,7 @@ arangodb::Result MoveShard::abort() { // Current preconditions for all shards doForAllShards( _snapshot, _database, shardsLikeMe, - [this, &trx]( + [&trx]( Slice plan, Slice current, std::string& planPath, std::string& curPath) { // Current still as is trx.add(curPath, current); diff --git a/arangod/Agency/Supervision.cpp b/arangod/Agency/Supervision.cpp index 7c761f4234..9ec7a70835 100644 --- a/arangod/Agency/Supervision.cpp +++ b/arangod/Agency/Supervision.cpp @@ -695,9 +695,9 @@ bool Supervision::updateSnapshot() { // All checks, guarded by main thread bool Supervision::doChecks() { _lock.assertLockedByCurrentThread(); - TRI_ASSERT(ServerState::roleToAgencyListKey(ServerState::ROLE_PRIMARY) == + TRI_ASSERT(ServerState::roleToAgencyListKey(ServerState::ROLE_DBSERVER) == "DBServers"); - check(ServerState::roleToAgencyListKey(ServerState::ROLE_PRIMARY)); + check(ServerState::roleToAgencyListKey(ServerState::ROLE_DBSERVER)); TRI_ASSERT(ServerState::roleToAgencyListKey(ServerState::ROLE_COORDINATOR) == "Coordinators"); check(ServerState::roleToAgencyListKey(ServerState::ROLE_COORDINATOR)); diff --git a/arangod/Aql/EngineInfoContainerCoordinator.cpp b/arangod/Aql/EngineInfoContainerCoordinator.cpp index 55da4df36f..6046e49508 100644 --- a/arangod/Aql/EngineInfoContainerCoordinator.cpp +++ b/arangod/Aql/EngineInfoContainerCoordinator.cpp @@ -157,7 +157,7 @@ ExecutionEngineResult EngineInfoContainerCoordinator::buildEngines( Query* localQuery = query; try { bool first = true; - for (auto const& info : _engines) { + for (EngineInfo const& info : _engines) { if (!first) { // need a new query instance on the coordinator localQuery = query->clone(PART_DEPENDENT, false); diff --git a/arangod/Aql/EngineInfoContainerDBServer.cpp b/arangod/Aql/EngineInfoContainerDBServer.cpp index 8016f55dac..960f7643c9 100644 --- a/arangod/Aql/EngineInfoContainerDBServer.cpp +++ b/arangod/Aql/EngineInfoContainerDBServer.cpp @@ -39,6 +39,7 @@ #include "Graph/BaseOptions.h" #include "RestServer/QueryRegistryFeature.h" #include "StorageEngine/TransactionState.h" +#include "Utils/CollectionNameResolver.h" #include "VocBase/LogicalCollection.h" #include "VocBase/ticks.h" #ifdef USE_IRESEARCH diff --git a/arangod/Aql/Functions.cpp b/arangod/Aql/Functions.cpp index 79278f254b..33a7796c4e 100644 --- a/arangod/Aql/Functions.cpp +++ b/arangod/Aql/Functions.cpp @@ -1466,6 +1466,7 @@ AqlValue Functions::LevenshteinDistance(ExpressionContext*, transaction::Methods AqlValue const& value1 = extractFunctionParameterValue(parameters, 0); AqlValue const& value2 = extractFunctionParameterValue(parameters, 1); + // FIXME: there is only one shared stringbuffer instance transaction::StringBufferLeaser buffer1(trx); transaction::StringBufferLeaser buffer2(trx); diff --git a/arangod/Aql/OptimizerRules.cpp b/arangod/Aql/OptimizerRules.cpp index 1c23fe754a..15446c7eaa 100644 --- a/arangod/Aql/OptimizerRules.cpp +++ b/arangod/Aql/OptimizerRules.cpp @@ -58,6 +58,7 @@ #include "StorageEngine/EngineSelectorFeature.h" #include "StorageEngine/StorageEngine.h" #include "Transaction/Methods.h" +#include "Utils/CollectionNameResolver.h" #include "VocBase/Methods/Collections.h" #ifdef USE_IRESEARCH diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index 345b32939c..45dbf94d48 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -358,6 +358,7 @@ void Query::prepare(QueryRegistry* registry) { // create the transaction object, but do not start it yet _trx = AqlTransaction::create(createTransactionContext(), _collections.collections(), _queryOptions.transactionOptions, _part == PART_MAIN); + _trx->addHint(transaction::Hints::Hint::FROM_TOPLEVEL_AQL); // only used on toplevel VPackBuilder* builder = planCacheEntry->builder.get(); VPackSlice slice = builder->slice(); @@ -368,10 +369,6 @@ void Query::prepare(QueryRegistry* registry) { int res = trx->addCollections(*_collections.collections()); - if (!trx->transactionContextPtr()->getParentTransaction()) { - trx->addHint(transaction::Hints::Hint::FROM_TOPLEVEL_AQL); - } - if (res == TRI_ERROR_NO_ERROR) { res = _trx->begin(); } @@ -470,10 +467,7 @@ ExecutionPlan* Query::preparePlan() { TRI_DEFER(trx.release()); // create the transaction object, but do not start it yet _trx = trx.get(); - - if (!trx->transactionContextPtr()->getParentTransaction()) { - trx->addHint(transaction::Hints::Hint::FROM_TOPLEVEL_AQL); - } + _trx->addHint(transaction::Hints::Hint::FROM_TOPLEVEL_AQL); // only used on toplevel // As soon as we start to instantiate the plan we have to clean it // up before killing the unique_ptr diff --git a/arangod/CMakeLists.txt b/arangod/CMakeLists.txt index ebe84ecc52..b68c531f23 100644 --- a/arangod/CMakeLists.txt +++ b/arangod/CMakeLists.txt @@ -494,7 +494,6 @@ SET(ARANGOD_SOURCES RestServer/ServerFeature.cpp RestServer/ServerIdFeature.cpp RestServer/SystemDatabaseFeature.cpp - RestServer/TransactionManagerFeature.cpp RestServer/TraverserEngineRegistryFeature.cpp RestServer/TtlFeature.cpp RestServer/UpgradeFeature.cpp @@ -527,6 +526,8 @@ SET(ARANGOD_SOURCES Transaction/SmartContext.cpp Transaction/StandaloneContext.cpp Transaction/Status.cpp + Transaction/Manager.cpp + Transaction/ManagerFeature.cpp Transaction/V8Context.cpp Utils/CollectionKeys.cpp Utils/CollectionKeysRepository.cpp diff --git a/arangod/Cluster/ClusterMethods.cpp b/arangod/Cluster/ClusterMethods.cpp index 474c97cdaf..3b3f2e9d02 100644 --- a/arangod/Cluster/ClusterMethods.cpp +++ b/arangod/Cluster/ClusterMethods.cpp @@ -21,6 +21,8 @@ /// @author Max Neunhoeffer //////////////////////////////////////////////////////////////////////////////// +#include "ClusterMethods.h" + #include "Basics/NumberUtils.h" #include "Basics/StaticStrings.h" #include "Basics/StringUtils.h" @@ -29,7 +31,6 @@ #include "Basics/tri-strings.h" #include "Cluster/ClusterComm.h" #include "Cluster/ClusterInfo.h" -#include "ClusterMethods.h" #include "Graph/Traverser.h" #include "Indexes/Index.h" #include "RestServer/TtlFeature.h" @@ -50,6 +51,7 @@ #include #include +using namespace arangodb; using namespace arangodb::basics; using namespace arangodb::rest; @@ -174,32 +176,6 @@ static std::unique_ptr> CreateNoLoc namespace arangodb { -static int handleGeneralCommErrors(ClusterCommResult const* res) { - // This function creates an error code from a ClusterCommResult, - // but only if it is a communication error. If the communication - // was successful and there was an HTTP error code, this function - // returns TRI_ERROR_NO_ERROR. - // If TRI_ERROR_NO_ERROR is returned, then the result was CL_COMM_RECEIVED - // and .answer can safely be inspected. - if (res->status == CL_COMM_TIMEOUT) { - // No reply, we give up: - return TRI_ERROR_CLUSTER_TIMEOUT; - } else if (res->status == CL_COMM_ERROR) { - return TRI_ERROR_CLUSTER_CONNECTION_LOST; - } else if (res->status == CL_COMM_BACKEND_UNAVAILABLE) { - if (res->result == nullptr) { - return TRI_ERROR_CLUSTER_CONNECTION_LOST; - } - if (!res->result->isComplete()) { - // there is no result - return TRI_ERROR_CLUSTER_CONNECTION_LOST; - } - return TRI_ERROR_CLUSTER_BACKEND_UNAVAILABLE; - } - - return TRI_ERROR_NO_ERROR; -} - //////////////////////////////////////////////////////////////////////////////// /// @brief extracts a numeric value from an hierarchical VelocyPack //////////////////////////////////////////////////////////////////////////////// @@ -636,6 +612,33 @@ static std::shared_ptr> } return result; } + +/// @brief convert ClusterComm error into arango error code +int handleGeneralCommErrors(arangodb::ClusterCommResult const* res) { + // This function creates an error code from a ClusterCommResult, + // but only if it is a communication error. If the communication + // was successful and there was an HTTP error code, this function + // returns TRI_ERROR_NO_ERROR. + // If TRI_ERROR_NO_ERROR is returned, then the result was CL_COMM_RECEIVED + // and .answer can safely be inspected. + if (res->status == CL_COMM_TIMEOUT) { + // No reply, we give up: + return TRI_ERROR_CLUSTER_TIMEOUT; + } else if (res->status == CL_COMM_ERROR) { + return TRI_ERROR_CLUSTER_CONNECTION_LOST; + } else if (res->status == CL_COMM_BACKEND_UNAVAILABLE) { + if (res->result == nullptr) { + return TRI_ERROR_CLUSTER_CONNECTION_LOST; + } + if (!res->result->isComplete()) { + // there is no result + return TRI_ERROR_CLUSTER_CONNECTION_LOST; + } + return TRI_ERROR_CLUSTER_BACKEND_UNAVAILABLE; + } + + return TRI_ERROR_NO_ERROR; +} //////////////////////////////////////////////////////////////////////////////// /// @brief creates a copy of all HTTP headers to forward @@ -742,7 +745,7 @@ int revisionOnCoordinator(std::string const& dbname, // If we get here, the sharding attributes are not only _key, therefore // we have to contact everybody: - auto shards = collinfo->shardIds(); + std::shared_ptr shards = collinfo->shardIds(); CoordTransactionID coordTransactionID = TRI_NewTickServer(); std::unordered_map headers; @@ -810,7 +813,7 @@ int warmupOnCoordinator(std::string const& dbname, std::string const& cid) { // If we get here, the sharding attributes are not only _key, therefore // we have to contact everybody: - auto shards = collinfo->shardIds(); + std::shared_ptr shards = collinfo->shardIds(); CoordTransactionID coordTransactionID = TRI_NewTickServer(); std::unordered_map headers; @@ -855,7 +858,7 @@ int figuresOnCoordinator(std::string const& dbname, std::string const& collname, // If we get here, the sharding attributes are not only _key, therefore // we have to contact everybody: - auto shards = collinfo->shardIds(); + std::shared_ptr shards = collinfo->shardIds(); CoordTransactionID coordTransactionID = TRI_NewTickServer(); std::unordered_map headers; @@ -902,8 +905,7 @@ int figuresOnCoordinator(std::string const& dbname, std::string const& collname, /// @brief counts number of documents in a coordinator, by shard //////////////////////////////////////////////////////////////////////////////// -int countOnCoordinator(std::string const& dbname, std::string const& cname, - transaction::Methods const& trx, +int countOnCoordinator(transaction::Methods& trx, std::string const& cname, std::vector>& result) { // Set a few variables needed for our work: ClusterInfo* ci = ClusterInfo::instance(); @@ -915,17 +917,18 @@ int countOnCoordinator(std::string const& dbname, std::string const& cname, result.clear(); + std::string const& dbname = trx.vocbase().name(); // First determine the collection ID from the name: std::shared_ptr collinfo; collinfo = ci->getCollectionNT(dbname, cname); if (collinfo == nullptr) { return TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND; } - - auto shards = collinfo->shardIds(); + + std::shared_ptr shards = collinfo->shardIds(); std::vector requests; auto body = std::make_shared(); - for (auto const& p : *shards) { + for (std::pair> const& p : *shards) { requests.emplace_back("shard:" + p.first, arangodb::rest::RequestType::GET, "/_db/" + StringUtils::urlEncode(dbname) + "/_api/collection/" + @@ -983,7 +986,7 @@ int selectivityEstimatesOnCoordinator(std::string const& dbname, std::string con return TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND; } - auto shards = collinfo->shardIds(); + std::shared_ptr shards = collinfo->shardIds(); std::vector requests; std::string requestsUrl; auto body = std::make_shared(); @@ -1082,8 +1085,7 @@ int selectivityEstimatesOnCoordinator(std::string const& dbname, std::string con /// for their documents. //////////////////////////////////////////////////////////////////////////////// -Result createDocumentOnCoordinator(std::string const& dbname, std::string const& collname, - transaction::Methods const& trx, +Result createDocumentOnCoordinator(transaction::Methods& trx, std::string const& collname, arangodb::OperationOptions const& options, VPackSlice const& slice, arangodb::rest::ResponseCode& responseCode, @@ -1098,6 +1100,7 @@ Result createDocumentOnCoordinator(std::string const& dbname, std::string const& ClusterInfo* ci = ClusterInfo::instance(); TRI_ASSERT(ci != nullptr); + std::string const& dbname = trx.vocbase().name(); // First determine the collection ID from the name: std::shared_ptr collinfo; collinfo = ci->getCollectionNT(dbname, collname); @@ -1105,6 +1108,7 @@ Result createDocumentOnCoordinator(std::string const& dbname, std::string const& return TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND; } auto collid = std::to_string(collinfo->id()); + std::shared_ptr shards = collinfo->shardIds(); // create vars used in this function bool const useMultiple = slice.isArray(); // insert more than one document @@ -1224,9 +1228,8 @@ Result createDocumentOnCoordinator(std::string const& dbname, std::string const& /// @brief deletes a document in a coordinator //////////////////////////////////////////////////////////////////////////////// -int deleteDocumentOnCoordinator(std::string const& dbname, std::string const& collname, - arangodb::transaction::Methods const& trx, - VPackSlice const slice, +int deleteDocumentOnCoordinator(arangodb::transaction::Methods& trx, + std::string const& collname, VPackSlice const slice, arangodb::OperationOptions const& options, arangodb::rest::ResponseCode& responseCode, std::unordered_map& errorCounter, @@ -1239,6 +1242,7 @@ int deleteDocumentOnCoordinator(std::string const& dbname, std::string const& co return TRI_ERROR_SHUTTING_DOWN; } + std::string const& dbname = trx.vocbase().name(); // First determine the collection ID from the name: std::shared_ptr collinfo; collinfo = ci->getCollectionNT(dbname, collname); @@ -1247,6 +1251,7 @@ int deleteDocumentOnCoordinator(std::string const& dbname, std::string const& co } bool useDefaultSharding = collinfo->usesDefaultShardKeys(); auto collid = std::to_string(collinfo->id()); + std::shared_ptr shards = collinfo->shardIds(); bool useMultiple = slice.isArray(); std::string const baseUrl = @@ -1458,7 +1463,7 @@ int deleteDocumentOnCoordinator(std::string const& dbname, std::string const& co /// @brief truncate a cluster collection on a coordinator //////////////////////////////////////////////////////////////////////////////// -int truncateCollectionOnCoordinator(std::string const& dbname, std::string const& collname) { +Result truncateCollectionOnCoordinator(transaction::Methods& trx, std::string const& collname) { // Set a few variables needed for our work: ClusterInfo* ci = ClusterInfo::instance(); auto cc = ClusterComm::instance(); @@ -1467,6 +1472,7 @@ int truncateCollectionOnCoordinator(std::string const& dbname, std::string const return TRI_ERROR_SHUTTING_DOWN; } + std::string const& dbname = trx.vocbase().name(); // First determine the collection ID from the name: std::shared_ptr collinfo; collinfo = ci->getCollectionNT(dbname, collname); @@ -1476,7 +1482,8 @@ int truncateCollectionOnCoordinator(std::string const& dbname, std::string const // Some stuff to prepare cluster-intern requests: // We have to contact everybody: - auto shards = collinfo->shardIds(); + std::shared_ptr shards = collinfo->shardIds(); + CoordTransactionID coordTransactionID = TRI_NewTickServer(); std::unordered_map headers; for (auto const& p : *shards) { @@ -1494,6 +1501,11 @@ int truncateCollectionOnCoordinator(std::string const& dbname, std::string const if (res.status == CL_COMM_RECEIVED) { if (res.answer_code == arangodb::rest::ResponseCode::OK) { nrok++; + } else if (res.answer->payload().isObject()) { + VPackSlice answer = res.answer->payload(); + return Result(VelocyPackHelper::readNumericValue(answer, StaticStrings::ErrorNum, + TRI_ERROR_TRANSACTION_INTERNAL), + VelocyPackHelper::getStringValue(answer, StaticStrings::ErrorMessage, "")); } } } @@ -1502,15 +1514,14 @@ int truncateCollectionOnCoordinator(std::string const& dbname, std::string const if (nrok < shards->size()) { return TRI_ERROR_CLUSTER_COULD_NOT_TRUNCATE_COLLECTION; } - return TRI_ERROR_NO_ERROR; + return Result(); } //////////////////////////////////////////////////////////////////////////////// /// @brief get a document in a coordinator //////////////////////////////////////////////////////////////////////////////// -int getDocumentOnCoordinator(std::string const& dbname, std::string const& collname, - arangodb::transaction::Methods const& trx, +int getDocumentOnCoordinator(arangodb::transaction::Methods& trx, std::string const& collname, VPackSlice slice, OperationOptions const& options, arangodb::rest::ResponseCode& responseCode, std::unordered_map& errorCounter, @@ -1523,6 +1534,7 @@ int getDocumentOnCoordinator(std::string const& dbname, std::string const& colln return TRI_ERROR_SHUTTING_DOWN; } + std::string const& dbname = trx.vocbase().name(); // First determine the collection ID from the name: std::shared_ptr collinfo; collinfo = ci->getCollectionNT(dbname, collname); @@ -1531,6 +1543,7 @@ int getDocumentOnCoordinator(std::string const& dbname, std::string const& colln } auto collid = std::to_string(collinfo->id()); + std::shared_ptr shards = collinfo->shardIds(); // If _key is the one and only sharding attribute, we can do this quickly, // because we can easily determine which shard is responsible for the @@ -2057,9 +2070,8 @@ void fetchVerticesFromEngines( /// @brief get all edges on coordinator using a Traverser Filter //////////////////////////////////////////////////////////////////////////////// -int getFilteredEdgesOnCoordinator(std::string const& dbname, std::string const& collname, - arangodb::transaction::Methods const& trx, - std::string const& vertex, +int getFilteredEdgesOnCoordinator(arangodb::transaction::Methods const& trx, + std::string const& collname, std::string const& vertex, TRI_edge_direction_e const& direction, arangodb::rest::ResponseCode& responseCode, VPackBuilder& result) { @@ -2073,8 +2085,12 @@ int getFilteredEdgesOnCoordinator(std::string const& dbname, std::string const& return TRI_ERROR_SHUTTING_DOWN; } + std::string const& dbname = trx.vocbase().name(); // First determine the collection ID from the name: - std::shared_ptr collinfo = ci->getCollection(dbname, collname); + std::shared_ptr collinfo = ci->getCollectionNT(dbname, collname); + if (collinfo == nullptr) { + return TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND; + } std::shared_ptr>> shards; if (collinfo->isSmart() && collinfo->type() == TRI_COL_TYPE_EDGE) { @@ -2181,8 +2197,7 @@ int getFilteredEdgesOnCoordinator(std::string const& dbname, std::string const& //////////////////////////////////////////////////////////////////////////////// int modifyDocumentOnCoordinator( - std::string const& dbname, std::string const& collname, - arangodb::transaction::Methods const& trx, VPackSlice const& slice, + transaction::Methods& trx, std::string const& collname, VPackSlice const& slice, arangodb::OperationOptions const& options, bool isPatch, std::unique_ptr>& headers, arangodb::rest::ResponseCode& responseCode, std::unordered_map& errorCounter, @@ -2195,9 +2210,11 @@ int modifyDocumentOnCoordinator( return TRI_ERROR_SHUTTING_DOWN; } + std::string const& dbname = trx.vocbase().name(); // First determine the collection ID from the name: std::shared_ptr collinfo = ci->getCollection(dbname, collname); auto collid = std::to_string(collinfo->id()); + std::shared_ptr shards = collinfo->shardIds(); // We have a fast path and a slow path. The fast path only asks one shard // to do the job and the slow path asks them all and expects to get @@ -2482,7 +2499,7 @@ int flushWalOnAllDBServers(bool waitForSync, bool waitForCollector, double maxWa if (resSlice.isObject()) { int code = arangodb::basics::VelocyPackHelper::getNumericValue( resSlice, "errorNum", TRI_ERROR_INTERNAL); - + if (code != TRI_ERROR_NO_ERROR) { globalErrorCode = code; } diff --git a/arangod/Cluster/ClusterMethods.h b/arangod/Cluster/ClusterMethods.h index 604064d2dd..4082c6fa08 100644 --- a/arangod/Cluster/ClusterMethods.h +++ b/arangod/Cluster/ClusterMethods.h @@ -40,12 +40,16 @@ namespace velocypack { template class Buffer; class Builder; -class Slice; } // namespace velocypack +struct ClusterCommResult; struct OperationOptions; +class TransactionState; struct TtlStatistics; +/// @brief convert ClusterComm error into arango error code +int handleGeneralCommErrors(arangodb::ClusterCommResult const* res); + //////////////////////////////////////////////////////////////////////////////// /// @brief creates a copy of all HTTP headers to forward //////////////////////////////////////////////////////////////////////////////// @@ -84,8 +88,7 @@ int figuresOnCoordinator(std::string const& dbname, std::string const& collname, /// @brief counts number of documents in a coordinator, by shard //////////////////////////////////////////////////////////////////////////////// -int countOnCoordinator(std::string const& dbname, std::string const& collname, - transaction::Methods const& trx, +int countOnCoordinator(transaction::Methods& trx, std::string const& collname, std::vector>& result); //////////////////////////////////////////////////////////////////////////////// @@ -99,8 +102,8 @@ int selectivityEstimatesOnCoordinator(std::string const& dbname, std::string con /// @brief creates a document in a coordinator //////////////////////////////////////////////////////////////////////////////// -Result createDocumentOnCoordinator(std::string const& dbname, std::string const& collname, - transaction::Methods const& trx, +Result createDocumentOnCoordinator(transaction::Methods& trx, + std::string const& collname, OperationOptions const& options, arangodb::velocypack::Slice const& slice, arangodb::rest::ResponseCode& responseCode, @@ -111,8 +114,7 @@ Result createDocumentOnCoordinator(std::string const& dbname, std::string const& /// @brief delete a document in a coordinator //////////////////////////////////////////////////////////////////////////////// -int deleteDocumentOnCoordinator(std::string const& dbname, std::string const& collname, - transaction::Methods const& trx, +int deleteDocumentOnCoordinator(transaction::Methods& trx, std::string const& collname, VPackSlice const slice, OperationOptions const& options, arangodb::rest::ResponseCode& responseCode, std::unordered_map& errorCounters, @@ -122,9 +124,8 @@ int deleteDocumentOnCoordinator(std::string const& dbname, std::string const& co /// @brief get a document in a coordinator //////////////////////////////////////////////////////////////////////////////// -int getDocumentOnCoordinator(std::string const& dbname, std::string const& collname, - transaction::Methods const& trx, VPackSlice slice, - OperationOptions const& options, +int getDocumentOnCoordinator(transaction::Methods& trx, std::string const& collname, + VPackSlice slice, OperationOptions const& options, arangodb::rest::ResponseCode& responseCode, std::unordered_map& errorCounter, std::shared_ptr& resultBody); @@ -206,8 +207,8 @@ void fetchVerticesFromEngines( /// Also returns the result in VelocyPack //////////////////////////////////////////////////////////////////////////////// -int getFilteredEdgesOnCoordinator(std::string const& dbname, std::string const& collname, - transaction::Methods const& trx, std::string const& vertex, +int getFilteredEdgesOnCoordinator(transaction::Methods const& trx, + std::string const& collname, std::string const& vertex, TRI_edge_direction_e const& direction, arangodb::rest::ResponseCode& responseCode, arangodb::velocypack::Builder& result); @@ -217,8 +218,8 @@ int getFilteredEdgesOnCoordinator(std::string const& dbname, std::string const& //////////////////////////////////////////////////////////////////////////////// int modifyDocumentOnCoordinator( - std::string const& dbname, std::string const& collname, - transaction::Methods const& trx, arangodb::velocypack::Slice const& slice, + transaction::Methods& trx, std::string const& collname, + arangodb::velocypack::Slice const& slice, OperationOptions const& options, bool isPatch, std::unique_ptr>& headers, arangodb::rest::ResponseCode& responseCode, std::unordered_map& errorCounter, @@ -228,7 +229,8 @@ int modifyDocumentOnCoordinator( /// @brief truncate a cluster collection on a coordinator //////////////////////////////////////////////////////////////////////////////// -int truncateCollectionOnCoordinator(std::string const& dbname, std::string const& collname); +Result truncateCollectionOnCoordinator(transaction::Methods& trx, + std::string const& collname); //////////////////////////////////////////////////////////////////////////////// /// @brief flush Wal on all DBservers @@ -267,7 +269,7 @@ class ClusterMethods { TRI_col_type_e collectionType, TRI_vocbase_t& vocbase, arangodb::velocypack::Slice parameters, bool ignoreDistributeShardsLikeErrors, bool waitForSyncReplication, bool enforceReplicationFactor); - + private: //////////////////////////////////////////////////////////////////////////////// /// @brief Persist collection in Agency and trigger shard creation process diff --git a/arangod/Cluster/DBServerAgencySync.cpp b/arangod/Cluster/DBServerAgencySync.cpp index 5d8e965123..8f4ae5477a 100644 --- a/arangod/Cluster/DBServerAgencySync.cpp +++ b/arangod/Cluster/DBServerAgencySync.cpp @@ -90,7 +90,7 @@ Result DBServerAgencySync::getLocalCollections(VPackBuilder& collections) { collections.add(VPackValue(colname)); VPackObjectBuilder col(&collections); - collection->properties(collections, true, false); + collection->properties(collections, /*detailed*/true, false); auto const& folls = collection->followers(); std::string const theLeader = folls->getLeader(); diff --git a/arangod/Cluster/FollowerInfo.cpp b/arangod/Cluster/FollowerInfo.cpp index 985cc1b540..fed8d6fb60 100644 --- a/arangod/Cluster/FollowerInfo.cpp +++ b/arangod/Cluster/FollowerInfo.cpp @@ -298,3 +298,17 @@ void FollowerInfo::clear() { auto v = std::make_shared>(); _followers = v; // will cast to std::vector const } + +////////////////////////////////////////////////////////////////////////////// +/// @brief check whether the given server is a follower +////////////////////////////////////////////////////////////////////////////// + +bool FollowerInfo::contains(ServerID const& sid) const { + MUTEX_LOCKER(locker, _mutex); + for (auto const& s : *_followers) { + if (s == sid) { + return true; + } + } + return false; +} diff --git a/arangod/Cluster/FollowerInfo.h b/arangod/Cluster/FollowerInfo.h index 1b2aa103e5..4321b63da0 100644 --- a/arangod/Cluster/FollowerInfo.h +++ b/arangod/Cluster/FollowerInfo.h @@ -76,6 +76,12 @@ class FollowerInfo { void clear(); + ////////////////////////////////////////////////////////////////////////////// + /// @brief check whether the given server is a follower + ////////////////////////////////////////////////////////////////////////////// + + bool contains(ServerID const& s) const; + ////////////////////////////////////////////////////////////////////////////// /// @brief set leadership ////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Cluster/ServerState.cpp b/arangod/Cluster/ServerState.cpp index 1adba1f8e1..0fcfe1df89 100644 --- a/arangod/Cluster/ServerState.cpp +++ b/arangod/Cluster/ServerState.cpp @@ -143,7 +143,7 @@ std::string ServerState::roleToString(ServerState::RoleEnum role) { return "UNDEFINED"; case ROLE_SINGLE: return "SINGLE"; - case ROLE_PRIMARY: + case ROLE_DBSERVER: return "PRIMARY"; case ROLE_COORDINATOR: return "COORDINATOR"; @@ -161,7 +161,7 @@ std::string ServerState::roleToShortString(ServerState::RoleEnum role) { return "NONE"; case ROLE_SINGLE: return "SNGL"; - case ROLE_PRIMARY: + case ROLE_DBSERVER: return "PRMR"; case ROLE_COORDINATOR: return "CRDN"; @@ -184,7 +184,7 @@ ServerState::RoleEnum ServerState::stringToRole(std::string const& value) { // note: DBSERVER is an alias for PRIMARY // internally and in all API values returned we will still use PRIMARY // for compatibility reasons - return ROLE_PRIMARY; + return ROLE_DBSERVER; } else if (value == "COORDINATOR") { return ROLE_COORDINATOR; } else if (value == "AGENT") { @@ -396,7 +396,7 @@ std::string ServerState::roleToAgencyListKey(ServerState::RoleEnum role) { std::string ServerState::roleToAgencyKey(ServerState::RoleEnum role) { switch (role) { - case ROLE_PRIMARY: + case ROLE_DBSERVER: return "DBServer"; case ROLE_COORDINATOR: return "Coordinator"; @@ -768,7 +768,7 @@ void ServerState::setState(StateEnum state) { } auto role = getRole(); - if (role == ROLE_PRIMARY) { + if (role == ROLE_DBSERVER) { result = checkPrimaryState(state); } else if (role == ROLE_COORDINATOR) { result = checkCoordinatorState(state); diff --git a/arangod/Cluster/ServerState.h b/arangod/Cluster/ServerState.h index 9f52a1d20e..f7f54c664e 100644 --- a/arangod/Cluster/ServerState.h +++ b/arangod/Cluster/ServerState.h @@ -38,7 +38,7 @@ class ServerState { enum RoleEnum : int { ROLE_UNDEFINED = 0, // initial value ROLE_SINGLE, // is set when cluster feature is off - ROLE_PRIMARY, + ROLE_DBSERVER, ROLE_COORDINATOR, ROLE_AGENT }; @@ -146,13 +146,13 @@ class ServerState { /// running in cluster mode. static bool isDBServer(ServerState::RoleEnum role) { TRI_ASSERT(role != ServerState::ROLE_UNDEFINED); - return (role == ServerState::ROLE_PRIMARY); + return (role == ServerState::ROLE_DBSERVER); } /// @brief whether or not the role is a cluster-related role static bool isClusterRole(ServerState::RoleEnum role) { TRI_ASSERT(role != ServerState::ROLE_UNDEFINED); - return (role == ServerState::ROLE_PRIMARY || role == ServerState::ROLE_COORDINATOR); + return (role == ServerState::ROLE_DBSERVER || role == ServerState::ROLE_COORDINATOR); } /// @brief whether or not the role is a cluster-related role diff --git a/arangod/ClusterEngine/CMakeLists.txt b/arangod/ClusterEngine/CMakeLists.txt index 3b6b0f8299..4d0aa0e953 100644 --- a/arangod/ClusterEngine/CMakeLists.txt +++ b/arangod/ClusterEngine/CMakeLists.txt @@ -15,7 +15,6 @@ set(CLUSTER_ENGINE_SOURCES ClusterEngine/ClusterRestWalHandler.cpp ClusterEngine/ClusterSelectivityEstimates.cpp ClusterEngine/ClusterTransactionCollection.cpp - ClusterEngine/ClusterTransactionContextData.h ClusterEngine/ClusterTransactionState.cpp ClusterEngine/ClusterV8Functions.cpp ClusterEngine/MMFilesMethods.cpp diff --git a/arangod/ClusterEngine/ClusterEngine.cpp b/arangod/ClusterEngine/ClusterEngine.cpp index 1aa4b0936d..4926309e7e 100644 --- a/arangod/ClusterEngine/ClusterEngine.cpp +++ b/arangod/ClusterEngine/ClusterEngine.cpp @@ -36,8 +36,6 @@ #include "ClusterEngine/ClusterIndexFactory.h" #include "ClusterEngine/ClusterRestHandlers.h" #include "ClusterEngine/ClusterTransactionCollection.h" -#include "ClusterEngine/ClusterTransactionContextData.h" -#include "ClusterEngine/ClusterTransactionManager.h" #include "ClusterEngine/ClusterTransactionState.h" #include "ClusterEngine/ClusterV8Functions.h" #include "GeneralServer/RestHandlerFactory.h" @@ -53,6 +51,8 @@ #include "RocksDBEngine/RocksDBEngine.h" #include "RocksDBEngine/RocksDBOptimizerRules.h" #include "Transaction/Context.h" +#include "Transaction/ContextData.h" +#include "Transaction/Manager.h" #include "Transaction/Options.h" #include "VocBase/LogicalView.h" #include "VocBase/ticks.h" @@ -126,17 +126,18 @@ void ClusterEngine::start() { TRI_ASSERT(ServerState::instance()->isCoordinator()); } -std::unique_ptr ClusterEngine::createTransactionManager() { - return std::unique_ptr(new ClusterTransactionManager()); +std::unique_ptr ClusterEngine::createTransactionManager() { + return std::make_unique(/*keepData*/ false); } std::unique_ptr ClusterEngine::createTransactionContextData() { - return std::unique_ptr(new ClusterTransactionContextData()); + return std::unique_ptr(); // not used by coordinator } -std::unique_ptr ClusterEngine::createTransactionState( - TRI_vocbase_t& vocbase, transaction::Options const& options) { - return std::make_unique(vocbase, TRI_NewTickServer(), options); +std::unique_ptr ClusterEngine::createTransactionState(TRI_vocbase_t& vocbase, + TRI_voc_tid_t tid, + transaction::Options const& options) { + return std::make_unique(vocbase, tid, options); } std::unique_ptr ClusterEngine::createTransactionCollection( @@ -361,4 +362,4 @@ std::unique_ptr ClusterEngine::openExistingDatabase( // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/arangod/ClusterEngine/ClusterEngine.h b/arangod/ClusterEngine/ClusterEngine.h index b06ebd0734..7b4641dcc0 100644 --- a/arangod/ClusterEngine/ClusterEngine.h +++ b/arangod/ClusterEngine/ClusterEngine.h @@ -34,19 +34,6 @@ #include namespace arangodb { -class PhysicalCollection; -class PhysicalView; -class TransactionCollection; -class TransactionState; - -namespace rest { -class RestHandlerFactory; -} - -namespace transaction { -class ContextData; -struct Options; -} // namespace transaction class ClusterEngine final : public StorageEngine { public: @@ -82,9 +69,9 @@ class ClusterEngine final : public StorageEngine { bool supportsDfdb() const override { return false; } bool useRawDocumentPointers() override { return false; } - std::unique_ptr createTransactionManager() override; + std::unique_ptr createTransactionManager() override; std::unique_ptr createTransactionContextData() override; - std::unique_ptr createTransactionState(TRI_vocbase_t& vocbase, + std::unique_ptr createTransactionState(TRI_vocbase_t& vocbase, TRI_voc_tid_t tid, transaction::Options const& options) override; std::unique_ptr createTransactionCollection( TransactionState& state, TRI_voc_cid_t cid, AccessMode::Type accessType, @@ -272,4 +259,4 @@ class ClusterEngine final : public StorageEngine { } // namespace arangodb -#endif \ No newline at end of file +#endif diff --git a/arangod/ClusterEngine/ClusterRestWalHandler.cpp b/arangod/ClusterEngine/ClusterRestWalHandler.cpp index f23a1f7546..af688db7a4 100644 --- a/arangod/ClusterEngine/ClusterRestWalHandler.cpp +++ b/arangod/ClusterEngine/ClusterRestWalHandler.cpp @@ -20,15 +20,15 @@ /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// -#include "ClusterRestWalHandler.h" #include "Basics/StringUtils.h" #include "Basics/VelocyPackHelper.h" #include "Cluster/ClusterMethods.h" #include "Cluster/ServerState.h" -#include "RestServer/TransactionManagerFeature.h" +#include "ClusterRestWalHandler.h" #include "StorageEngine/EngineSelectorFeature.h" #include "StorageEngine/StorageEngine.h" -#include "StorageEngine/TransactionManager.h" +#include "Transaction/Manager.h" +#include "Transaction/ManagerFeature.h" #include "Utils/ExecContext.h" #include @@ -152,7 +152,7 @@ void ClusterRestWalHandler::flush() { } void ClusterRestWalHandler::transactions() { - TransactionManager* mngr = TransactionManagerFeature::manager(); + auto* mngr = transaction::ManagerFeature::manager(); VPackBuilder builder; builder.openObject(); builder.add("runningTransactions", VPackValue(mngr->getActiveTransactionCount())); diff --git a/arangod/ClusterEngine/ClusterTransactionCollection.cpp b/arangod/ClusterEngine/ClusterTransactionCollection.cpp index d51b0366bc..54375ca686 100644 --- a/arangod/ClusterEngine/ClusterTransactionCollection.cpp +++ b/arangod/ClusterEngine/ClusterTransactionCollection.cpp @@ -20,9 +20,9 @@ /// @author Simon Grätzer //////////////////////////////////////////////////////////////////////////////// -#include "ClusterTransactionCollection.h" #include "Basics/Exceptions.h" #include "Cluster/ClusterInfo.h" +#include "ClusterTransactionCollection.h" #include "Logger/Logger.h" #include "StorageEngine/TransactionState.h" #include "Transaction/Hints.h" @@ -37,8 +37,7 @@ ClusterTransactionCollection::ClusterTransactionCollection(TransactionState* trx int nestingLevel) : TransactionCollection(trx, cid, accessType), _lockType(AccessMode::Type::NONE), - _nestingLevel(nestingLevel), - _usageLocked(false) {} + _nestingLevel(nestingLevel) {} ClusterTransactionCollection::~ClusterTransactionCollection() {} @@ -107,7 +106,6 @@ int ClusterTransactionCollection::use(int nestingLevel) { !_transaction->hasHint(transaction::Hints::Hint::NO_USAGE_LOCK)) { // use and usage-lock LOG_TRX(_transaction, nestingLevel) << "using collection " << _cid; - _usageLocked = true; } } @@ -143,11 +141,6 @@ void ClusterTransactionCollection::release() { if (_collection != nullptr) { // unuse collection, remove usage-lock LOG_TRX(_transaction, 0) << "unusing collection " << _cid; - - if (_usageLocked) { - _transaction->vocbase().releaseCollection(_collection.get()); - _usageLocked = false; - } _collection = nullptr; } } @@ -169,12 +162,6 @@ int ClusterTransactionCollection::doLock(AccessMode::Type type, int nestingLevel TRI_ASSERT(_collection != nullptr); - std::string collName(_collection->name()); - if (_transaction->isLockedShard(collName)) { - // do not lock by command - return TRI_ERROR_NO_ERROR; - } - TRI_ASSERT(!isLocked()); TRI_ASSERT(_collection); @@ -200,14 +187,7 @@ int ClusterTransactionCollection::doUnlock(AccessMode::Type type, int nestingLev TRI_ASSERT(_collection != nullptr); - std::string collName(_collection->name()); - if (_transaction->isLockedShard(collName)) { - // do not lock by command - return TRI_ERROR_NO_ERROR; - } - TRI_ASSERT(isLocked()); - if (_nestingLevel < nestingLevel) { // only process our own collections return TRI_ERROR_NO_ERROR; diff --git a/arangod/ClusterEngine/ClusterTransactionCollection.h b/arangod/ClusterEngine/ClusterTransactionCollection.h index e0bb3c8578..e02560a09e 100644 --- a/arangod/ClusterEngine/ClusterTransactionCollection.h +++ b/arangod/ClusterEngine/ClusterTransactionCollection.h @@ -65,7 +65,6 @@ class ClusterTransactionCollection final : public TransactionCollection { private: AccessMode::Type _lockType; // collection lock type, used for exclusive locks int _nestingLevel; // the transaction level that added this collection - bool _usageLocked; // is this already locked }; } // namespace arangodb diff --git a/arangod/ClusterEngine/ClusterTransactionContextData.h b/arangod/ClusterEngine/ClusterTransactionContextData.h deleted file mode 100644 index 8163d4dd90..0000000000 --- a/arangod/ClusterEngine/ClusterTransactionContextData.h +++ /dev/null @@ -1,49 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// DISCLAIMER -/// -/// Copyright 2018 ArangoDB GmbH, Cologne, Germany -/// -/// Licensed under the Apache License, Version 2.0 (the "License"); -/// you may not use this file except in compliance with the License. -/// You may obtain a copy of the License at -/// -/// http://www.apache.org/licenses/LICENSE-2.0 -/// -/// Unless required by applicable law or agreed to in writing, software -/// distributed under the License is distributed on an "AS IS" BASIS, -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -/// See the License for the specific language governing permissions and -/// limitations under the License. -/// -/// Copyright holder is ArangoDB GmbH, Cologne, Germany -/// -/// @author Simon Grätzer -//////////////////////////////////////////////////////////////////////////////// - -#ifndef ARANGOD_CLUSTER_CLUSTER_TRANSACTION_CONTEXT_DATA_H -#define ARANGOD_CLUSTER_CLUSTER_TRANSACTION_CONTEXT_DATA_H 1 - -#include "Basics/Common.h" -#include "Transaction/ContextData.h" -#include "VocBase/voc-types.h" - -namespace arangodb { -class LogicalCollection; - -/// @brief transaction type -class ClusterTransactionContextData final : public transaction::ContextData { - public: - ClusterTransactionContextData() = default; - ~ClusterTransactionContextData() = default; - - /// @brief pin data for the collection - /// there is nothing to do for the RocksDB engine - void pinData(arangodb::LogicalCollection*) override {} - - /// @brief whether or not the data for the collection is pinned - /// note that this is always true in RocksDB - bool isPinned(TRI_voc_cid_t) const override { return true; } -}; -} // namespace arangodb - -#endif diff --git a/arangod/ClusterEngine/ClusterTransactionManager.h b/arangod/ClusterEngine/ClusterTransactionManager.h deleted file mode 100644 index d344b2e7c2..0000000000 --- a/arangod/ClusterEngine/ClusterTransactionManager.h +++ /dev/null @@ -1,74 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// DISCLAIMER -/// -/// Copyright 2018 ArangoDB GmbH, Cologne, Germany -/// -/// Licensed under the Apache License, Version 2.0 (the "License"); -/// you may not use this file except in compliance with the License. -/// You may obtain a copy of the License at -/// -/// http://www.apache.org/licenses/LICENSE-2.0 -/// -/// Unless required by applicable law or agreed to in writing, software -/// distributed under the License is distributed on an "AS IS" BASIS, -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -/// See the License for the specific language governing permissions and -/// limitations under the License. -/// -/// Copyright holder is ArangoDB GmbH, Cologne, Germany -/// -/// @author Simon Grätzer -//////////////////////////////////////////////////////////////////////////////// - -#ifndef ARANGOD_CLUSTER_CLUSTER_TRANSACTION_MANAGER_H -#define ARANGOD_CLUSTER_CLUSTER_TRANSACTION_MANAGER_H 1 - -#include "Basics/Common.h" -#include "Basics/ReadWriteLock.h" -#include "StorageEngine/TransactionManager.h" -#include "VocBase/voc-types.h" - -namespace arangodb { - -class ClusterTransactionManager final : public TransactionManager { - public: - ClusterTransactionManager() : TransactionManager(), _nrRunning(0) {} - ~ClusterTransactionManager() {} - - // register a list of failed transactions - void registerFailedTransactions(std::unordered_set const& failedTransactions) override { - } - - // unregister a list of failed transactions - void unregisterFailedTransactions(std::unordered_set const& failedTransactions) override { - } - - // return the set of failed transactions - std::unordered_set getFailedTransactions() override { - return std::unordered_set(); - } - - // register a transaction - void registerTransaction(TRI_voc_tid_t transactionId, - std::unique_ptr data) override { - TRI_ASSERT(data == nullptr); - ++_nrRunning; - } - - // unregister a transaction - void unregisterTransaction(TRI_voc_tid_t transactionId, bool markAsFailed) override { - --_nrRunning; - } - - // iterate all the active transactions - void iterateActiveTransactions( - std::function const& callback) override {} - - uint64_t getActiveTransactionCount() override { return _nrRunning; } - - private: - std::atomic _nrRunning; -}; -} // namespace arangodb - -#endif diff --git a/arangod/ClusterEngine/ClusterTransactionState.cpp b/arangod/ClusterEngine/ClusterTransactionState.cpp index a9cc30b003..7655838051 100644 --- a/arangod/ClusterEngine/ClusterTransactionState.cpp +++ b/arangod/ClusterEngine/ClusterTransactionState.cpp @@ -21,12 +21,15 @@ //////////////////////////////////////////////////////////////////////////////// #include "ClusterTransactionState.h" + #include "Basics/Exceptions.h" #include "Logger/Logger.h" -#include "RestServer/TransactionManagerFeature.h" -#include "StorageEngine/StorageEngine.h" +#include "Cluster/ClusterMethods.h" +#include "ClusterEngine/ClusterEngine.h" +#include "StorageEngine/EngineSelectorFeature.h" #include "StorageEngine/TransactionCollection.h" -#include "StorageEngine/TransactionManager.h" +#include "Transaction/Manager.h" +#include "Transaction/ManagerFeature.h" #include "Transaction/Methods.h" #include "Utils/ExecContext.h" #include "VocBase/LogicalCollection.h" @@ -34,52 +37,46 @@ using namespace arangodb; -// for the Cluster engine we do not need any additional data -struct ClusterTransactionData final : public TransactionData {}; - /// @brief transaction type -ClusterTransactionState::ClusterTransactionState(TRI_vocbase_t& vocbase, TRI_voc_tid_t tid, +ClusterTransactionState::ClusterTransactionState(TRI_vocbase_t& vocbase, + TRI_voc_tid_t tid, transaction::Options const& options) : TransactionState(vocbase, tid, options) {} -/// @brief free a transaction container -ClusterTransactionState::~ClusterTransactionState() {} - /// @brief start a transaction Result ClusterTransactionState::beginTransaction(transaction::Hints hints) { - LOG_TRX(this, _nestingLevel) + LOG_TRX(this, nestingLevel()) << "beginning " << AccessMode::typeString(_type) << " transaction"; TRI_ASSERT(!hasHint(transaction::Hints::Hint::NO_USAGE_LOCK) || !AccessMode::isWriteOrExclusive(_type)); - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { // set hints _hints = hints; } - Result result = useCollections(_nestingLevel); + Result result = useCollections(nestingLevel()); if (result.ok()) { // all valid - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { updateStatus(transaction::Status::RUNNING); } } else { // something is wrong - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { updateStatus(transaction::Status::ABORTED); } // free what we have got so far - unuseCollections(_nestingLevel); + unuseCollections(nestingLevel()); return result; } - if (_nestingLevel == 0) { - // register a protector (intentionally empty) - TransactionManagerFeature::manager()->registerTransaction( - _id, std::unique_ptr()); + if (nestingLevel() == 0) { + transaction::ManagerFeature::manager()->registerTransaction(id(), nullptr); + setRegistered(); } else { TRI_ASSERT(_status == transaction::Status::RUNNING); } @@ -89,7 +86,7 @@ Result ClusterTransactionState::beginTransaction(transaction::Hints hints) { /// @brief commit a transaction Result ClusterTransactionState::commitTransaction(transaction::Methods* activeTrx) { - LOG_TRX(this, _nestingLevel) + LOG_TRX(this, nestingLevel()) << "committing " << AccessMode::typeString(_type) << " transaction"; TRI_ASSERT(_status == transaction::Status::RUNNING); @@ -98,28 +95,23 @@ Result ClusterTransactionState::commitTransaction(transaction::Methods* activeTr } arangodb::Result res; - if (_nestingLevel == 0) { - if (true) { - updateStatus(transaction::Status::COMMITTED); - // cleanupTransaction(); // deletes trx - } else { - abortTransaction(activeTrx); // deletes trx - } + if (nestingLevel() == 0) { + updateStatus(transaction::Status::COMMITTED); } - unuseCollections(_nestingLevel); + unuseCollections(nestingLevel()); return res; } /// @brief abort and rollback a transaction Result ClusterTransactionState::abortTransaction(transaction::Methods* activeTrx) { - LOG_TRX(this, _nestingLevel) << "aborting " << AccessMode::typeString(_type) << " transaction"; + LOG_TRX(this, nestingLevel()) << "aborting " << AccessMode::typeString(_type) << " transaction"; TRI_ASSERT(_status == transaction::Status::RUNNING); - Result result; - if (_nestingLevel == 0) { + Result res; + if (nestingLevel() == 0) { updateStatus(transaction::Status::ABORTED); } - unuseCollections(_nestingLevel); - return result; + unuseCollections(nestingLevel()); + return res; } diff --git a/arangod/ClusterEngine/ClusterTransactionState.h b/arangod/ClusterEngine/ClusterTransactionState.h index 4784c42ce3..449838e653 100644 --- a/arangod/ClusterEngine/ClusterTransactionState.h +++ b/arangod/ClusterEngine/ClusterTransactionState.h @@ -23,35 +23,16 @@ #ifndef ARANGOD_CLUSTER_CLUSTER_TRANSACTION_STATE_H #define ARANGOD_CLUSTER_CLUSTER_TRANSACTION_STATE_H 1 -#include "Basics/Common.h" -#include "Basics/SmallVector.h" #include "StorageEngine/TransactionState.h" -#include "Transaction/Hints.h" -#include "Transaction/Methods.h" -#include "VocBase/AccessMode.h" -#include "VocBase/voc-types.h" - -struct TRI_vocbase_t; namespace arangodb { -class LogicalCollection; - -namespace transaction { - -class Methods; -struct Options; - -} // namespace transaction - -class TransactionCollection; - /// @brief transaction type class ClusterTransactionState final : public TransactionState { public: ClusterTransactionState(TRI_vocbase_t& vocbase, TRI_voc_tid_t tid, transaction::Options const& options); - ~ClusterTransactionState(); + ~ClusterTransactionState() {} /// @brief begin a transaction Result beginTransaction(transaction::Hints hints) override; diff --git a/arangod/Graph/EdgeCollectionInfo.cpp b/arangod/Graph/EdgeCollectionInfo.cpp index f4142d07d1..daa5b25b2d 100644 --- a/arangod/Graph/EdgeCollectionInfo.cpp +++ b/arangod/Graph/EdgeCollectionInfo.cpp @@ -36,7 +36,6 @@ EdgeCollectionInfo::EdgeCollectionInfo(transaction::Methods* trx, _collectionName(collectionName), _searchBuilder(), _weightAttribute(weightAttribute), - _defaultWeight(defaultWeight), _dir(direction) { TRI_ASSERT(_dir == TRI_EDGE_OUT || _dir == TRI_EDGE_IN); @@ -85,81 +84,6 @@ std::unique_ptr EdgeCollectionInfo::getEdges( _forwardIndexId, cond, _searchBuilder.getVariable(), opts)); } -//////////////////////////////////////////////////////////////////////////////// -/// @brief Get edges for the given direction and start vertex. On Coordinator. -//////////////////////////////////////////////////////////////////////////////// - -int EdgeCollectionInfo::getEdgesCoordinator(VPackSlice const& vertexId, VPackBuilder& result) { - TRI_ASSERT(result.isEmpty()); - arangodb::rest::ResponseCode responseCode; - - result.openObject(); - - int res = getFilteredEdgesOnCoordinator(_trx->vocbase().name(), _collectionName, - *_trx, vertexId.copyString(), _dir, - responseCode, result); - - result.close(); - - return res; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Get edges for the given direction and start vertex. Reverse version -//////////////////////////////////////////////////////////////////////////////// - -std::unique_ptr EdgeCollectionInfo::getReverseEdges( - std::string const& vertexId) { - _searchBuilder.setVertexId(vertexId); - arangodb::aql::AstNode const* cond; - if (_dir == TRI_EDGE_OUT) { - cond = _searchBuilder.getInboundCondition(); - } else { - cond = _searchBuilder.getOutboundCondition(); - } - - IndexIteratorOptions opts; - return std::make_unique(_trx->indexScanForCondition( - _backwardIndexId, cond, _searchBuilder.getVariable(), opts)); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Get edges for the given direction and start vertex. Reverse version -/// on Coordinator. -//////////////////////////////////////////////////////////////////////////////// - -int EdgeCollectionInfo::getReverseEdgesCoordinator(VPackSlice const& vertexId, - VPackBuilder& result) { - TRI_ASSERT(result.isEmpty()); - arangodb::rest::ResponseCode responseCode; - - result.openObject(); - - TRI_edge_direction_e dir = TRI_EDGE_OUT; - - if (_dir == TRI_EDGE_OUT) { - dir = TRI_EDGE_IN; - } - - int res = getFilteredEdgesOnCoordinator(_trx->vocbase().name(), _collectionName, - *_trx, vertexId.copyString(), dir, - responseCode, result); - - result.close(); - - return res; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Compute the weight of an edge -//////////////////////////////////////////////////////////////////////////////// - -double EdgeCollectionInfo::weightEdge(VPackSlice const edge) { - TRI_ASSERT(!_weightAttribute.empty()); - return arangodb::basics::VelocyPackHelper::getNumericValue( - edge, _weightAttribute.c_str(), _defaultWeight); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief Return name of the wrapped collection //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Graph/EdgeCollectionInfo.h b/arangod/Graph/EdgeCollectionInfo.h index 5b24f9bef9..7d46bb937a 100644 --- a/arangod/Graph/EdgeCollectionInfo.h +++ b/arangod/Graph/EdgeCollectionInfo.h @@ -66,8 +66,6 @@ class EdgeCollectionInfo { std::string _weightAttribute; - double _defaultWeight; - TRI_edge_direction_e _dir; public: @@ -81,28 +79,6 @@ class EdgeCollectionInfo { std::unique_ptr getEdges(std::string const&); - //////////////////////////////////////////////////////////////////////////////// - /// @brief Get edges for the given direction and start vertex. On Coordinator. - //////////////////////////////////////////////////////////////////////////////// - - int getEdgesCoordinator(arangodb::velocypack::Slice const&, arangodb::velocypack::Builder&); - - //////////////////////////////////////////////////////////////////////////////// - /// @brief Get edges for the given direction and start vertex. Reverse version - //////////////////////////////////////////////////////////////////////////////// - - std::unique_ptr getReverseEdges(std::string const&); - - //////////////////////////////////////////////////////////////////////////////// - /// @brief Get edges for the given direction and start vertex. Reverse version - /// on Coordinator. - //////////////////////////////////////////////////////////////////////////////// - - int getReverseEdgesCoordinator(arangodb::velocypack::Slice const&, - arangodb::velocypack::Builder&); - - double weightEdge(arangodb::velocypack::Slice const); - transaction::Methods* trx() const { return _trx; } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/IResearch/IResearchViewNode.cpp b/arangod/IResearch/IResearchViewNode.cpp index 374309162e..7b8fc7fe85 100644 --- a/arangod/IResearch/IResearchViewNode.cpp +++ b/arangod/IResearch/IResearchViewNode.cpp @@ -39,8 +39,10 @@ #include "IResearchViewBlock.h" #include "IResearchViewCoordinator.h" #include "StorageEngine/TransactionState.h" +#include "Utils/CollectionNameResolver.h" #include "VocBase/LogicalCollection.h" -#include "velocypack/Iterator.h" + +#include namespace { diff --git a/arangod/MMFiles/CMakeLists.txt b/arangod/MMFiles/CMakeLists.txt index c3a66eee1a..d882502a5a 100644 --- a/arangod/MMFiles/CMakeLists.txt +++ b/arangod/MMFiles/CMakeLists.txt @@ -46,7 +46,6 @@ set(MMFILES_SOURCES MMFiles/MMFilesSynchronizerThread.cpp MMFiles/MMFilesTransactionCollection.cpp MMFiles/MMFilesTransactionContextData.cpp - MMFiles/MMFilesTransactionManager.cpp MMFiles/MMFilesTransactionState.cpp MMFiles/MMFilesTtlIndex.cpp MMFiles/MMFilesV8Functions.cpp diff --git a/arangod/MMFiles/MMFilesCollectorThread.cpp b/arangod/MMFiles/MMFilesCollectorThread.cpp index a49ea73c26..fca83caae3 100644 --- a/arangod/MMFiles/MMFilesCollectorThread.cpp +++ b/arangod/MMFiles/MMFilesCollectorThread.cpp @@ -22,6 +22,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "MMFilesCollectorThread.h" + #include "Basics/ConditionLocker.h" #include "Basics/Exceptions.h" #include "Basics/MutexLocker.h" @@ -40,9 +41,9 @@ #include "MMFiles/MMFilesPersistentIndex.h" #include "MMFiles/MMFilesPrimaryIndex.h" #include "MMFiles/MMFilesWalLogfile.h" -#include "RestServer/TransactionManagerFeature.h" #include "StorageEngine/EngineSelectorFeature.h" #include "StorageEngine/StorageEngine.h" +#include "Transaction/ManagerFeature.h" #include "Transaction/Helpers.h" #include "Transaction/Hints.h" #include "Transaction/StandaloneContext.h" @@ -836,7 +837,7 @@ int MMFilesCollectorThread::collect(MMFilesWalLogfile* logfile) { // transactions CollectorState state; state.failedTransactions = - TransactionManagerFeature::manager()->getFailedTransactions(); + transaction::ManagerFeature::manager()->getFailedTransactions(); // scan all markers in logfile, this will fill the state bool result = TRI_IterateDatafile(df, &ScanMarker, static_cast(&state)); @@ -962,7 +963,7 @@ int MMFilesCollectorThread::collect(MMFilesWalLogfile* logfile) { // remove all handled transactions from failedTransactions list if (!state.handledTransactions.empty()) { - TransactionManagerFeature::manager()->unregisterFailedTransactions(state.handledTransactions); + transaction::ManagerFeature::manager()->unregisterFailedTransactions(state.handledTransactions); } return TRI_ERROR_NO_ERROR; diff --git a/arangod/MMFiles/MMFilesEdgeIndex.cpp b/arangod/MMFiles/MMFilesEdgeIndex.cpp index 130838ab89..527a9f7690 100644 --- a/arangod/MMFiles/MMFilesEdgeIndex.cpp +++ b/arangod/MMFiles/MMFilesEdgeIndex.cpp @@ -325,7 +325,7 @@ void MMFilesEdgeIndex::batchInsert(transaction::Methods& trx, toElements->reserve(documents.size()); // functions that will be called for each thread - auto creator = [&trx, this]() -> void* { + auto creator = [this]() -> void* { return new MMFilesIndexLookupContext(&_collection, nullptr, 1); }; auto destroyer = [](void* userData) { diff --git a/arangod/MMFiles/MMFilesEngine.cpp b/arangod/MMFiles/MMFilesEngine.cpp index 97ecee05d6..2228e0d5b8 100644 --- a/arangod/MMFiles/MMFilesEngine.cpp +++ b/arangod/MMFiles/MMFilesEngine.cpp @@ -23,6 +23,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "MMFiles/MMFilesEngine.h" + #include "ApplicationFeatures/ApplicationServer.h" #include "Basics/FileUtils.h" #include "Basics/MutexLocker.h" @@ -48,7 +49,6 @@ #include "MMFiles/MMFilesRestHandlers.h" #include "MMFiles/MMFilesTransactionCollection.h" #include "MMFiles/MMFilesTransactionContextData.h" -#include "MMFiles/MMFilesTransactionManager.h" #include "MMFiles/MMFilesTransactionState.h" #include "MMFiles/MMFilesV8Functions.h" #include "MMFiles/MMFilesWalAccess.h" @@ -277,18 +277,17 @@ void MMFilesEngine::stop() { } } -std::unique_ptr MMFilesEngine::createTransactionManager() { - return std::unique_ptr(new MMFilesTransactionManager()); +std::unique_ptr MMFilesEngine::createTransactionManager() { + return std::make_unique(/*keepData*/ true); } std::unique_ptr MMFilesEngine::createTransactionContextData() { - return std::unique_ptr(new MMFilesTransactionContextData()); + return std::make_unique(); } std::unique_ptr MMFilesEngine::createTransactionState( - TRI_vocbase_t& vocbase, transaction::Options const& options) { - return std::unique_ptr( - new MMFilesTransactionState(vocbase, TRI_NewTickServer(), options)); + TRI_vocbase_t& vocbase, TRI_voc_tick_t tid, transaction::Options const& options) { + return std::make_unique(vocbase, tid, options); } std::unique_ptr MMFilesEngine::createTransactionCollection( @@ -301,7 +300,6 @@ std::unique_ptr MMFilesEngine::createTransactionCollectio std::unique_ptr MMFilesEngine::createPhysicalCollection( LogicalCollection& collection, velocypack::Slice const& info) { TRI_ASSERT(EngineSelectorFeature::ENGINE == this); - return std::unique_ptr(new MMFilesCollection(collection, info)); } diff --git a/arangod/MMFiles/MMFilesEngine.h b/arangod/MMFiles/MMFilesEngine.h index e76b0a7fe5..c5194ebddd 100644 --- a/arangod/MMFiles/MMFilesEngine.h +++ b/arangod/MMFiles/MMFilesEngine.h @@ -39,22 +39,6 @@ namespace arangodb { class MMFilesCleanupThread; class MMFilesCompactorThread; class MMFilesWalAccess; -class PhysicalCollection; -class PhysicalView; -class TransactionCollection; -class TransactionState; - -namespace rest { - -class RestHandlerFactory; -} - -namespace transaction { - -class ContextData; -struct Options; - -} // namespace transaction class MMFilesRecoveryHelper { public: @@ -124,10 +108,10 @@ class MMFilesEngine final : public StorageEngine { std::shared_ptr& builderSPtr) override; WalAccess const* walAccess() const override; - std::unique_ptr createTransactionManager() override; + std::unique_ptr createTransactionManager() override; std::unique_ptr createTransactionContextData() override; - std::unique_ptr createTransactionState(TRI_vocbase_t& vocbase, - transaction::Options const& options) override; + std::unique_ptr createTransactionState( + TRI_vocbase_t& vocbase, TRI_voc_tick_t, transaction::Options const& options) override; std::unique_ptr createTransactionCollection( TransactionState& state, TRI_voc_cid_t cid, AccessMode::Type accessType, int nestingLevel) override; @@ -531,4 +515,4 @@ class MMFilesEngine final : public StorageEngine { } // namespace arangodb -#endif \ No newline at end of file +#endif diff --git a/arangod/MMFiles/MMFilesHashIndex.cpp b/arangod/MMFiles/MMFilesHashIndex.cpp index e4ccfcc368..f457827e16 100644 --- a/arangod/MMFiles/MMFilesHashIndex.cpp +++ b/arangod/MMFiles/MMFilesHashIndex.cpp @@ -655,7 +655,7 @@ void MMFilesHashIndex::batchInsertUnique( } // functions that will be called for each thread - auto creator = [&trx, this]() -> void* { + auto creator = [this]() -> void* { return new MMFilesIndexLookupContext(&_collection, nullptr, numPaths()); }; auto destroyer = [](void* userData) { @@ -774,7 +774,7 @@ void MMFilesHashIndex::batchInsertMulti( } // functions that will be called for each thread - auto creator = [&trx, this]() -> void* { + auto creator = [this]() -> void* { return new MMFilesIndexLookupContext(&_collection, nullptr, numPaths()); }; auto destroyer = [](void* userData) { diff --git a/arangod/MMFiles/MMFilesLogfileManager.cpp b/arangod/MMFiles/MMFilesLogfileManager.cpp index fa800cc514..e78a545bc8 100644 --- a/arangod/MMFiles/MMFilesLogfileManager.cpp +++ b/arangod/MMFiles/MMFilesLogfileManager.cpp @@ -48,9 +48,10 @@ #include "RestServer/DatabaseFeature.h" #include "RestServer/DatabasePathFeature.h" #include "RestServer/FlushFeature.h" -#include "RestServer/TransactionManagerFeature.h" #include "StorageEngine/EngineSelectorFeature.h" #include "StorageEngine/StorageEngine.h" +#include "Transaction/ManagerFeature.h" +#include "StorageEngine/TransactionState.h" using namespace arangodb; using namespace arangodb::application_features; @@ -355,7 +356,7 @@ bool MMFilesLogfileManager::open() { for (auto const& it : _recoverState->failedTransactions) { failedTransactions.emplace(it.first); } - TransactionManagerFeature::manager()->registerFailedTransactions(failedTransactions); + transaction::ManagerFeature::manager()->registerFailedTransactions(failedTransactions); _droppedDatabases = _recoverState->droppedDatabases; _droppedCollections = _recoverState->droppedCollections; @@ -598,8 +599,7 @@ int MMFilesLogfileManager::registerTransaction(TRI_voc_tid_t transactionId, try { auto data = std::make_unique(lastCollectedId, lastSealedId); - TransactionManagerFeature::manager()->registerTransaction(transactionId, - std::move(data)); + transaction::ManagerFeature::manager()->registerTransaction(transactionId, std::move(data)); return TRI_ERROR_NO_ERROR; } catch (...) { return TRI_ERROR_OUT_OF_MEMORY; @@ -1425,7 +1425,7 @@ MMFilesWalLogfile* MMFilesLogfileManager::getCollectableLogfile() { }; // iterate over all active transactions and find their minimum used logfile id - TransactionManagerFeature::manager()->iterateActiveTransactions(cb); + transaction::ManagerFeature::manager()->iterateActiveTransactions(cb); { READ_LOCKER(readLocker, _logfilesLock); @@ -1488,7 +1488,7 @@ MMFilesWalLogfile* MMFilesLogfileManager::getRemovableLogfile() { } }; - TransactionManagerFeature::manager()->iterateActiveTransactions(cb); + transaction::ManagerFeature::manager()->iterateActiveTransactions(cb); { uint32_t numberOfLogfiles = 0; @@ -1691,7 +1691,7 @@ std::tuple MMFiles }; // iterate over all active transactions - TransactionManagerFeature::manager()->iterateActiveTransactions(cb); + transaction::ManagerFeature::manager()->iterateActiveTransactions(cb); return std::tuple( count, lastCollectedId, lastSealedId); diff --git a/arangod/MMFiles/MMFilesLogfileManager.h b/arangod/MMFiles/MMFilesLogfileManager.h index cfcb6c4509..1b42f2f5f3 100644 --- a/arangod/MMFiles/MMFilesLogfileManager.h +++ b/arangod/MMFiles/MMFilesLogfileManager.h @@ -30,7 +30,7 @@ #include "Basics/ReadWriteLock.h" #include "MMFiles/MMFilesWalLogfile.h" #include "MMFiles/MMFilesWalSlots.h" -#include "StorageEngine/TransactionManager.h" +#include "Transaction/Manager.h" #include "VocBase/voc-types.h" namespace arangodb { @@ -236,7 +236,8 @@ class MMFilesLogfileManager final : public application_features::ApplicationFeat } // registers a transaction - int registerTransaction(TRI_voc_tid_t id, bool isReadOnlyTransaction); + int registerTransaction(TRI_voc_tid_t transactionId, + bool isReadOnlyTransaction); // return the set of dropped collections /// this is used during recovery and not used afterwards diff --git a/arangod/MMFiles/MMFilesTransactionState.cpp b/arangod/MMFiles/MMFilesTransactionState.cpp index 2a89096053..debfcf6058 100644 --- a/arangod/MMFiles/MMFilesTransactionState.cpp +++ b/arangod/MMFiles/MMFilesTransactionState.cpp @@ -22,6 +22,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "MMFilesTransactionState.h" + #include "Aql/QueryCache.h" #include "Basics/Exceptions.h" #include "Basics/RocksDBUtils.h" @@ -73,11 +74,11 @@ rocksdb::Transaction* MMFilesTransactionState::rocksTransaction() { /// @brief start a transaction Result MMFilesTransactionState::beginTransaction(transaction::Hints hints) { - LOG_TRX(this, _nestingLevel) + LOG_TRX(this, nestingLevel()) << "beginning " << AccessMode::typeString(_type) << " transaction"; Result result; - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { TRI_ASSERT(_status == transaction::Status::CREATED); auto logfileManager = MMFilesLogfileManager::instance(); @@ -102,7 +103,7 @@ Result MMFilesTransactionState::beginTransaction(transaction::Hints hints) { _hints = hints; // register a protector - int res = logfileManager->registerTransaction(_id, isReadOnlyTransaction()); + int res = logfileManager->registerTransaction(id(), isReadOnlyTransaction()); result.reset(res); if (!result.ok()) { @@ -115,23 +116,23 @@ Result MMFilesTransactionState::beginTransaction(transaction::Hints hints) { TRI_ASSERT(_status == transaction::Status::RUNNING); } - result = useCollections(_nestingLevel); + result = useCollections(nestingLevel()); if (result.ok()) { // all valid - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { updateStatus(transaction::Status::RUNNING); // defer writing of the begin marker until necessary! } } else { // something is wrong - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { updateStatus(transaction::Status::ABORTED); } // free what we have got so far - unuseCollections(_nestingLevel); + unuseCollections(nestingLevel()); } return result; @@ -139,12 +140,12 @@ Result MMFilesTransactionState::beginTransaction(transaction::Hints hints) { /// @brief commit a transaction Result MMFilesTransactionState::commitTransaction(transaction::Methods* activeTrx) { - LOG_TRX(this, _nestingLevel) + LOG_TRX(this, nestingLevel()) << "committing " << AccessMode::typeString(_type) << " transaction"; TRI_ASSERT(_status == transaction::Status::RUNNING); Result result; - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { if (_rocksTransaction != nullptr) { auto status = _rocksTransaction->Commit(); result = rocksutils::convertStatus(status); @@ -177,20 +178,20 @@ Result MMFilesTransactionState::commitTransaction(transaction::Methods* activeTr freeOperations(activeTrx); } - unuseCollections(_nestingLevel); + unuseCollections(nestingLevel()); return result; } /// @brief abort and rollback a transaction Result MMFilesTransactionState::abortTransaction(transaction::Methods* activeTrx) { - LOG_TRX(this, _nestingLevel) << "aborting " << AccessMode::typeString(_type) << " transaction"; + LOG_TRX(this, nestingLevel()) << "aborting " << AccessMode::typeString(_type) << " transaction"; TRI_ASSERT(_status == transaction::Status::RUNNING); Result result; - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { int res = writeAbortMarker(); result.reset(res); @@ -205,7 +206,7 @@ Result MMFilesTransactionState::abortTransaction(transaction::Methods* activeTrx freeOperations(activeTrx); } - unuseCollections(_nestingLevel); + unuseCollections(nestingLevel()); return result; } @@ -497,7 +498,7 @@ int MMFilesTransactionState::writeCommitMarker() { // also sync RocksDB WAL if required bool hasPersistentIndex = false; - allCollections([&hasPersistentIndex](TransactionCollection& collection)->bool { + allCollections([&hasPersistentIndex](TransactionCollection& collection) -> bool { auto* c = static_cast(&collection); if (c->canAccess(AccessMode::Type::WRITE) && diff --git a/arangod/MMFiles/MMFilesTransactionState.h b/arangod/MMFiles/MMFilesTransactionState.h index a3b5e9f5cf..105eacec3b 100644 --- a/arangod/MMFiles/MMFilesTransactionState.h +++ b/arangod/MMFiles/MMFilesTransactionState.h @@ -26,36 +26,19 @@ #include "Basics/Common.h" #include "Basics/Result.h" -#include "Basics/SmallVector.h" #include "StorageEngine/TransactionState.h" -#include "Transaction/Hints.h" -#include "Transaction/Methods.h" -#include "VocBase/AccessMode.h" -#include "VocBase/LocalDocumentId.h" -#include "VocBase/voc-types.h" - -struct TRI_vocbase_t; namespace rocksdb { - class Transaction; } namespace arangodb { +class LocalDocumentId; class LogicalCollection; struct MMFilesDocumentOperation; class MMFilesWalMarker; -namespace transaction { - -class Methods; -struct Options; - -} // namespace transaction - -class TransactionCollection; - /// @brief transaction type class MMFilesTransactionState final : public TransactionState { public: @@ -98,7 +81,7 @@ class MMFilesTransactionState final : public TransactionState { return (!isReadOnlyTransaction() && !isSingleOperation()); } - return (_nestingLevel == 0 && _beginWritten && !isReadOnlyTransaction() && + return (isTopLevelTransaction() && _beginWritten && !isReadOnlyTransaction() && !isSingleOperation()); } diff --git a/arangod/RestHandler/RestCollectionHandler.cpp b/arangod/RestHandler/RestCollectionHandler.cpp index bb7d772fb8..ff6aaacfa2 100644 --- a/arangod/RestHandler/RestCollectionHandler.cpp +++ b/arangod/RestHandler/RestCollectionHandler.cpp @@ -379,16 +379,14 @@ void RestCollectionHandler::handleCommandPut() { opts.isSynchronousReplicationFrom = _request->value("isSynchronousReplication"); - auto ctx = transaction::StandaloneContext::Create(_vocbase); - SingleCollectionTransaction trx(ctx, *coll, AccessMode::Type::EXCLUSIVE); - trx.addHint(transaction::Hints::Hint::INTERMEDIATE_COMMITS); - trx.addHint(transaction::Hints::Hint::ALLOW_RANGE_DELETE); - res = trx.begin(); + auto trx = createTransaction(coll->name(), AccessMode::Type::EXCLUSIVE); + trx->addHint(transaction::Hints::Hint::INTERMEDIATE_COMMITS); + trx->addHint(transaction::Hints::Hint::ALLOW_RANGE_DELETE); + res = trx->begin(); if (res.ok()) { - auto result = trx.truncate(coll->name(), opts); - - res = trx.finish(result.result); + auto result = trx->truncate(coll->name(), opts); + res = trx->finish(result.result); } if (res.ok()) { diff --git a/arangod/RestHandler/RestEdgesHandler.cpp b/arangod/RestHandler/RestEdgesHandler.cpp index 6bfef5804e..cfbdf2501a 100644 --- a/arangod/RestHandler/RestEdgesHandler.cpp +++ b/arangod/RestHandler/RestEdgesHandler.cpp @@ -194,8 +194,7 @@ bool RestEdgesHandler::readEdges() { VPackBuffer buffer; VPackBuilder resultDocument(buffer); resultDocument.openObject(); - int res = getFilteredEdgesOnCoordinator(_vocbase.name(), collectionName, - *(trx.get()), vertexString, direction, + int res = getFilteredEdgesOnCoordinator(*trx, collectionName, vertexString, direction, responseCode, resultDocument); if (res != TRI_ERROR_NO_ERROR) { @@ -335,8 +334,7 @@ bool RestEdgesHandler::readEdgesForMultipleVertices() { for (auto const& it : VPackArrayIterator(body)) { if (it.isString()) { std::string vertexString(it.copyString()); - int res = getFilteredEdgesOnCoordinator(_vocbase.name(), collectionName, - *(trx.get()), vertexString, direction, + int res = getFilteredEdgesOnCoordinator(*trx, collectionName, vertexString, direction, responseCode, resultDocument); if (res != TRI_ERROR_NO_ERROR) { diff --git a/arangod/RestHandler/RestReplicationHandler.cpp b/arangod/RestHandler/RestReplicationHandler.cpp index 1ada982b15..d8ee6159cf 100644 --- a/arangod/RestHandler/RestReplicationHandler.cpp +++ b/arangod/RestHandler/RestReplicationHandler.cpp @@ -1007,17 +1007,21 @@ Result RestReplicationHandler::processRestoreCollectionCoordinator( || TRI_ERROR_CLUSTER_MUST_NOT_DROP_COLL_OTHER_DISTRIBUTESHARDSLIKE == result.errorNumber()) { // some collections must not be dropped - auto res = truncateCollectionOnCoordinator(dbName, name); - - if (res != TRI_ERROR_NO_ERROR) { - return Result( - res, - std::string( - "unable to truncate collection (dropping is forbidden): '") + - name + "'"); + auto ctx = transaction::StandaloneContext::Create(_vocbase); + SingleCollectionTransaction trx(ctx, name, AccessMode::Type::EXCLUSIVE); + + Result res = trx.begin(); + if (res.fail()) { + return res; } - - return Result(res); + + OperationOptions options; + OperationResult result = trx.truncate(name, options); + res = trx.finish(result.result); + if (res.fail()) { + res.appendErrorMessage(". Unable to truncate collection (dropping is forbidden)"); + } + return res; } if (!result.ok()) { diff --git a/arangod/RestServer/arangod.cpp b/arangod/RestServer/arangod.cpp index af2f39cb7f..72c8b9e1c0 100644 --- a/arangod/RestServer/arangod.cpp +++ b/arangod/RestServer/arangod.cpp @@ -89,7 +89,6 @@ #include "RestServer/ServerFeature.h" #include "RestServer/ServerIdFeature.h" #include "RestServer/SystemDatabaseFeature.h" -#include "RestServer/TransactionManagerFeature.h" #include "RestServer/TraverserEngineRegistryFeature.h" #include "RestServer/TtlFeature.h" #include "RestServer/UpgradeFeature.h" @@ -101,6 +100,7 @@ #include "Statistics/StatisticsFeature.h" #include "StorageEngine/EngineSelectorFeature.h" #include "StorageEngine/StorageEngineFeature.h" +#include "Transaction/ManagerFeature.h" #include "V8Server/FoxxQueuesFeature.h" #include "V8Server/V8DealerFeature.h" @@ -213,7 +213,7 @@ static int runServer(int argc, char** argv, ArangoGlobalContext& context) { server.addFeature(new StorageEngineFeature(server)); server.addFeature(new SystemDatabaseFeature(server)); server.addFeature(new TempFeature(server, name)); - server.addFeature(new TransactionManagerFeature(server)); + server.addFeature(new transaction::ManagerFeature(server)); server.addFeature(new TraverserEngineRegistryFeature(server)); server.addFeature(new TtlFeature(server)); server.addFeature(new UpgradeFeature(server, &ret, nonServerFeatures)); diff --git a/arangod/RocksDBEngine/RocksDBEngine.cpp b/arangod/RocksDBEngine/RocksDBEngine.cpp index 1cb8e30eed..1c8972e6b1 100644 --- a/arangod/RocksDBEngine/RocksDBEngine.cpp +++ b/arangod/RocksDBEngine/RocksDBEngine.cpp @@ -65,8 +65,6 @@ #include "RocksDBEngine/RocksDBSyncThread.h" #include "RocksDBEngine/RocksDBThrottle.h" #include "RocksDBEngine/RocksDBTransactionCollection.h" -#include "RocksDBEngine/RocksDBTransactionContextData.h" -#include "RocksDBEngine/RocksDBTransactionManager.h" #include "RocksDBEngine/RocksDBTransactionState.h" #include "RocksDBEngine/RocksDBTypes.h" #include "RocksDBEngine/RocksDBUpgrade.h" @@ -74,6 +72,8 @@ #include "RocksDBEngine/RocksDBValue.h" #include "RocksDBEngine/RocksDBWalAccess.h" #include "Transaction/Context.h" +#include "Transaction/ContextData.h" +#include "Transaction/Manager.h" #include "Transaction/Options.h" #include "Transaction/StandaloneContext.h" #include "VocBase/LogicalView.h" @@ -503,6 +503,7 @@ void RocksDBEngine::start() { static_cast(opts->_blockCacheShardBits), /*strict_capacity_limit*/ opts->_enforceBlockCacheSizeLimit); // tableOptions.cache_index_and_filter_blocks = + // tableOptions.pin_l0_filter_and_index_blocks_in_cache // opts->_compactionReadaheadSize > 0; } else { tableOptions.no_block_cache = true; @@ -783,18 +784,17 @@ void RocksDBEngine::unprepare() { shutdownRocksDBInstance(); } -std::unique_ptr RocksDBEngine::createTransactionManager() { - return std::unique_ptr(new RocksDBTransactionManager()); +std::unique_ptr RocksDBEngine::createTransactionManager() { + return std::make_unique(/*keepData*/ false); } std::unique_ptr RocksDBEngine::createTransactionContextData() { - return std::unique_ptr(new RocksDBTransactionContextData()); + return std::unique_ptr(nullptr); // not used by rocksdb } std::unique_ptr RocksDBEngine::createTransactionState( - TRI_vocbase_t& vocbase, transaction::Options const& options) { - return std::unique_ptr( - new RocksDBTransactionState(vocbase, TRI_NewTickServer(), options)); + TRI_vocbase_t& vocbase, TRI_voc_tid_t tid, transaction::Options const& options) { + return std::make_unique(vocbase, tid, options); } std::unique_ptr RocksDBEngine::createTransactionCollection( diff --git a/arangod/RocksDBEngine/RocksDBEngine.h b/arangod/RocksDBEngine/RocksDBEngine.h index 19b103b3b0..767febc7e0 100644 --- a/arangod/RocksDBEngine/RocksDBEngine.h +++ b/arangod/RocksDBEngine/RocksDBEngine.h @@ -149,10 +149,10 @@ class RocksDBEngine final : public StorageEngine { bool supportsDfdb() const override { return false; } bool useRawDocumentPointers() override { return false; } - std::unique_ptr createTransactionManager() override; + std::unique_ptr createTransactionManager() override; std::unique_ptr createTransactionContextData() override; - std::unique_ptr createTransactionState(TRI_vocbase_t& vocbase, - transaction::Options const& options) override; + std::unique_ptr createTransactionState( + TRI_vocbase_t& vocbase, TRI_voc_tid_t, transaction::Options const& options) override; std::unique_ptr createTransactionCollection( TransactionState& state, TRI_voc_cid_t cid, AccessMode::Type accessType, int nestingLevel) override; diff --git a/arangod/RocksDBEngine/RocksDBIterators.cpp b/arangod/RocksDBEngine/RocksDBIterators.cpp index 677826dc87..353e37235b 100644 --- a/arangod/RocksDBEngine/RocksDBIterators.cpp +++ b/arangod/RocksDBEngine/RocksDBIterators.cpp @@ -244,11 +244,11 @@ void RocksDBAnyIndexIterator::reset() { return; } uint64_t steps = RandomGenerator::interval(_total - 1) % 500; - auto initialKey = RocksDBKey(); - - initialKey.constructDocument(_objectId, - LocalDocumentId(RandomGenerator::interval(UINT64_MAX))); - _iterator->Seek(initialKey.string()); + + RocksDBKeyLeaser key(_trx); + key->constructDocument(_objectId, + LocalDocumentId(RandomGenerator::interval(UINT64_MAX))); + _iterator->Seek(key->string()); if (checkIter()) { if (_forward) { diff --git a/arangod/RocksDBEngine/RocksDBKey.cpp b/arangod/RocksDBEngine/RocksDBKey.cpp index cf06054dc8..e306aa2bcf 100644 --- a/arangod/RocksDBEngine/RocksDBKey.cpp +++ b/arangod/RocksDBEngine/RocksDBKey.cpp @@ -45,7 +45,7 @@ bool RocksDBKey::containsLocalDocumentId(LocalDocumentId const& documentId) cons std::string buffer; uint64ToPersistent(buffer, documentId.id()); // and now check if the key actually contains this local document id - return _buffer.find(buffer) != std::string::npos; + return _buffer->find(buffer) != std::string::npos; } default: { @@ -61,37 +61,34 @@ void RocksDBKey::constructDatabase(TRI_voc_tick_t databaseId) { TRI_ASSERT(databaseId != 0); _type = RocksDBEntryType::Database; size_t keyLength = sizeof(char) + sizeof(uint64_t); - _buffer.clear(); - _buffer.reserve(keyLength); - _buffer.push_back(static_cast(_type)); - uint64ToPersistent(_buffer, databaseId); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + _buffer->push_back(static_cast(_type)); + uint64ToPersistent(*_buffer, databaseId); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructCollection(TRI_voc_tick_t databaseId, TRI_voc_cid_t collectionId) { TRI_ASSERT(databaseId != 0 && collectionId != 0); _type = RocksDBEntryType::Collection; size_t keyLength = sizeof(char) + 2 * sizeof(uint64_t); - _buffer.clear(); - _buffer.reserve(keyLength); - _buffer.push_back(static_cast(_type)); - uint64ToPersistent(_buffer, databaseId); - uint64ToPersistent(_buffer, collectionId); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + _buffer->push_back(static_cast(_type)); + uint64ToPersistent(*_buffer, databaseId); + uint64ToPersistent(*_buffer, collectionId); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructDocument(uint64_t objectId, LocalDocumentId documentId) { TRI_ASSERT(objectId != 0); _type = RocksDBEntryType::Document; size_t keyLength = 2 * sizeof(uint64_t); - _buffer.clear(); - _buffer.reserve(keyLength); - uint64ToPersistent(_buffer, objectId); - uint64ToPersistent(_buffer, documentId.id()); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + uint64ToPersistent(*_buffer, objectId); + uint64ToPersistent(*_buffer, documentId.id()); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructPrimaryIndexValue(uint64_t indexId, @@ -99,12 +96,11 @@ void RocksDBKey::constructPrimaryIndexValue(uint64_t indexId, TRI_ASSERT(indexId != 0 && !primaryKey.empty()); _type = RocksDBEntryType::PrimaryIndexValue; size_t keyLength = sizeof(uint64_t) + primaryKey.size(); - _buffer.clear(); - _buffer.reserve(keyLength); - uint64ToPersistent(_buffer, indexId); - _buffer.append(primaryKey.data(), primaryKey.size()); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + uint64ToPersistent(*_buffer, indexId); + _buffer->append(primaryKey.data(), primaryKey.size()); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructPrimaryIndexValue(uint64_t indexId, char const* primaryKey) { @@ -118,15 +114,14 @@ void RocksDBKey::constructEdgeIndexValue(uint64_t indexId, arangodb::velocypack: TRI_ASSERT(indexId != 0 && !vertexId.empty()); _type = RocksDBEntryType::EdgeIndexValue; size_t keyLength = (sizeof(uint64_t) + sizeof(char)) * 2 + vertexId.size(); - _buffer.clear(); - _buffer.reserve(keyLength); - uint64ToPersistent(_buffer, indexId); - _buffer.append(vertexId.data(), vertexId.length()); - _buffer.push_back(_stringSeparator); - uint64ToPersistent(_buffer, documentId.id()); - _buffer.push_back(0xFFU); // high-byte for prefix extractor - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + uint64ToPersistent(*_buffer, indexId); + _buffer->append(vertexId.data(), vertexId.length()); + _buffer->push_back(_stringSeparator); + uint64ToPersistent(*_buffer, documentId.id()); + _buffer->push_back(0xFFU); // high-byte for prefix extractor + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructVPackIndexValue(uint64_t indexId, VPackSlice const& indexValues, @@ -135,13 +130,12 @@ void RocksDBKey::constructVPackIndexValue(uint64_t indexId, VPackSlice const& in _type = RocksDBEntryType::VPackIndexValue; size_t const byteSize = static_cast(indexValues.byteSize()); size_t keyLength = 2 * sizeof(uint64_t) + byteSize; - _buffer.clear(); - _buffer.reserve(keyLength); - uint64ToPersistent(_buffer, indexId); - _buffer.append(reinterpret_cast(indexValues.begin()), byteSize); - uint64ToPersistent(_buffer, documentId.id()); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + uint64ToPersistent(*_buffer, indexId); + _buffer->append(reinterpret_cast(indexValues.begin()), byteSize); + uint64ToPersistent(*_buffer, documentId.id()); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructUniqueVPackIndexValue(uint64_t indexId, VPackSlice const& indexValues) { @@ -149,12 +143,11 @@ void RocksDBKey::constructUniqueVPackIndexValue(uint64_t indexId, VPackSlice con _type = RocksDBEntryType::UniqueVPackIndexValue; size_t const byteSize = static_cast(indexValues.byteSize()); size_t keyLength = sizeof(uint64_t) + byteSize; - _buffer.clear(); - _buffer.reserve(keyLength); - uint64ToPersistent(_buffer, indexId); - _buffer.append(reinterpret_cast(indexValues.begin()), byteSize); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + uint64ToPersistent(*_buffer, indexId); + _buffer->append(reinterpret_cast(indexValues.begin()), byteSize); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructFulltextIndexValue(uint64_t indexId, @@ -163,14 +156,13 @@ void RocksDBKey::constructFulltextIndexValue(uint64_t indexId, TRI_ASSERT(indexId != 0 && !word.empty()); _type = RocksDBEntryType::FulltextIndexValue; size_t keyLength = sizeof(uint64_t) * 2 + word.size() + sizeof(char); - _buffer.clear(); - _buffer.reserve(keyLength); - uint64ToPersistent(_buffer, indexId); - _buffer.append(word.data(), word.length()); - _buffer.push_back(_stringSeparator); - uint64ToPersistent(_buffer, documentId.id()); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + uint64ToPersistent(*_buffer, indexId); + _buffer->append(word.data(), word.length()); + _buffer->push_back(_stringSeparator); + uint64ToPersistent(*_buffer, documentId.id()); + TRI_ASSERT(_buffer->size() == keyLength); } ////////////////////////////////////////////////////////////////////////////// @@ -181,92 +173,85 @@ void RocksDBKey::constructGeoIndexValue(uint64_t indexId, uint64_t value, TRI_ASSERT(indexId != 0); _type = RocksDBEntryType::GeoIndexValue; size_t keyLength = 3 * sizeof(uint64_t); - _buffer.clear(); - _buffer.reserve(keyLength); - uint64ToPersistent(_buffer, indexId); - uintToPersistentBigEndian(_buffer, value); - uint64ToPersistent(_buffer, documentId.id()); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + uint64ToPersistent(*_buffer, indexId); + uintToPersistentBigEndian(*_buffer, value); // always big endian + uint64ToPersistent(*_buffer, documentId.id()); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructView(TRI_voc_tick_t databaseId, TRI_voc_cid_t viewId) { TRI_ASSERT(databaseId != 0 && viewId != 0); _type = RocksDBEntryType::View; size_t keyLength = sizeof(char) + 2 * sizeof(uint64_t); - _buffer.clear(); - _buffer.reserve(keyLength); - _buffer.push_back(static_cast(_type)); - uint64ToPersistent(_buffer, databaseId); - uint64ToPersistent(_buffer, viewId); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + _buffer->push_back(static_cast(_type)); + uint64ToPersistent(*_buffer, databaseId); + uint64ToPersistent(*_buffer, viewId); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructCounterValue(uint64_t objectId) { TRI_ASSERT(objectId != 0); _type = RocksDBEntryType::CounterValue; size_t keyLength = sizeof(char) + sizeof(uint64_t); - _buffer.clear(); - _buffer.reserve(keyLength); - _buffer.push_back(static_cast(_type)); - uint64ToPersistent(_buffer, objectId); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + _buffer->push_back(static_cast(_type)); + uint64ToPersistent(*_buffer, objectId); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructSettingsValue(RocksDBSettingsType st) { TRI_ASSERT(st != RocksDBSettingsType::Invalid); _type = RocksDBEntryType::SettingsValue; size_t keyLength = 2; - _buffer.clear(); - _buffer.reserve(keyLength); - _buffer.push_back(static_cast(_type)); - _buffer.push_back(static_cast(st)); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + _buffer->push_back(static_cast(_type)); + _buffer->push_back(static_cast(st)); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructReplicationApplierConfig(TRI_voc_tick_t databaseId) { // databaseId may be 0 for global applier config _type = RocksDBEntryType::ReplicationApplierConfig; size_t keyLength = sizeof(char) + sizeof(uint64_t); - _buffer.clear(); - _buffer.reserve(keyLength); - _buffer.push_back(static_cast(_type)); - uint64ToPersistent(_buffer, databaseId); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + _buffer->push_back(static_cast(_type)); + uint64ToPersistent(*_buffer, databaseId); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructIndexEstimateValue(uint64_t collectionObjectId) { TRI_ASSERT(collectionObjectId != 0); _type = RocksDBEntryType::IndexEstimateValue; size_t keyLength = sizeof(char) + sizeof(uint64_t); - _buffer.clear(); - _buffer.reserve(keyLength); - _buffer.push_back(static_cast(_type)); - uint64ToPersistent(_buffer, collectionObjectId); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + _buffer->push_back(static_cast(_type)); + uint64ToPersistent(*_buffer, collectionObjectId); + TRI_ASSERT(_buffer->size() == keyLength); } void RocksDBKey::constructKeyGeneratorValue(uint64_t objectId) { TRI_ASSERT(objectId != 0); _type = RocksDBEntryType::KeyGeneratorValue; size_t keyLength = sizeof(char) + sizeof(uint64_t); - _buffer.clear(); - _buffer.reserve(keyLength); - _buffer.push_back(static_cast(_type)); - uint64ToPersistent(_buffer, objectId); - TRI_ASSERT(_buffer.size() == keyLength); - _slice = rocksdb::Slice(_buffer.data(), keyLength); + _buffer->clear(); + _buffer->reserve(keyLength); + _buffer->push_back(static_cast(_type)); + uint64ToPersistent(*_buffer, objectId); + TRI_ASSERT(_buffer->size() == keyLength); } // ========================= Member methods =========================== RocksDBEntryType RocksDBKey::type(RocksDBKey const& key) { - return type(key._buffer.data(), key._buffer.size()); + return type(key._buffer->data(), key._buffer->size()); } uint64_t RocksDBKey::definitionsObjectId(rocksdb::Slice const& s) { @@ -275,7 +260,7 @@ uint64_t RocksDBKey::definitionsObjectId(rocksdb::Slice const& s) { } TRI_voc_tick_t RocksDBKey::databaseId(RocksDBKey const& key) { - return databaseId(key._buffer.data(), key._buffer.size()); + return databaseId(key._buffer->data(), key._buffer->size()); } TRI_voc_tick_t RocksDBKey::databaseId(rocksdb::Slice const& slice) { @@ -283,7 +268,7 @@ TRI_voc_tick_t RocksDBKey::databaseId(rocksdb::Slice const& slice) { } TRI_voc_cid_t RocksDBKey::collectionId(RocksDBKey const& key) { - return collectionId(key._buffer.data(), key._buffer.size()); + return collectionId(key._buffer->data(), key._buffer->size()); } TRI_voc_cid_t RocksDBKey::collectionId(rocksdb::Slice const& slice) { @@ -291,7 +276,7 @@ TRI_voc_cid_t RocksDBKey::collectionId(rocksdb::Slice const& slice) { } uint64_t RocksDBKey::objectId(RocksDBKey const& key) { - return objectId(key._buffer.data(), key._buffer.size()); + return objectId(key._buffer->data(), key._buffer->size()); } uint64_t RocksDBKey::objectId(rocksdb::Slice const& slice) { @@ -299,7 +284,7 @@ uint64_t RocksDBKey::objectId(rocksdb::Slice const& slice) { } TRI_voc_cid_t RocksDBKey::viewId(RocksDBKey const& key) { - return viewId(key._buffer.data(), key._buffer.size()); + return viewId(key._buffer->data(), key._buffer->size()); } TRI_voc_cid_t RocksDBKey::viewId(rocksdb::Slice const& slice) { @@ -340,7 +325,7 @@ LocalDocumentId RocksDBKey::indexDocumentId(RocksDBEntryType type, } arangodb::velocypack::StringRef RocksDBKey::primaryKey(RocksDBKey const& key) { - return primaryKey(key._buffer.data(), key._buffer.size()); + return primaryKey(key._buffer->data(), key._buffer->size()); } arangodb::velocypack::StringRef RocksDBKey::primaryKey(rocksdb::Slice const& slice) { @@ -348,7 +333,7 @@ arangodb::velocypack::StringRef RocksDBKey::primaryKey(rocksdb::Slice const& sli } arangodb::velocypack::StringRef RocksDBKey::vertexId(RocksDBKey const& key) { - return vertexId(key._buffer.data(), key._buffer.size()); + return vertexId(key._buffer->data(), key._buffer->size()); } arangodb::velocypack::StringRef RocksDBKey::vertexId(rocksdb::Slice const& slice) { @@ -356,7 +341,7 @@ arangodb::velocypack::StringRef RocksDBKey::vertexId(rocksdb::Slice const& slice } VPackSlice RocksDBKey::indexedVPack(RocksDBKey const& key) { - return indexedVPack(key._buffer.data(), key._buffer.size()); + return indexedVPack(key._buffer->data(), key._buffer->size()); } VPackSlice RocksDBKey::indexedVPack(rocksdb::Slice const& slice) { diff --git a/arangod/RocksDBEngine/RocksDBKey.h b/arangod/RocksDBEngine/RocksDBKey.h index 4bd6fe3463..6d48809dd5 100644 --- a/arangod/RocksDBEngine/RocksDBKey.h +++ b/arangod/RocksDBEngine/RocksDBKey.h @@ -42,22 +42,34 @@ class RocksDBKey { public: RocksDBKey() : _type(RocksDBEntryType::Document), // placeholder - _buffer(), - _slice() {} + _local(), + _buffer(&_local) {} + + /// @brief construct a leased RocksDBKey + /// @param leased will use _local std::string if nullptr + explicit RocksDBKey(std::string* leased) + : _type(RocksDBEntryType::Document), // placeholder + _local(), + _buffer(leased != nullptr ? leased : &_local) {} explicit RocksDBKey(rocksdb::Slice slice) : _type(static_cast(slice.data()[0])), - _buffer(slice.data(), slice.size()), - _slice(_buffer) {} + _local(slice.data(), slice.size()), + _buffer(&_local) {} RocksDBKey(RocksDBKey&& other) noexcept : _type(other._type), - _buffer(std::move(other._buffer)), - _slice(_buffer.data(), other._slice.size()) {} + _local(), + _buffer(&_local) { + _local.assign(std::move(*(other._buffer))); + other._buffer = &(other._local); + } RocksDBKey& operator=(RocksDBKey const& other) = delete; RocksDBKey& operator=(RocksDBKey&& other) = delete; - + + public: + /// @brief verify that a key actually contains the given local document id bool containsLocalDocumentId(LocalDocumentId const& id) const; @@ -264,12 +276,22 @@ class RocksDBKey { ////////////////////////////////////////////////////////////////////////////// /// @brief Returns a reference to the full, constructed key ////////////////////////////////////////////////////////////////////////////// - rocksdb::Slice const& string() const { return _slice; } + rocksdb::Slice string() const { return rocksdb::Slice(*_buffer); } - inline size_t size() const { return _slice.size(); } + inline size_t size() const { return _buffer->size(); } bool operator==(RocksDBKey const& other) const { - return _type == other._type && _slice == other._slice; + return _type == other._type && *_buffer == *(other._buffer); + } + + /// @brief does this use the inline buffer or a leased one + inline bool usesInlineBuffer() const { + return &_local == _buffer; + } + + /// @brief internal buffer string, unmanaged use carefully + inline std::string* buffer() const { + return _buffer; } private: @@ -309,9 +331,10 @@ class RocksDBKey { private: static const char _stringSeparator; + RocksDBEntryType _type; - std::string _buffer; - rocksdb::Slice _slice; + std::string _local; // local inline buffer + std::string* _buffer; }; std::ostream& operator<<(std::ostream&, RocksDBKey const&); diff --git a/arangod/RocksDBEngine/RocksDBPrimaryIndex.cpp b/arangod/RocksDBEngine/RocksDBPrimaryIndex.cpp index 814439f9a5..fb178b2942 100644 --- a/arangod/RocksDBEngine/RocksDBPrimaryIndex.cpp +++ b/arangod/RocksDBEngine/RocksDBPrimaryIndex.cpp @@ -46,6 +46,7 @@ #include "Transaction/Context.h" #include "Transaction/Helpers.h" #include "Transaction/Methods.h" +#include "Utils/CollectionNameResolver.h" #include "VocBase/LogicalCollection.h" #include "RocksDBEngine/RocksDBPrefixExtractor.h" diff --git a/arangod/RocksDBEngine/RocksDBReplicationContext.h b/arangod/RocksDBEngine/RocksDBReplicationContext.h index 01ecdcc6f0..9306491abb 100644 --- a/arangod/RocksDBEngine/RocksDBReplicationContext.h +++ b/arangod/RocksDBEngine/RocksDBReplicationContext.h @@ -48,6 +48,9 @@ class Snapshot; } // namespace rocksdb namespace arangodb { +namespace basics { +class StringBuffer; +} class RocksDBReplicationContext { private: diff --git a/arangod/RocksDBEngine/RocksDBRestWalHandler.cpp b/arangod/RocksDBEngine/RocksDBRestWalHandler.cpp index 108845509d..40ea31373c 100644 --- a/arangod/RocksDBEngine/RocksDBRestWalHandler.cpp +++ b/arangod/RocksDBEngine/RocksDBRestWalHandler.cpp @@ -21,16 +21,16 @@ /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// -#include "RocksDBRestWalHandler.h" #include "Basics/StringUtils.h" #include "Basics/VelocyPackHelper.h" #include "Cluster/ClusterMethods.h" #include "Cluster/ServerState.h" -#include "RestServer/TransactionManagerFeature.h" #include "RocksDBEngine/RocksDBCommon.h" #include "RocksDBEngine/RocksDBEngine.h" +#include "RocksDBRestWalHandler.h" #include "StorageEngine/EngineSelectorFeature.h" -#include "StorageEngine/TransactionManager.h" +#include "Transaction/Manager.h" +#include "Transaction/ManagerFeature.h" #include "Utils/ExecContext.h" #include @@ -146,7 +146,7 @@ void RocksDBRestWalHandler::flush() { } void RocksDBRestWalHandler::transactions() { - TransactionManager* mngr = TransactionManagerFeature::manager(); + transaction::Manager* mngr = transaction::ManagerFeature::manager(); VPackBuilder builder; builder.openObject(); builder.add("runningTransactions", VPackValue(mngr->getActiveTransactionCount())); diff --git a/arangod/RocksDBEngine/RocksDBTransactionContextData.h b/arangod/RocksDBEngine/RocksDBTransactionContextData.h deleted file mode 100644 index 438961f326..0000000000 --- a/arangod/RocksDBEngine/RocksDBTransactionContextData.h +++ /dev/null @@ -1,50 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// DISCLAIMER -/// -/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany -/// Copyright 2004-2014 triAGENS 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 Jan Steemann -//////////////////////////////////////////////////////////////////////////////// - -#ifndef ARANGOD_ROCKSDB_ROCKSDB_TRANSACTION_CONTEXT_DATA_H -#define ARANGOD_ROCKSDB_ROCKSDB_TRANSACTION_CONTEXT_DATA_H 1 - -#include "Basics/Common.h" -#include "Transaction/ContextData.h" -#include "VocBase/voc-types.h" - -namespace arangodb { -class LogicalCollection; - -/// @brief transaction type -class RocksDBTransactionContextData final : public transaction::ContextData { - public: - RocksDBTransactionContextData() = default; - ~RocksDBTransactionContextData() = default; - - /// @brief pin data for the collection - /// there is nothing to do for the RocksDB engine - void pinData(arangodb::LogicalCollection*) override {} - - /// @brief whether or not the data for the collection is pinned - /// note that this is always true in RocksDB - bool isPinned(TRI_voc_cid_t) const override { return true; } -}; -} // namespace arangodb - -#endif diff --git a/arangod/RocksDBEngine/RocksDBTransactionManager.h b/arangod/RocksDBEngine/RocksDBTransactionManager.h deleted file mode 100644 index b1d62c6fcf..0000000000 --- a/arangod/RocksDBEngine/RocksDBTransactionManager.h +++ /dev/null @@ -1,76 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// DISCLAIMER -/// -/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany -/// Copyright 2004-2014 triAGENS 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 Jan Steemann -//////////////////////////////////////////////////////////////////////////////// - -#ifndef ARANGOD_ROCKSDB_ROCKSDB_TRANSACTION_MANAGER_H -#define ARANGOD_ROCKSDB_ROCKSDB_TRANSACTION_MANAGER_H 1 - -#include "Basics/Common.h" -#include "Basics/ReadWriteLock.h" -#include "StorageEngine/TransactionManager.h" -#include "VocBase/voc-types.h" - -namespace arangodb { - -class RocksDBTransactionManager final : public TransactionManager { - public: - RocksDBTransactionManager() : TransactionManager(), _nrRunning(0) {} - ~RocksDBTransactionManager() {} - - // register a list of failed transactions - void registerFailedTransactions(std::unordered_set const& failedTransactions) override { - } - - // unregister a list of failed transactions - void unregisterFailedTransactions(std::unordered_set const& failedTransactions) override { - } - - // return the set of failed transactions - std::unordered_set getFailedTransactions() override { - return std::unordered_set(); - } - - // register a transaction - void registerTransaction(TRI_voc_tid_t transactionId, - std::unique_ptr data) override { - TRI_ASSERT(data == nullptr); - ++_nrRunning; - } - - // unregister a transaction - void unregisterTransaction(TRI_voc_tid_t transactionId, bool markAsFailed) override { - TRI_ASSERT(_nrRunning > 0); - --_nrRunning; - } - - // iterate all the active transactions - void iterateActiveTransactions( - std::function const& callback) override {} - - uint64_t getActiveTransactionCount() override { return _nrRunning; } - - private: - std::atomic _nrRunning; -}; -} // namespace arangodb - -#endif diff --git a/arangod/RocksDBEngine/RocksDBTransactionState.cpp b/arangod/RocksDBEngine/RocksDBTransactionState.cpp index fd21b46467..de8bce4979 100644 --- a/arangod/RocksDBEngine/RocksDBTransactionState.cpp +++ b/arangod/RocksDBEngine/RocksDBTransactionState.cpp @@ -22,13 +22,13 @@ //////////////////////////////////////////////////////////////////////////////// #include "RocksDBTransactionState.h" + #include "Aql/QueryCache.h" #include "Basics/Exceptions.h" #include "Cache/CacheManagerFeature.h" #include "Cache/Manager.h" #include "Cache/Transaction.h" #include "Logger/Logger.h" -#include "RestServer/TransactionManagerFeature.h" #include "RocksDBEngine/RocksDBCollection.h" #include "RocksDBEngine/RocksDBCommon.h" #include "RocksDBEngine/RocksDBEngine.h" @@ -39,7 +39,9 @@ #include "StorageEngine/EngineSelectorFeature.h" #include "StorageEngine/StorageEngine.h" #include "StorageEngine/TransactionCollection.h" -#include "StorageEngine/TransactionManager.h" +#include "Transaction/Context.h" +#include "Transaction/Manager.h" +#include "Transaction/ManagerFeature.h" #include "Transaction/Methods.h" #include "Utils/ExecContext.h" #include "VocBase/LogicalCollection.h" @@ -53,9 +55,6 @@ using namespace arangodb; -// for the RocksDB engine we do not need any additional data -struct RocksDBTransactionData final : public TransactionData {}; - /// @brief transaction type RocksDBTransactionState::RocksDBTransactionState(TRI_vocbase_t& vocbase, TRI_voc_tid_t tid, transaction::Options const& options) @@ -67,52 +66,43 @@ RocksDBTransactionState::RocksDBTransactionState(TRI_vocbase_t& vocbase, TRI_voc _numInserts(0), _numUpdates(0), _numRemoves(0), - _keys{_arena}, _parallel(false) {} /// @brief free a transaction container RocksDBTransactionState::~RocksDBTransactionState() { cleanupTransaction(); - for (auto& it : _keys) { - delete it; - } } /// @brief start a transaction Result RocksDBTransactionState::beginTransaction(transaction::Hints hints) { - LOG_TRX(this, _nestingLevel) + LOG_TRX(this, nestingLevel()) << "beginning " << AccessMode::typeString(_type) << " transaction"; TRI_ASSERT(!hasHint(transaction::Hints::Hint::NO_USAGE_LOCK) || !AccessMode::isWriteOrExclusive(_type)); - if (_nestingLevel == 0) { - // set hints - _hints = hints; + if (nestingLevel() == 0) { + _hints = hints; // set hints before useCollections } - Result result = useCollections(_nestingLevel); - + Result result = useCollections(nestingLevel()); if (result.fail()) { // something is wrong - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { updateStatus(transaction::Status::ABORTED); } // free what we have got so far - unuseCollections(_nestingLevel); + unuseCollections(nestingLevel()); return result; } - // all valid - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { // result is valid + // register with manager + transaction::ManagerFeature::manager()->registerTransaction(id(), nullptr); updateStatus(transaction::Status::RUNNING); - // register a protector (intentionally empty) - TransactionManagerFeature::manager()->registerTransaction( - _id, std::unique_ptr()); - setRegistered(); TRI_ASSERT(_rocksTransaction == nullptr); @@ -383,7 +373,7 @@ arangodb::Result RocksDBTransactionState::internalCommit() { /// @brief commit a transaction Result RocksDBTransactionState::commitTransaction(transaction::Methods* activeTrx) { - LOG_TRX(this, _nestingLevel) + LOG_TRX(this, nestingLevel()) << "committing " << AccessMode::typeString(_type) << " transaction"; TRI_ASSERT(_status == transaction::Status::RUNNING); @@ -392,7 +382,7 @@ Result RocksDBTransactionState::commitTransaction(transaction::Methods* activeTr } arangodb::Result res; - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { if (_rocksTransaction != nullptr) { res = internalCommit(); } @@ -405,16 +395,16 @@ Result RocksDBTransactionState::commitTransaction(transaction::Methods* activeTr TRI_ASSERT(!_rocksTransaction && !_cacheTx && !_readSnapshot); } - unuseCollections(_nestingLevel); + unuseCollections(nestingLevel()); return res; } /// @brief abort and rollback a transaction Result RocksDBTransactionState::abortTransaction(transaction::Methods* activeTrx) { - LOG_TRX(this, _nestingLevel) << "aborting " << AccessMode::typeString(_type) << " transaction"; + LOG_TRX(this, nestingLevel()) << "aborting " << AccessMode::typeString(_type) << " transaction"; TRI_ASSERT(_status == transaction::Status::RUNNING); Result result; - if (_nestingLevel == 0) { + if (nestingLevel() == 0) { if (_rocksTransaction != nullptr) { rocksdb::Status status = _rocksTransaction->Rollback(); result = rocksutils::convertStatus(status); @@ -430,7 +420,7 @@ Result RocksDBTransactionState::abortTransaction(transaction::Methods* activeTrx TRI_ASSERT(!_rocksTransaction && !_cacheTx && !_readSnapshot); } - unuseCollections(_nestingLevel); + unuseCollections(nestingLevel()); return result; } @@ -625,31 +615,6 @@ Result RocksDBTransactionState::checkIntermediateCommit(uint64_t newSize, bool& return TRI_ERROR_NO_ERROR; } -/// @brief temporarily lease a RocksDBKey object -RocksDBKey* RocksDBTransactionState::leaseRocksDBKey() { - if (_keys.empty()) { - // create a new key and return it - return new RocksDBKey(); - } - - // re-use an existing builder - RocksDBKey* k = _keys.back(); - _keys.pop_back(); - - return k; -} - -/// @brief return a temporary RocksDBKey object -void RocksDBTransactionState::returnRocksDBKey(RocksDBKey* key) noexcept { - try { - // put key back into our vector of keys - _keys.emplace_back(key); - } catch (...) { - // no harm done. just wipe the key - delete key; - } -} - void RocksDBTransactionState::trackIndexInsert(TRI_voc_cid_t cid, TRI_idx_iid_t idxId, uint64_t hash) { auto col = findCollection(cid); @@ -672,15 +637,15 @@ void RocksDBTransactionState::trackIndexRemove(TRI_voc_cid_t cid, /// @brief constructor, leases a builder RocksDBKeyLeaser::RocksDBKeyLeaser(transaction::Methods* trx) - : _rtrx(RocksDBTransactionState::toState(trx)), - _parallel(_rtrx->inParallelMode()), - _key(_parallel ? &_internal : _rtrx->leaseRocksDBKey()) { - TRI_ASSERT(_key != nullptr); + : _ctx(trx->transactionContextPtr()), + _key(RocksDBTransactionState::toState(trx)->inParallelMode() ? nullptr : _ctx->leaseString()) { + TRI_ASSERT(_ctx != nullptr); + TRI_ASSERT(_key.buffer() != nullptr); } /// @brief destructor RocksDBKeyLeaser::~RocksDBKeyLeaser() { - if (!_parallel && _key != nullptr) { - _rtrx->returnRocksDBKey(_key); + if (!_key.usesInlineBuffer()) { + _ctx->returnString(_key.buffer()); } } diff --git a/arangod/RocksDBEngine/RocksDBTransactionState.h b/arangod/RocksDBEngine/RocksDBTransactionState.h index b5b05055eb..b67eadbed8 100644 --- a/arangod/RocksDBEngine/RocksDBTransactionState.h +++ b/arangod/RocksDBEngine/RocksDBTransactionState.h @@ -49,20 +49,11 @@ class Iterator; namespace arangodb { namespace cache { - struct Transaction; } class LogicalCollection; struct RocksDBDocumentOperation; - -namespace transaction { - -class Methods; -struct Options; - -} // namespace transaction - class RocksDBMethods; /// @brief transaction type @@ -144,10 +135,6 @@ class RocksDBTransactionState final : public TransactionState { void prepareForParallelReads() { _parallel = true; } /// @brief in parallel mode. READ-ONLY transactions bool inParallelMode() const { return _parallel; } - /// @brief temporarily lease a Builder object. Not thread safe - RocksDBKey* leaseRocksDBKey(); - /// @brief return a temporary RocksDBKey object. Not thread safe - void returnRocksDBKey(RocksDBKey* key) noexcept; /// @brief Every index can track hashes inserted into this index /// Used to update the estimate after the trx committed @@ -202,9 +189,7 @@ class RocksDBTransactionState final : public TransactionState { uint64_t _numUpdates; uint64_t _numRemoves; - SmallVector::allocator_type::arena_type _arena; - SmallVector _keys; - /// @brief if true the key buffers will no longer be shared + /// @brief if true there key buffers will no longer be shared bool _parallel; }; @@ -212,16 +197,14 @@ class RocksDBKeyLeaser { public: explicit RocksDBKeyLeaser(transaction::Methods*); ~RocksDBKeyLeaser(); - inline RocksDBKey* builder() const { return _key; } - inline RocksDBKey* operator->() const { return _key; } - inline RocksDBKey* get() const { return _key; } - inline RocksDBKey& ref() const { return *_key; } + inline RocksDBKey* builder() { return &_key; } + inline RocksDBKey* operator->() { return &_key; } + inline RocksDBKey* get() { return &_key; } + inline RocksDBKey& ref() { return _key; } private: - RocksDBTransactionState* _rtrx; - bool _parallel; - RocksDBKey* _key; - RocksDBKey _internal; + transaction::Context* _ctx; + RocksDBKey _key; }; } // namespace arangodb diff --git a/arangod/RocksDBEngine/RocksDBVPackIndex.cpp b/arangod/RocksDBEngine/RocksDBVPackIndex.cpp index 69850e558a..9cb3e62cbc 100644 --- a/arangod/RocksDBEngine/RocksDBVPackIndex.cpp +++ b/arangod/RocksDBEngine/RocksDBVPackIndex.cpp @@ -679,7 +679,7 @@ Result RocksDBVPackIndex::insert(transaction::Methods& trx, RocksDBMethods* mthd } } - IndexingDisabler guard(mthds, !_unique && trx.hasHint(transaction::Hints::Hint::FROM_TOPLEVEL_AQL)); + IndexingDisabler guard(mthds, !_unique && trx.state()->hasHint(transaction::Hints::Hint::FROM_TOPLEVEL_AQL)); // now we are going to construct the value to insert into rocksdb // unique indexes have a different key structure @@ -831,7 +831,7 @@ Result RocksDBVPackIndex::remove(transaction::Methods& trx, RocksDBMethods* mthd } } - IndexingDisabler guard(mthds, !_unique && trx.hasHint(transaction::Hints::Hint::FROM_TOPLEVEL_AQL)); + IndexingDisabler guard(mthds, !_unique && trx.state()->hasHint(transaction::Hints::Hint::FROM_TOPLEVEL_AQL)); size_t const count = elements.size(); diff --git a/arangod/StorageEngine/StorageEngine.h b/arangod/StorageEngine/StorageEngine.h index 3fbb3b778c..d661ee00b9 100644 --- a/arangod/StorageEngine/StorageEngine.h +++ b/arangod/StorageEngine/StorageEngine.h @@ -47,12 +47,10 @@ class PhysicalCollection; class PhysicalView; class Result; class TransactionCollection; -class TransactionManager; class TransactionState; class WalAccess; namespace rest { - class RestHandlerFactory; } @@ -60,6 +58,7 @@ namespace transaction { class Context; class ContextData; +class Manager; struct Options; } // namespace transaction @@ -88,10 +87,10 @@ class StorageEngine : public application_features::ApplicationFeature { virtual bool supportsDfdb() const = 0; - virtual std::unique_ptr createTransactionManager() = 0; + virtual std::unique_ptr createTransactionManager() = 0; virtual std::unique_ptr createTransactionContextData() = 0; virtual std::unique_ptr createTransactionState( - TRI_vocbase_t& vocbase, transaction::Options const& options) = 0; + TRI_vocbase_t& vocbase, TRI_voc_tid_t, transaction::Options const& options) = 0; virtual std::unique_ptr createTransactionCollection( TransactionState& state, TRI_voc_cid_t cid, AccessMode::Type accessType, int nestingLevel) = 0; diff --git a/arangod/StorageEngine/TransactionCollection.h b/arangod/StorageEngine/TransactionCollection.h index 1057db21f4..fdc53924dc 100644 --- a/arangod/StorageEngine/TransactionCollection.h +++ b/arangod/StorageEngine/TransactionCollection.h @@ -54,7 +54,7 @@ class TransactionCollection { inline TRI_voc_cid_t id() const { return _cid; } std::shared_ptr const& collection() const { - return _collection; // vocbase collection pointer + return _collection; // vocbase collection pointer } std::string collectionName() const; diff --git a/arangod/StorageEngine/TransactionManager.h b/arangod/StorageEngine/TransactionManager.h deleted file mode 100644 index 411b4ad408..0000000000 --- a/arangod/StorageEngine/TransactionManager.h +++ /dev/null @@ -1,67 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// DISCLAIMER -/// -/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany -/// Copyright 2004-2014 triAGENS 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 Jan Steemann -//////////////////////////////////////////////////////////////////////////////// - -#ifndef ARANGOD_STORAGE_ENGINE_TRANSACTION_MANAGER_H -#define ARANGOD_STORAGE_ENGINE_TRANSACTION_MANAGER_H 1 - -#include "Basics/Common.h" -#include "VocBase/voc-types.h" - -namespace arangodb { - -// to be derived by storage engines -struct TransactionData { - virtual ~TransactionData() = default; -}; - -class TransactionManager { - public: - TransactionManager() {} - virtual ~TransactionManager() {} - - // register a list of failed transactions - virtual void registerFailedTransactions(std::unordered_set const& failedTransactions) = 0; - - // unregister a list of failed transactions - virtual void unregisterFailedTransactions(std::unordered_set const& failedTransactions) = 0; - - // return the set of failed transactions - virtual std::unordered_set getFailedTransactions() = 0; - - // register a transaction - virtual void registerTransaction(TRI_voc_tid_t transactionId, - std::unique_ptr data) = 0; - - // unregister a transaction - virtual void unregisterTransaction(TRI_voc_tid_t transactionId, bool markAsFailed) = 0; - - // iterate all the active transactions - virtual void iterateActiveTransactions( - std::function const& callback) = 0; - - virtual uint64_t getActiveTransactionCount() = 0; -}; - -} // namespace arangodb - -#endif diff --git a/arangod/StorageEngine/TransactionState.cpp b/arangod/StorageEngine/TransactionState.cpp index c33ba83927..46c215c1c1 100644 --- a/arangod/StorageEngine/TransactionState.cpp +++ b/arangod/StorageEngine/TransactionState.cpp @@ -22,12 +22,14 @@ //////////////////////////////////////////////////////////////////////////////// #include "TransactionState.h" + #include "Aql/QueryCache.h" #include "Basics/Exceptions.h" #include "Logger/Logger.h" #include "StorageEngine/EngineSelectorFeature.h" #include "StorageEngine/StorageEngine.h" #include "StorageEngine/TransactionCollection.h" +#include "Transaction/Context.h" #include "Transaction/Methods.h" #include "Transaction/Options.h" #include "Utils/ExecContext.h" @@ -47,9 +49,9 @@ TransactionState::TransactionState(TRI_vocbase_t& vocbase, TRI_voc_tid_t tid, _collections{_arena}, // assign arena to vector _serverRole(ServerState::instance()->getRole()), _hints(), + _options(options), _nestingLevel(0), - _registeredTransaction(false), - _options(options) {} + _registeredTransaction(false) {} /// @brief free a transaction container TransactionState::~TransactionState() { @@ -124,7 +126,7 @@ int TransactionState::addCollection(TRI_voc_cid_t cid, std::string const& cname, "AccessMode::Type total order fail"); // we may need to recheck permissions here if (trxCollection->accessType() < accessType) { - int res = checkCollectionPermission(cid, cname, accessType); + int res = checkCollectionPermission(cname, accessType); if (res != TRI_ERROR_NO_ERROR) { return res; } @@ -146,7 +148,7 @@ int TransactionState::addCollection(TRI_voc_cid_t cid, std::string const& cname, } // now check the permissions - int res = checkCollectionPermission(cid, cname, accessType); + int res = checkCollectionPermission(cname, accessType); if (res != TRI_ERROR_NO_ERROR) { return res; } @@ -179,11 +181,11 @@ Result TransactionState::ensureCollections(int nestingLevel) { } /// @brief run a callback on all collections -void TransactionState::allCollections( // iterate - std::function const& cb // callback to invoke +void TransactionState::allCollections( // iterate + std::function const& cb // callback to invoke ) { for (auto& trxCollection : _collections) { - TRI_ASSERT(trxCollection); // ensured by addCollection(...) + TRI_ASSERT(trxCollection); // ensured by addCollection(...) if (!cb(*trxCollection)) { // abort early return; @@ -321,8 +323,9 @@ bool TransactionState::isOnlyExclusiveTransaction() const { return true; } -int TransactionState::checkCollectionPermission(TRI_voc_cid_t cid, std::string const& cname, +int TransactionState::checkCollectionPermission(std::string const& cname, AccessMode::Type accessType) const { + TRI_ASSERT(!cname.empty()); ExecContext const* exec = ExecContext::CURRENT; // no need to check for superuser, cluster_sync tests break otherwise @@ -376,10 +379,10 @@ void TransactionState::clearQueryCache() { std::vector collections; for (auto& trxCollection : _collections) { - if (trxCollection // valid instance - && trxCollection->collection() // has a valid collection - && trxCollection->hasOperations() // may have been modified - ) { + if (trxCollection // valid instance + && trxCollection->collection() // has a valid collection + && trxCollection->hasOperations() // may have been modified + ) { // we're only interested in collections that may have been modified collections.emplace_back(trxCollection->collection()->guid()); } diff --git a/arangod/StorageEngine/TransactionState.h b/arangod/StorageEngine/TransactionState.h index 42fe340a11..b6b198fdc5 100644 --- a/arangod/StorageEngine/TransactionState.h +++ b/arangod/StorageEngine/TransactionState.h @@ -31,7 +31,6 @@ #include "Transaction/Hints.h" #include "Transaction/Options.h" #include "Transaction/Status.h" -#include "Utils/CollectionNameResolver.h" #include "VocBase/AccessMode.h" #include "VocBase/voc-types.h" @@ -54,10 +53,9 @@ struct TRI_vocbase_t; namespace arangodb { namespace transaction { - +class Context; class Methods; struct Options; - } // namespace transaction class ExecContext; @@ -108,11 +106,11 @@ class TransactionState { int increaseNesting() { return ++_nestingLevel; } int decreaseNesting() { - TRI_ASSERT(_nestingLevel > 0); + TRI_ASSERT(nestingLevel() > 0); return --_nestingLevel; } int nestingLevel() const { return _nestingLevel; } - bool isTopLevelTransaction() const { return _nestingLevel == 0; } + bool isTopLevelTransaction() const { return nestingLevel() == 0; } bool isEmbeddedTransaction() const { return !isTopLevelTransaction(); } double timeout() const { return _options.lockTimeout; } @@ -220,8 +218,7 @@ class TransactionState { TransactionCollection* findCollection(TRI_voc_cid_t cid, size_t& position) const; /// @brief check if current user can access this collection - int checkCollectionPermission(TRI_voc_cid_t cid, std::string const& cname, - AccessMode::Type) const; + int checkCollectionPermission(std::string const& cname, AccessMode::Type) const; /// @brief release collection locks for a transaction int releaseCollections(); @@ -230,11 +227,10 @@ class TransactionState { /// the transaction void clearQueryCache(); - /// @brief vocbase for this transaction - TRI_vocbase_t& _vocbase; + protected: + TRI_vocbase_t& _vocbase; /// @brief vocbase for this transaction + TRI_voc_tid_t const _id; /// @brief local trx id - /// @brief local trx id - TRI_voc_tid_t const _id; /// @brief access type (read|write) AccessMode::Type _type; /// @brief current status @@ -243,11 +239,9 @@ class TransactionState { SmallVector::allocator_type::arena_type _arena; // memory for collections SmallVector _collections; // list of participating collections - ServerState::RoleEnum const _serverRole; // role of the server + ServerState::RoleEnum const _serverRole; /// role of the server - transaction::Hints _hints; // hints; - int _nestingLevel; - bool _registeredTransaction; + transaction::Hints _hints; // hints; set on _nestingLevel == 0 transaction::Options _options; @@ -257,6 +251,10 @@ class TransactionState { /// the list of locked shards (cluster only) std::unordered_set _lockedShards; + /// @brief reference counter of # of 'Methods' instances using this object + int _nestingLevel; + + bool _registeredTransaction; }; } // namespace arangodb diff --git a/arangod/Transaction/Context.cpp b/arangod/Transaction/Context.cpp index aba18ae594..4d67c0785e 100644 --- a/arangod/Transaction/Context.cpp +++ b/arangod/Transaction/Context.cpp @@ -22,13 +22,15 @@ //////////////////////////////////////////////////////////////////////////////// #include "Context.h" + #include "Basics/StringBuffer.h" -#include "RestServer/TransactionManagerFeature.h" +#include "Cluster/ClusterInfo.h" #include "StorageEngine/EngineSelectorFeature.h" #include "StorageEngine/StorageEngine.h" -#include "StorageEngine/TransactionManager.h" #include "Transaction/ContextData.h" #include "Transaction/Helpers.h" +#include "Transaction/Manager.h" +#include "Transaction/ManagerFeature.h" #include "Transaction/Methods.h" #include "Utils/CollectionNameResolver.h" #include "VocBase/LogicalCollection.h" @@ -69,7 +71,7 @@ transaction::Context::Context(TRI_vocbase_t& vocbase) _stringBuffer(), _options(arangodb::velocypack::Options::Defaults), _dumpOptions(arangodb::velocypack::Options::Defaults), - _transaction{0, false, false}, + _transaction{0, false}, _ownsResolver(false) { /// dump options contain have the escapeUnicode attribute set to true /// this allows dumping of string values as plain 7-bit ASCII values. @@ -78,14 +80,16 @@ transaction::Context::Context(TRI_vocbase_t& vocbase) /// which speculate on ASCII strings first and only fall back to slower /// multibyte strings on first actual occurrence of a multibyte character. _dumpOptions.escapeUnicode = true; + StorageEngine* engine = EngineSelectorFeature::ENGINE; + _contextData = engine->createTransactionContextData(); } /// @brief destroy the context transaction::Context::~Context() { // unregister the transaction from the logfile manager - if (_transaction.id > 0 && _transaction.wasRegistered) { - TransactionManagerFeature::manager()->unregisterTransaction(_transaction.id, - _transaction.hasFailedOperations); + if (_transaction.id > 0) { + transaction::ManagerFeature::manager()->unregisterTransaction(_transaction.id, + _transaction.hasFailedOperations); } // free all VPackBuilders we handed out @@ -108,12 +112,17 @@ VPackCustomTypeHandler* transaction::Context::createCustomTypeHandler( /// @brief pin data for the collection void transaction::Context::pinData(LogicalCollection* collection) { - contextData()->pinData(collection); + if (_contextData) { + _contextData->pinData(collection); + } } /// @brief whether or not the data for the collection is pinned bool transaction::Context::isPinned(TRI_voc_cid_t cid) { - return contextData()->isPinned(cid); + if (_contextData) { + return _contextData->isPinned(cid); + } + return true; // storage engine does not need pinning } /// @brief temporarily lease a StringBuffer object @@ -132,6 +141,22 @@ void transaction::Context::returnStringBuffer(basics::StringBuffer* stringBuffer _stringBuffer.reset(stringBuffer); } +/// @brief temporarily lease a std::string +std::string* transaction::Context::leaseString() { + if (_stdString == nullptr) { + _stdString.reset(new std::string()); + } else { + _stdString->clear(); + } + + return _stdString.release(); +} + +/// @brief return a temporary std::string object +void transaction::Context::returnString(std::string* str) { + _stdString.reset(str); +} + /// @brief temporarily lease a Builder object VPackBuilder* transaction::Context::leaseBuilder() { if (_builders.empty()) { @@ -195,22 +220,16 @@ CollectionNameResolver const* transaction::Context::createResolver() { /// @brief unregister the transaction /// this will save the transaction's id and status locally -void transaction::Context::storeTransactionResult(TRI_voc_tid_t id, - bool hasFailedOperations, +void transaction::Context::storeTransactionResult(TRI_voc_tid_t id, bool hasFailedOperations, bool wasRegistered) noexcept { TRI_ASSERT(_transaction.id == 0); - _transaction.id = id; - _transaction.hasFailedOperations = hasFailedOperations; - _transaction.wasRegistered = wasRegistered; -} - -transaction::ContextData* transaction::Context::contextData() { - if (_contextData == nullptr) { - StorageEngine* engine = EngineSelectorFeature::ENGINE; - - _contextData = engine->createTransactionContextData(); + if (wasRegistered) { + _transaction.id = id; + _transaction.hasFailedOperations = hasFailedOperations; } - - return _contextData.get(); +} + +TRI_voc_tid_t transaction::Context::generateId() const { + return TRI_NewTickServer(); } diff --git a/arangod/Transaction/Context.h b/arangod/Transaction/Context.h index 31bba44be7..bc83bd2c20 100644 --- a/arangod/Transaction/Context.h +++ b/arangod/Transaction/Context.h @@ -84,6 +84,12 @@ class Context { /// @brief return a temporary StringBuffer object void returnStringBuffer(basics::StringBuffer* stringBuffer); + /// @brief temporarily lease a std::string + std::string* leaseString(); + + /// @brief return a temporary std::string object + void returnString(std::string* str); + /// @brief temporarily lease a Builder object arangodb::velocypack::Builder* leaseBuilder(); @@ -98,12 +104,14 @@ class Context { /// @brief unregister the transaction /// this will save the transaction's id and status locally - void storeTransactionResult(TRI_voc_tid_t id, bool hasFailedOperations, bool wasRegistered) noexcept; + void storeTransactionResult(TRI_voc_tid_t id, bool hasFailedOperations, + bool wasRegistered) noexcept; + public: /// @brief get a custom type handler virtual std::shared_ptr orderCustomTypeHandler() = 0; - /// @brief get parent transaction (if any) + /// @brief get parent transaction (if any) increase nesting virtual TransactionState* getParentTransaction() const = 0; /// @brief whether or not the transaction is embeddable @@ -117,12 +125,14 @@ class Context { /// @brief unregister the transaction virtual void unregisterTransaction() noexcept = 0; + /// @brief generate persisted transaction ID + virtual TRI_voc_tid_t generateId() const; + protected: /// @brief create a resolver CollectionNameResolver const* createResolver(); - transaction::ContextData* contextData(); - + protected: TRI_vocbase_t& _vocbase; CollectionNameResolver const* _resolver; std::shared_ptr _customTypeHandler; @@ -131,16 +141,17 @@ class Context { SmallVector _builders; std::unique_ptr _stringBuffer; + std::unique_ptr _stdString; arangodb::velocypack::Options _options; arangodb::velocypack::Options _dumpOptions; + private: std::unique_ptr _contextData; struct { TRI_voc_tid_t id; bool hasFailedOperations; - bool wasRegistered; } _transaction; bool _ownsResolver; diff --git a/arangod/Transaction/ContextData.h b/arangod/Transaction/ContextData.h index 7acdc16a2d..0483a454db 100644 --- a/arangod/Transaction/ContextData.h +++ b/arangod/Transaction/ContextData.h @@ -31,6 +31,9 @@ namespace arangodb { class LogicalCollection; namespace transaction { + +/// Storage engine specific data that shares the lifetime +/// of the transaction::Context class ContextData { public: ContextData(ContextData const&) = delete; diff --git a/arangod/Transaction/Helpers.cpp b/arangod/Transaction/Helpers.cpp index d35961f4ed..b10a20cdd0 100644 --- a/arangod/Transaction/Helpers.cpp +++ b/arangod/Transaction/Helpers.cpp @@ -424,6 +424,8 @@ std::string transaction::helpers::makeIdFromCustom(CollectionNameResolver const* return resolved; } +// ============== StringBufferLeaser ============== + /// @brief constructor, leases a StringBuffer transaction::StringBufferLeaser::StringBufferLeaser(transaction::Methods* trx) : _transactionContext(trx->transactionContextPtr()), @@ -439,6 +441,25 @@ transaction::StringBufferLeaser::~StringBufferLeaser() { _transactionContext->returnStringBuffer(_stringBuffer); } +// ============== StringLeaser ============== + +/// @brief constructor, leases a std::string +transaction::StringLeaser::StringLeaser(transaction::Methods* trx) + : _transactionContext(trx->transactionContextPtr()), + _string(_transactionContext->leaseString()) {} + +/// @brief constructor, leases a StringBuffer +transaction::StringLeaser::StringLeaser(transaction::Context* transactionContext) + : _transactionContext(transactionContext), + _string(_transactionContext->leaseString()) {} + +/// @brief destructor +transaction::StringLeaser::~StringLeaser() { + _transactionContext->returnString(_string); +} + +// ============== BuilderLeaser ============== + /// @brief constructor, leases a builder transaction::BuilderLeaser::BuilderLeaser(transaction::Methods* trx) : _transactionContext(trx->transactionContextPtr()), diff --git a/arangod/Transaction/Helpers.h b/arangod/Transaction/Helpers.h index 38cebf0517..f1d59a4d9b 100644 --- a/arangod/Transaction/Helpers.h +++ b/arangod/Transaction/Helpers.h @@ -96,6 +96,8 @@ std::string makeIdFromCustom(CollectionNameResolver const* resolver, VPackSlice const& idPart, VPackSlice const& keyPart); }; // namespace helpers +/// @brief basics::StringBuffer leaser +/// @deprecated rather use StringLeaser for a shared std::string class StringBufferLeaser { public: explicit StringBufferLeaser(Methods*); @@ -110,6 +112,21 @@ class StringBufferLeaser { arangodb::basics::StringBuffer* _stringBuffer; }; +/// @brief std::string leaser +class StringLeaser { + public: + explicit StringLeaser(Methods*); + explicit StringLeaser(transaction::Context*); + ~StringLeaser(); + std::string* string() const { return _string; } + std::string* operator->() const { return _string; } + std::string* get() const { return _string; } + + private: + transaction::Context* _transactionContext; + std::string* _string; +}; + class BuilderLeaser { public: explicit BuilderLeaser(transaction::Methods*); diff --git a/arangod/MMFiles/MMFilesTransactionManager.cpp b/arangod/Transaction/Manager.cpp similarity index 52% rename from arangod/MMFiles/MMFilesTransactionManager.cpp rename to arangod/Transaction/Manager.cpp index b666f7728d..04ca91e81e 100644 --- a/arangod/MMFiles/MMFilesTransactionManager.cpp +++ b/arangod/Transaction/Manager.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// -/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany +/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,70 +21,88 @@ /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// -#include "MMFilesTransactionManager.h" +#include "Manager.h" + #include "Basics/ReadLocker.h" #include "Basics/WriteLocker.h" +#include "Logger/Logger.h" +#include "StorageEngine/EngineSelectorFeature.h" +#include "StorageEngine/StorageEngine.h" +#include "StorageEngine/TransactionState.h" +#include "Transaction/Helpers.h" +#include "Transaction/Methods.h" +#include "Transaction/SmartContext.h" +#include "Utils/CollectionNameResolver.h" -using namespace arangodb; +#include +#include + +namespace arangodb { +namespace transaction { // register a list of failed transactions -void MMFilesTransactionManager::registerFailedTransactions( - std::unordered_set const& failedTransactions) { +void Manager::registerFailedTransactions(std::unordered_set const& failedTransactions) { + TRI_ASSERT(_keepTransactionData); READ_LOCKER(allTransactionsLocker, _allTransactionsLock); - for (auto const& it : failedTransactions) { - size_t bucket = getBucket(it); - + const size_t bucket = getBucket(it); WRITE_LOCKER(locker, _transactions[bucket]._lock); - _transactions[bucket]._failedTransactions.emplace(it); } } // unregister a list of failed transactions -void MMFilesTransactionManager::unregisterFailedTransactions( - std::unordered_set const& failedTransactions) { +void Manager::unregisterFailedTransactions(std::unordered_set const& failedTransactions) { + TRI_ASSERT(_keepTransactionData); READ_LOCKER(allTransactionsLocker, _allTransactionsLock); - for (size_t bucket = 0; bucket < numBuckets; ++bucket) { WRITE_LOCKER(locker, _transactions[bucket]._lock); - std::for_each(failedTransactions.begin(), failedTransactions.end(), [&](TRI_voc_tid_t id) { _transactions[bucket]._failedTransactions.erase(id); }); } } -void MMFilesTransactionManager::registerTransaction(TRI_voc_tid_t transactionId, - std::unique_ptr data) { - TRI_ASSERT(data != nullptr); +void Manager::registerTransaction(TRI_voc_tid_t transactionId, + std::unique_ptr data) { + _nrRunning.fetch_add(1, std::memory_order_relaxed); - size_t bucket = getBucket(transactionId); - READ_LOCKER(allTransactionsLocker, _allTransactionsLock); - - WRITE_LOCKER(writeLocker, _transactions[bucket]._lock); - - // insert into currently running list of transactions - _transactions[bucket]._activeTransactions.emplace(transactionId, std::move(data)); + if (_keepTransactionData) { + TRI_ASSERT(data != nullptr); + const size_t bucket = getBucket(transactionId); + READ_LOCKER(allTransactionsLocker, _allTransactionsLock); + WRITE_LOCKER(writeLocker, _transactions[bucket]._lock); + + try { + // insert into currently running list of transactions + _transactions[bucket]._activeTransactions.emplace(transactionId, std::move(data)); + } catch (...) { + _nrRunning.fetch_sub(1, std::memory_order_relaxed); + throw; + } + } } // unregisters a transaction -void MMFilesTransactionManager::unregisterTransaction(TRI_voc_tid_t transactionId, - bool markAsFailed) { - size_t bucket = getBucket(transactionId); - READ_LOCKER(allTransactionsLocker, _allTransactionsLock); +void Manager::unregisterTransaction(TRI_voc_tid_t transactionId, bool markAsFailed) { + uint64_t r = _nrRunning.fetch_sub(1, std::memory_order_relaxed); + TRI_ASSERT(r > 0); - WRITE_LOCKER(writeLocker, _transactions[bucket]._lock); + if (_keepTransactionData) { + const size_t bucket = getBucket(transactionId); + READ_LOCKER(allTransactionsLocker, _allTransactionsLock); - _transactions[bucket]._activeTransactions.erase(transactionId); + WRITE_LOCKER(writeLocker, _transactions[bucket]._lock); - if (markAsFailed) { - _transactions[bucket]._failedTransactions.emplace(transactionId); + _transactions[bucket]._activeTransactions.erase(transactionId); + if (markAsFailed) { + _transactions[bucket]._failedTransactions.emplace(transactionId); + } } } // return the set of failed transactions -std::unordered_set MMFilesTransactionManager::getFailedTransactions() { +std::unordered_set Manager::getFailedTransactions() const { std::unordered_set failedTransactions; { @@ -102,8 +120,11 @@ std::unordered_set MMFilesTransactionManager::getFailedTransactio return failedTransactions; } -void MMFilesTransactionManager::iterateActiveTransactions( +void Manager::iterateActiveTransactions( std::function const& callback) { + if (!_keepTransactionData) { + return; + } WRITE_LOCKER(allTransactionsLocker, _allTransactionsLock); // iterate over all active transactions @@ -117,14 +138,9 @@ void MMFilesTransactionManager::iterateActiveTransactions( } } -uint64_t MMFilesTransactionManager::getActiveTransactionCount() { - WRITE_LOCKER(allTransactionsLocker, _allTransactionsLock); - - uint64_t count = 0; - // iterate over all active transactions - for (size_t bucket = 0; bucket < numBuckets; ++bucket) { - READ_LOCKER(locker, _transactions[bucket]._lock); - count += _transactions[bucket]._activeTransactions.size(); - } - return count; +uint64_t Manager::getActiveTransactionCount() { + return _nrRunning.load(std::memory_order_relaxed); } + +} // namespace transaction +} // namespace arangodb diff --git a/arangod/MMFiles/MMFilesTransactionManager.h b/arangod/Transaction/Manager.h similarity index 57% rename from arangod/MMFiles/MMFilesTransactionManager.h rename to arangod/Transaction/Manager.h index 1fb22dc59a..6aa9cde0dc 100644 --- a/arangod/MMFiles/MMFilesTransactionManager.h +++ b/arangod/Transaction/Manager.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// -/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany +/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,57 +21,77 @@ /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// -#ifndef ARANGOD_MMFILES_MMFILES_TRANSACTION_MANAGER_H -#define ARANGOD_MMFILES_MMFILES_TRANSACTION_MANAGER_H 1 +#ifndef ARANGOD_TRANSACTION_MANAGER_H +#define ARANGOD_TRANSACTION_MANAGER_H 1 #include "Basics/Common.h" #include "Basics/ReadWriteLock.h" -#include "StorageEngine/TransactionManager.h" +#include "Basics/ReadWriteSpinLock.h" +#include "Basics/Result.h" +#include "Transaction/Status.h" +#include "VocBase/AccessMode.h" #include "VocBase/voc-types.h" -namespace arangodb { +#include +#include -class MMFilesTransactionManager final : public TransactionManager { +namespace arangodb { +class TransactionState; +// to be derived by storage engines +struct TransactionData { + virtual ~TransactionData() = default; +}; + +namespace transaction { +class Context; + +class Manager final { static constexpr size_t numBuckets = 16; + static constexpr double defaultTTL = 10.0 * 60.0; // 10 minutes + static constexpr double tombstoneTTL = 5.0 * 60.0; // 5 minutes public: - MMFilesTransactionManager() : TransactionManager() {} - ~MMFilesTransactionManager() {} + explicit Manager(bool keepData) : _keepTransactionData(keepData), _nrRunning(0) {} + public: + typedef std::function TrxCallback; + + public: // register a list of failed transactions - void registerFailedTransactions(std::unordered_set const& failedTransactions) override; + void registerFailedTransactions(std::unordered_set const& failedTransactions); // unregister a list of failed transactions - void unregisterFailedTransactions(std::unordered_set const& failedTransactions) override; + void unregisterFailedTransactions(std::unordered_set const& failedTransactions); // return the set of failed transactions - std::unordered_set getFailedTransactions() override; + std::unordered_set getFailedTransactions() const; // register a transaction - void registerTransaction(TRI_voc_tid_t transactionId, - std::unique_ptr data) override; + void registerTransaction(TRI_voc_tid_t, std::unique_ptr data); // unregister a transaction - void unregisterTransaction(TRI_voc_tid_t transactionId, bool markAsFailed) override; + void unregisterTransaction(TRI_voc_tid_t transactionId, bool markAsFailed); // iterate all the active transactions - void iterateActiveTransactions( - std::function const& callback) override; + void iterateActiveTransactions(TrxCallback const&); - uint64_t getActiveTransactionCount() override; + uint64_t getActiveTransactionCount(); private: // hashes the transaction id into a bucket - inline size_t getBucket(TRI_voc_tid_t id) const { - return std::hash()(id) % numBuckets; + inline size_t getBucket(TRI_voc_tid_t tid) const { + return std::hash()(tid) % numBuckets; } + private: + const bool _keepTransactionData; + // a lock protecting ALL buckets in _transactions - basics::ReadWriteLock _allTransactionsLock; + mutable basics::ReadWriteLock _allTransactionsLock; struct { // a lock protecting _activeTransactions and _failedTransactions - basics::ReadWriteLock _lock; + mutable basics::ReadWriteLock _lock; // currently ongoing transactions std::unordered_map> _activeTransactions; @@ -79,8 +99,11 @@ class MMFilesTransactionManager final : public TransactionManager { // set of failed transactions std::unordered_set _failedTransactions; } _transactions[numBuckets]; -}; + /// Nr of running transactions + std::atomic _nrRunning; +}; +} // namespace transaction } // namespace arangodb #endif diff --git a/arangod/RestServer/TransactionManagerFeature.cpp b/arangod/Transaction/ManagerFeature.cpp similarity index 79% rename from arangod/RestServer/TransactionManagerFeature.cpp rename to arangod/Transaction/ManagerFeature.cpp index 6a4bbaa5f2..551f0b4ea5 100644 --- a/arangod/RestServer/TransactionManagerFeature.cpp +++ b/arangod/Transaction/ManagerFeature.cpp @@ -20,22 +20,24 @@ /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// -#include "TransactionManagerFeature.h" +#include "ManagerFeature.h" #include "ApplicationFeatures/ApplicationServer.h" +#include "Scheduler/SchedulerFeature.h" #include "StorageEngine/EngineSelectorFeature.h" #include "StorageEngine/StorageEngine.h" -#include "StorageEngine/TransactionManager.h" +#include "Transaction/Manager.h" using namespace arangodb::application_features; using namespace arangodb::basics; using namespace arangodb::options; namespace arangodb { +namespace transaction { -std::unique_ptr TransactionManagerFeature::MANAGER; +std::unique_ptr ManagerFeature::MANAGER; -TransactionManagerFeature::TransactionManagerFeature(application_features::ApplicationServer& server) +ManagerFeature::ManagerFeature(application_features::ApplicationServer& server) : ApplicationFeature(server, "TransactionManager") { setOptional(false); startsAfter("BasicsPhase"); @@ -43,12 +45,13 @@ TransactionManagerFeature::TransactionManagerFeature(application_features::Appli startsAfter("EngineSelector"); } -void TransactionManagerFeature::prepare() { +void ManagerFeature::prepare() { TRI_ASSERT(MANAGER == nullptr); TRI_ASSERT(EngineSelectorFeature::ENGINE != nullptr); MANAGER = EngineSelectorFeature::ENGINE->createTransactionManager(); } -void TransactionManagerFeature::unprepare() { MANAGER.reset(); } +void ManagerFeature::unprepare() { MANAGER.reset(); } +} // namespace transaction } // namespace arangodb diff --git a/arangod/RestServer/TransactionManagerFeature.h b/arangod/Transaction/ManagerFeature.h similarity index 73% rename from arangod/RestServer/TransactionManagerFeature.h rename to arangod/Transaction/ManagerFeature.h index 556799ca82..b00a28b585 100644 --- a/arangod/RestServer/TransactionManagerFeature.h +++ b/arangod/Transaction/ManagerFeature.h @@ -20,31 +20,33 @@ /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// -#ifndef ARANGODB_REST_SERVER_TRANSACTION_MANAGER_FEATURE_H -#define ARANGODB_REST_SERVER_TRANSACTION_MANAGER_FEATURE_H 1 +#ifndef ARANGODB_TRANSACTION_MANAGER_FEATURE_H +#define ARANGODB_TRANSACTION_MANAGER_FEATURE_H 1 #include "ApplicationFeatures/ApplicationFeature.h" namespace arangodb { +namespace transaction { -class TransactionManager; +class Manager; -class TransactionManagerFeature final : public application_features::ApplicationFeature { +class ManagerFeature final : public application_features::ApplicationFeature { public: - explicit TransactionManagerFeature(application_features::ApplicationServer& server); + explicit ManagerFeature(application_features::ApplicationServer& server); void prepare() override final; void unprepare() override final; - static TransactionManager* manager() { + static transaction::Manager* manager() { TRI_ASSERT(MANAGER != nullptr); return MANAGER.get(); } private: - static std::unique_ptr MANAGER; + static std::unique_ptr MANAGER; }; +} // namespace transaction } // namespace arangodb -#endif \ No newline at end of file +#endif diff --git a/arangod/Transaction/Methods.cpp b/arangod/Transaction/Methods.cpp index 1a5c941e8b..b533af5f44 100644 --- a/arangod/Transaction/Methods.cpp +++ b/arangod/Transaction/Methods.cpp @@ -22,6 +22,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "Methods.h" + #include "ApplicationFeatures/ApplicationServer.h" #include "Aql/Ast.h" #include "Aql/AstNode.h" @@ -343,7 +344,7 @@ bool transaction::Methods::sortOrs(arangodb::aql::Ast* ast, arangodb::aql::AstNo std::vector parts; parts.reserve(n); - + std::pair> result; for (size_t i = 0; i < n; ++i) { @@ -431,7 +432,7 @@ bool transaction::Methods::sortOrs(arangodb::aql::Ast* ast, arangodb::aql::AstNo for (size_t i = 0; i < n; ++i) { auto& p = parts[i]; - + if (p.operatorType == arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_BINARY_IN && p.valueNode->isArray()) { TRI_ASSERT(p.valueNode->isConstant()); @@ -442,15 +443,15 @@ bool transaction::Methods::sortOrs(arangodb::aql::Ast* ast, arangodb::aql::AstNo auto emptyArray = ast->createNodeArray(); auto mergedIn = ast->createNodeUnionizedArray(parts[previousIn].valueNode, p.valueNode); - + arangodb::aql::AstNode* clone = ast->clone(root->getMember(previousIn)); root->changeMember(previousIn, clone); static_cast(parts[previousIn].data)->first = clone; - + clone = ast->clone(root->getMember(i)); root->changeMember(i, clone); static_cast(parts[i].data)->first = clone; - + // can now edit nodes in place... parts[previousIn].valueNode = mergedIn; { @@ -459,7 +460,7 @@ bool transaction::Methods::sortOrs(arangodb::aql::Ast* ast, arangodb::aql::AstNo TEMPORARILY_UNLOCK_NODE(n1); n1->changeMember(1, mergedIn); } - + p.valueNode = emptyArray; { auto n2 = root->getMember(i)->getMember(0); @@ -467,14 +468,14 @@ bool transaction::Methods::sortOrs(arangodb::aql::Ast* ast, arangodb::aql::AstNo TEMPORARILY_UNLOCK_NODE(n2); n2->changeMember(1, emptyArray); } - + } else { // note first IN previousIn = i; } } } - + // now sort all conditions by variable name, attribute name, attribute value std::sort(parts.begin(), parts.end(), [](arangodb::aql::ConditionPart const& lhs, @@ -526,7 +527,7 @@ bool transaction::Methods::sortOrs(arangodb::aql::Ast* ast, arangodb::aql::AstNo }); TRI_ASSERT(parts.size() == conditionData.size()); - + // clean up while (root->numMembers()) { root->removeMemberUnchecked(0); @@ -567,7 +568,7 @@ bool transaction::Methods::sortOrs(arangodb::aql::Ast* ast, arangodb::aql::AstNo usedIndexes.emplace_back(conditionData->second); } } - + return true; } @@ -764,7 +765,6 @@ transaction::Methods::Methods(std::shared_ptr const& trans } _state = parent; - TRI_ASSERT(_state != nullptr); _state->increaseNesting(); } else { // non-embedded @@ -772,10 +772,10 @@ transaction::Methods::Methods(std::shared_ptr const& trans StorageEngine* engine = EngineSelectorFeature::ENGINE; _state = engine - ->createTransactionState(_transactionContextPtr->vocbase(), options) + ->createTransactionState(_transactionContextPtr->vocbase(), + _transactionContextPtr->generateId(), options) .release(); - TRI_ASSERT(_state != nullptr); - TRI_ASSERT(_state->isTopLevelTransaction()); + TRI_ASSERT(_state != nullptr && _state->isTopLevelTransaction()); // register the transaction in the context _transactionContextPtr->registerTransaction(_state); @@ -806,9 +806,10 @@ transaction::Methods::Methods(std::shared_ptr const& ctx, /// @brief destroy the transaction transaction::Methods::~Methods() { - if (_state->isEmbeddedTransaction()) { - _state->decreaseNesting(); - } else { + if (_state->isTopLevelTransaction()) { // _nestingLevel == 0 + // unregister transaction from context + _transactionContextPtr->unregisterTransaction(); + if (_state->status() == transaction::Status::RUNNING) { // auto abort a running transaction try { @@ -821,14 +822,16 @@ transaction::Methods::~Methods() { // free the state associated with the transaction TRI_ASSERT(_state->status() != transaction::Status::RUNNING); - // store result + + // store result in context _transactionContextPtr->storeTransactionResult(_state->id(), _state->hasFailedOperations(), _state->wasRegistered()); - _transactionContextPtr->unregisterTransaction(); delete _state; _state = nullptr; + } else { + _state->decreaseNesting(); // return transaction } } @@ -1460,9 +1463,8 @@ OperationResult transaction::Methods::documentCoordinator(std::string const& col } } - int res = arangodb::getDocumentOnCoordinator(vocbase().name(), collectionName, - *this, value, options, responseCode, - errorCounter, resultBody); + int res = arangodb::getDocumentOnCoordinator(*this, collectionName, value, options, + responseCode, errorCounter, resultBody); if (res == TRI_ERROR_NO_ERROR) { return clusterResultDocument(responseCode, resultBody, errorCounter); @@ -1587,8 +1589,8 @@ OperationResult transaction::Methods::insertCoordinator(std::string const& colle std::unordered_map errorCounter; auto resultBody = std::make_shared(); - Result res = arangodb::createDocumentOnCoordinator(vocbase().name(), collectionName, - *this, options, value, responseCode, + Result res = arangodb::createDocumentOnCoordinator(*this, collectionName, + options, value, responseCode, errorCounter, resultBody); if (res.ok()) { @@ -1677,7 +1679,7 @@ OperationResult transaction::Methods::insertLocal(std::string const& collectionN std::function updateFollowers = nullptr; if (needsToGetFollowersUnderLock) { - auto const& followerInfo = *collection->followers(); + FollowerInfo const& followerInfo = *collection->followers(); updateFollowers = [&followerInfo, &followers]() -> Result { TRI_ASSERT(followers == nullptr); @@ -1890,10 +1892,9 @@ OperationResult transaction::Methods::updateCoordinator(std::string const& colle rest::ResponseCode responseCode; std::unordered_map errorCounter; auto resultBody = std::make_shared(); - int res = arangodb::modifyDocumentOnCoordinator(vocbase().name(), collectionName, - *this, newValue, options, - true /* isPatch */, headers, responseCode, - errorCounter, resultBody); + int res = arangodb::modifyDocumentOnCoordinator(*this, collectionName, newValue, + options, true /* isPatch */, headers, + responseCode, errorCounter, resultBody); if (res == TRI_ERROR_NO_ERROR) { return clusterResultModify(responseCode, resultBody, errorCounter); @@ -1939,9 +1940,9 @@ OperationResult transaction::Methods::replaceCoordinator(std::string const& coll rest::ResponseCode responseCode; std::unordered_map errorCounter; auto resultBody = std::make_shared(); - int res = arangodb::modifyDocumentOnCoordinator(vocbase().name(), collectionName, - *this, newValue, options, - false /* isPatch */, headers, responseCode, + int res = arangodb::modifyDocumentOnCoordinator(*this, collectionName, newValue, + options, false /* isPatch */, + headers, responseCode, errorCounter, resultBody); if (res == TRI_ERROR_NO_ERROR) { @@ -2214,8 +2215,8 @@ OperationResult transaction::Methods::removeCoordinator(std::string const& colle rest::ResponseCode responseCode; std::unordered_map errorCounter; auto resultBody = std::make_shared(); - int res = arangodb::deleteDocumentOnCoordinator(vocbase().name(), collectionName, - *this, value, options, responseCode, + int res = arangodb::deleteDocumentOnCoordinator(*this, collectionName, value, + options, responseCode, errorCounter, resultBody); if (res == TRI_ERROR_NO_ERROR) { @@ -2514,8 +2515,7 @@ OperationResult transaction::Methods::truncate(std::string const& collectionName #ifndef USE_ENTERPRISE OperationResult transaction::Methods::truncateCoordinator(std::string const& collectionName, OperationOptions& options) { - return OperationResult( - arangodb::truncateCollectionOnCoordinator(vocbase().name(), collectionName)); + return OperationResult(arangodb::truncateCollectionOnCoordinator(*this, collectionName)); } #endif @@ -2696,7 +2696,7 @@ OperationResult transaction::Methods::countCoordinatorHelper( if (documents == CountCache::NotPopulated) { // no cache hit, or detailed results requested std::vector> count; - auto res = arangodb::countOnCoordinator(vocbase().name(), collectionName, *this, count); + auto res = arangodb::countOnCoordinator(*this, collectionName, count); if (res != TRI_ERROR_NO_ERROR) { return OperationResult(res); @@ -2917,8 +2917,7 @@ bool transaction::Methods::getIndexForSortCondition( /// calling this method std::unique_ptr transaction::Methods::indexScanForCondition( IndexHandle const& indexId, arangodb::aql::AstNode const* condition, - arangodb::aql::Variable const* var, - IndexIteratorOptions const& opts) { + arangodb::aql::Variable const* var, IndexIteratorOptions const& opts) { if (_state->isCoordinator()) { // The index scan is only available on DBServers and Single Server. THROW_ARANGO_EXCEPTION(TRI_ERROR_CLUSTER_ONLY_ON_DBSERVER); @@ -2970,7 +2969,7 @@ std::unique_ptr transaction::Methods::indexScan(std::string const } } - // the above methods must always return a valid iterator or throw! + // the above methods must always return a valid iterator or throw! TRI_ASSERT(iterator != nullptr); return iterator; } @@ -3153,14 +3152,11 @@ std::vector> transaction::Methods::indexesForCollection( LogicalCollection* document = documentCollection(trxCollection(cid)); std::vector> indexes = document->getIndexes(); if (!withHidden) { - auto it = indexes.begin(); - while (it != indexes.end()) { - if ((*it)->isHidden()) { - it = indexes.erase(it); - } else { - it++; - } - } + indexes.erase(std::remove_if(indexes.begin(), indexes.end(), + [](std::shared_ptr x) { + return x->isHidden(); + }), + indexes.end()); } return indexes; } @@ -3287,14 +3283,15 @@ Result Methods::replicateOperations(LogicalCollection const& collection, VPackBuilder& resultBuilder) { TRI_ASSERT(followers != nullptr); + Result res; if (followers->empty()) { - return Result{}; + return res; } // nullptr only happens on controlled shutdown auto cc = arangodb::ClusterComm::instance(); if (cc == nullptr) { - return Result{}; + return res.reset(TRI_ERROR_SHUTTING_DOWN); }; // path and requestType are different for insert/remove/modify. @@ -3371,7 +3368,7 @@ Result Methods::replicateOperations(LogicalCollection const& collection, if (count == 0) { // nothing to do - return Result{}; + return res; } auto body = std::make_shared(); @@ -3430,8 +3427,8 @@ Result Methods::replicateOperations(LogicalCollection const& collection, } if (findRefusal(requests)) { - return Result{TRI_ERROR_CLUSTER_SHARD_LEADER_RESIGNED}; + return res.reset(TRI_ERROR_CLUSTER_SHARD_LEADER_RESIGNED); } - return Result{}; + return res; } diff --git a/arangod/Transaction/Methods.h b/arangod/Transaction/Methods.h index 5485a0a697..fea5f475bc 100644 --- a/arangod/Transaction/Methods.h +++ b/arangod/Transaction/Methods.h @@ -50,7 +50,6 @@ namespace arangodb { namespace basics { struct AttributeName; -class StringBuffer; } // namespace basics namespace velocypack { @@ -199,9 +198,6 @@ class Methods { /// @brief add a transaction hint void addHint(transaction::Hints::Hint hint) { _localHints.set(hint); } - bool hasHint(transaction::Hints::Hint hint) const { - return _localHints.has(hint); - } /// @brief whether or not the transaction consists of a single operation only bool isSingleOperationTransaction() const; @@ -363,15 +359,17 @@ class Methods { /// @brief Gets the best fitting index for an AQL sort condition /// note: the caller must have read-locked the underlying collection when /// calling this method - ENTERPRISE_VIRT bool getIndexForSortCondition( - std::string const&, arangodb::aql::SortCondition const*, - arangodb::aql::Variable const*, size_t, std::vector&, - size_t& coveredAttributes); + ENTERPRISE_VIRT bool getIndexForSortCondition(std::string const&, + arangodb::aql::SortCondition const*, + arangodb::aql::Variable const*, + size_t, std::vector&, + size_t& coveredAttributes); /// @brief factory for IndexIterator objects from AQL /// note: the caller must have read-locked the underlying collection when /// calling this method - std::unique_ptr indexScanForCondition(IndexHandle const&, arangodb::aql::AstNode const*, + std::unique_ptr indexScanForCondition(IndexHandle const&, + arangodb::aql::AstNode const*, arangodb::aql::Variable const*, IndexIteratorOptions const&); diff --git a/arangod/Transaction/SmartContext.cpp b/arangod/Transaction/SmartContext.cpp index 2c83bf0b68..159b39f9a0 100644 --- a/arangod/Transaction/SmartContext.cpp +++ b/arangod/Transaction/SmartContext.cpp @@ -21,8 +21,6 @@ //////////////////////////////////////////////////////////////////////////////// #include "SmartContext.h" -#include "StorageEngine/TransactionManager.h" -#include "StorageEngine/TransactionState.h" #include "Utils/CollectionNameResolver.h" struct TRI_vocbase_t; diff --git a/arangod/Transaction/StandaloneContext.h b/arangod/Transaction/StandaloneContext.h index 7cdf9ceca5..767671e79a 100644 --- a/arangod/Transaction/StandaloneContext.h +++ b/arangod/Transaction/StandaloneContext.h @@ -24,8 +24,9 @@ #ifndef ARANGOD_TRANSACTION_STANDALONE_CONTEXT_H #define ARANGOD_TRANSACTION_STANDALONE_CONTEXT_H 1 -#include "Basics/Common.h" #include "Context.h" + +#include "Basics/Common.h" #include "VocBase/vocbase.h" struct TRI_vocbase_t; diff --git a/arangod/Transaction/Status.cpp b/arangod/Transaction/Status.cpp index 8152486a07..801675630f 100644 --- a/arangod/Transaction/Status.cpp +++ b/arangod/Transaction/Status.cpp @@ -25,7 +25,26 @@ #include -using namespace arangodb::transaction; +namespace arangodb { +namespace transaction { +Status statusFromString(char const* str, size_t len) { + if (len == 9 && memcmp(str, "undefined", len) == 0) { + return Status::UNDEFINED; + } else if (len == 7 && memcmp(str, "created", len) == 0) { + return Status::CREATED; + } else if (len == 7 && memcmp(str, "running", len) == 0) { + return Status::RUNNING; + } else if (len == 9 && memcmp(str, "committed", len) == 0) { + return Status::COMMITTED; + } else if (len == 7 && memcmp(str, "aborted", len) == 0) { + return Status::ABORTED; + } + + TRI_ASSERT(false); + return Status::UNDEFINED; +} +} // namespace transaction +} // namespace arangodb std::ostream& operator<<(std::ostream& stream, arangodb::transaction::Status const& s) { stream << arangodb::transaction::statusString(s); diff --git a/arangod/Transaction/Status.h b/arangod/Transaction/Status.h index 914d7a426e..8a61c9a90d 100644 --- a/arangod/Transaction/Status.h +++ b/arangod/Transaction/Status.h @@ -59,6 +59,8 @@ static inline char const* statusString(Status status) { return "unknown"; } +Status statusFromString(char const* str, size_t len); + } // namespace transaction } // namespace arangodb diff --git a/arangod/Transaction/V8Context.cpp b/arangod/Transaction/V8Context.cpp index f4d08918ac..ea1b20d8d7 100644 --- a/arangod/Transaction/V8Context.cpp +++ b/arangod/Transaction/V8Context.cpp @@ -22,6 +22,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "V8Context.h" + #include "StorageEngine/TransactionState.h" #include "Transaction/StandaloneContext.h" #include "Utils/CollectionNameResolver.h" diff --git a/arangod/Transaction/V8Context.h b/arangod/Transaction/V8Context.h index 7121cc0389..3c2c6a507b 100644 --- a/arangod/Transaction/V8Context.h +++ b/arangod/Transaction/V8Context.h @@ -97,4 +97,4 @@ class V8Context final : public Context { } // namespace transaction } // namespace arangodb -#endif \ No newline at end of file +#endif diff --git a/arangod/V8Server/V8DealerFeature.cpp b/arangod/V8Server/V8DealerFeature.cpp index 9642224f74..264a714f2d 100644 --- a/arangod/V8Server/V8DealerFeature.cpp +++ b/arangod/V8Server/V8DealerFeature.cpp @@ -182,7 +182,7 @@ void V8DealerFeature::validateOptions(std::shared_ptr options) { ProgramOptions::ProcessingResult const& result = options->processingResult(); // DBServer and Agent don't need JS. Agent role handled in AgencyFeature - if (ServerState::instance()->getRole() == ServerState::RoleEnum::ROLE_PRIMARY && + if (ServerState::instance()->getRole() == ServerState::RoleEnum::ROLE_DBSERVER && (!result.touched("console") || !*(options->get("console")->ptr))) { // specifiying --console requires JavaScript, so we can only turn it off diff --git a/lib/Basics/ReadWriteSpinLock.h b/lib/Basics/ReadWriteSpinLock.h index 3f473449ed..a4cd10514b 100644 --- a/lib/Basics/ReadWriteSpinLock.h +++ b/lib/Basics/ReadWriteSpinLock.h @@ -121,6 +121,7 @@ class ReadWriteSpinLock { void writeUnlock() { unlockWrite(); } void unlockWrite() { + TRI_ASSERT(isWriteLocked()); _state.fetch_sub(WRITE_LOCK, std::memory_order_release); } diff --git a/tests/Aql/RestAqlHandlerTest.cpp b/tests/Aql/RestAqlHandlerTest.cpp index d878a09674..5a98003142 100644 --- a/tests/Aql/RestAqlHandlerTest.cpp +++ b/tests/Aql/RestAqlHandlerTest.cpp @@ -80,7 +80,7 @@ class FakeResponse : public GeneralResponse { SCENARIO("Successful query setup", "[aql][restaqlhandler]") { // We always work on DBServer - ServerState::instance()->setRole(ServerState::ROLE_PRIMARY); + ServerState::instance()->setRole(ServerState::ROLE_DBSERVER); auto body = std::make_shared(); std::string dbName = "UnitTestDB"; diff --git a/tests/IResearch/IResearchFeature-test.cpp b/tests/IResearch/IResearchFeature-test.cpp index b9d82dfe28..be18c6971d 100644 --- a/tests/IResearch/IResearchFeature-test.cpp +++ b/tests/IResearch/IResearchFeature-test.cpp @@ -492,7 +492,7 @@ SECTION("test_upgrade0_1") { auto versionJson = arangodb::velocypack::Parser::fromJson("{ \"version\": 0, \"tasks\": {} }"); auto serverRoleBefore = arangodb::ServerState::instance()->getRole(); - arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_PRIMARY); + arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_DBSERVER); auto serverRoleRestore = irs::make_finally([&serverRoleBefore]()->void { arangodb::ServerState::instance()->setRole(serverRoleBefore); }); // create a new instance of an ApplicationServer and fill it with the required features @@ -572,7 +572,7 @@ SECTION("test_upgrade0_1") { auto versionJson = arangodb::velocypack::Parser::fromJson("{ \"version\": 0, \"tasks\": {} }"); auto serverRoleBefore = arangodb::ServerState::instance()->getRole(); - arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_PRIMARY); + arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_DBSERVER); auto serverRoleRestore = irs::make_finally([&serverRoleBefore]()->void { arangodb::ServerState::instance()->setRole(serverRoleBefore); }); // create a new instance of an ApplicationServer and fill it with the required features diff --git a/tests/IResearch/IResearchView-test.cpp b/tests/IResearch/IResearchView-test.cpp index 7fc0a9d888..3d39491b9e 100644 --- a/tests/IResearch/IResearchView-test.cpp +++ b/tests/IResearch/IResearchView-test.cpp @@ -5221,9 +5221,9 @@ SECTION("test_update_partial") { "{ \"links\": { \"testCollection\": {} } }" ); - auto before = StorageEngineMock::inRecoveryResult; + auto beforeRec = StorageEngineMock::inRecoveryResult; StorageEngineMock::inRecoveryResult = true; - auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); + auto restore = irs::make_finally([&beforeRec]()->void { StorageEngineMock::inRecoveryResult = beforeRec; }); persisted = false; CHECK((view->properties(updateJson->slice(), true).ok())); CHECK((false == persisted)); @@ -6415,4 +6415,4 @@ SECTION("test_update_partial") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/IResearch/IResearchViewDBServer-test.cpp b/tests/IResearch/IResearchViewDBServer-test.cpp index d5967c72a7..73dd0b1e8c 100644 --- a/tests/IResearch/IResearchViewDBServer-test.cpp +++ b/tests/IResearch/IResearchViewDBServer-test.cpp @@ -88,7 +88,7 @@ struct IResearchViewDBServerSetup { agency = agencyCommManager->addConnection(_agencyStore); // need 2 connections or Agency callbacks will fail arangodb::AgencyCommManager::MANAGER.reset(agencyCommManager); - arangodb::ServerState::instance()->setRole(arangodb::ServerState::RoleEnum::ROLE_PRIMARY); + arangodb::ServerState::instance()->setRole(arangodb::ServerState::RoleEnum::ROLE_DBSERVER); arangodb::EngineSelectorFeature::ENGINE = &engine; // suppress INFO {authentication} Authentication is turned on (system only), authentication for unix sockets is turned on @@ -1510,4 +1510,4 @@ SECTION("test_visitCollections") { // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- diff --git a/tests/Mocks/StorageEngineMock.cpp b/tests/Mocks/StorageEngineMock.cpp index 3cbe497a4f..b2c3a4ad39 100644 --- a/tests/Mocks/StorageEngineMock.cpp +++ b/tests/Mocks/StorageEngineMock.cpp @@ -37,8 +37,8 @@ #include "Indexes/SimpleAttributeEqualityMatcher.h" #include "RestServer/FlushFeature.h" #include "StorageEngine/EngineSelectorFeature.h" -#include "StorageEngine/TransactionManager.h" #include "Transaction/Helpers.h" +#include "Transaction/Manager.h" #include "Transaction/Methods.h" #include "Transaction/StandaloneContext.h" #include "Utils/OperationOptions.h" @@ -434,16 +434,6 @@ struct IndexFactoryMock : arangodb::IndexFactory { } // namespace -void ContextDataMock::pinData(arangodb::LogicalCollection* collection) { - if (collection) { - pinned.emplace(collection->id()); - } -} - -bool ContextDataMock::isPinned(TRI_voc_cid_t cid) const { - return pinned.find(cid) != pinned.end(); -} - std::function PhysicalCollectionMock::before = []() -> void {}; PhysicalCollectionMock::PhysicalCollectionMock(arangodb::LogicalCollection& collection, @@ -1061,18 +1051,22 @@ std::unique_ptr StorageEngineMock::createTransa } std::unique_ptr StorageEngineMock::createTransactionContextData() { - before(); - return std::unique_ptr(new ContextDataMock()); + return std::unique_ptr(); } -std::unique_ptr StorageEngineMock::createTransactionManager() { +std::unique_ptr StorageEngineMock::createTransactionManager() { TRI_ASSERT(false); return nullptr; } std::unique_ptr StorageEngineMock::createTransactionState( - TRI_vocbase_t& vocbase, arangodb::transaction::Options const& options) { - return std::unique_ptr(new TransactionStateMock(vocbase, options)); + TRI_vocbase_t& vocbase, + TRI_voc_tid_t tid, + arangodb::transaction::Options const& options +) { + return std::unique_ptr( + new TransactionStateMock(vocbase, options) + ); } arangodb::Result StorageEngineMock::createView(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, @@ -1443,9 +1437,9 @@ TransactionStateMock::TransactionStateMock(TRI_vocbase_t& vocbase, arangodb::Result TransactionStateMock::abortTransaction(arangodb::transaction::Methods* trx) { ++abortTransactionCount; updateStatus(arangodb::transaction::Status::ABORTED); - unuseCollections(_nestingLevel); - const_cast(_id) = - 0; // avoid use of TransactionManagerFeature::manager()->unregisterTransaction(...) + unuseCollections(nestingLevel()); + // avoid use of TransactionManagerFeature::manager()->unregisterTransaction(...) + const_cast(_id) = 0; return arangodb::Result(); } @@ -1455,7 +1449,7 @@ arangodb::Result TransactionStateMock::beginTransaction(arangodb::transaction::H ++beginTransactionCount; _hints = hints; - auto res = useCollections(_nestingLevel); + auto res = useCollections(nestingLevel()); if (!res.ok()) { updateStatus(arangodb::transaction::Status::ABORTED); @@ -1474,9 +1468,9 @@ arangodb::Result TransactionStateMock::beginTransaction(arangodb::transaction::H arangodb::Result TransactionStateMock::commitTransaction(arangodb::transaction::Methods* trx) { ++commitTransactionCount; updateStatus(arangodb::transaction::Status::COMMITTED); - unuseCollections(_nestingLevel); - const_cast(_id) = - 0; // avoid use of TransactionManagerFeature::manager()->unregisterTransaction(...) + unuseCollections(nestingLevel()); + // avoid use of TransactionManagerFeature::manager()->unregisterTransaction(...) + const_cast(_id) = 0; return arangodb::Result(); } diff --git a/tests/Mocks/StorageEngineMock.h b/tests/Mocks/StorageEngineMock.h index 41919d5abf..9556f9efce 100644 --- a/tests/Mocks/StorageEngineMock.h +++ b/tests/Mocks/StorageEngineMock.h @@ -43,14 +43,6 @@ class WalAccess; } // arangodb -class ContextDataMock: public arangodb::transaction::ContextData { - public: - std::set pinned; - - void pinData(arangodb::LogicalCollection* collection) override; - bool isPinned(TRI_voc_cid_t cid) const override; -}; - class PhysicalCollectionMock: public arangodb::PhysicalCollection { public: static std::function before; @@ -183,8 +175,8 @@ class StorageEngineMock: public arangodb::StorageEngine { virtual arangodb::Result createTickRanges(VPackBuilder&) override; virtual std::unique_ptr createTransactionCollection(arangodb::TransactionState& state, TRI_voc_cid_t cid, arangodb::AccessMode::Type, int nestingLevel) override; virtual std::unique_ptr createTransactionContextData() override; - virtual std::unique_ptr createTransactionManager() override; - virtual std::unique_ptr createTransactionState(TRI_vocbase_t& vocbase, arangodb::transaction::Options const& options) override; + virtual std::unique_ptr createTransactionManager() override; + virtual std::unique_ptr createTransactionState(TRI_vocbase_t& vocbase, TRI_voc_tid_t tid, arangodb::transaction::Options const& options) override; virtual arangodb::Result createView(TRI_vocbase_t& vocbase, TRI_voc_cid_t id, arangodb::LogicalView const& view) override; virtual void getViewProperties(TRI_vocbase_t& vocbase, arangodb::LogicalView const& view, VPackBuilder& builder) override; virtual TRI_voc_tick_t currentTick() const override;