1
0
Fork 0

Refactorings from cluster trx improvement branch (#8391)

This commit is contained in:
Simon 2019-03-14 23:13:17 +01:00 committed by Jan
parent 8d649903f7
commit 49cc3bcd1e
85 changed files with 796 additions and 1189 deletions

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <numeric>
#include <vector>
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;
@ -174,32 +176,6 @@ static std::unique_ptr<std::unordered_map<std::string, std::string>> 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<std::unordered_map<std::string, std::vector<std::string>>
}
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<ShardMap> shards = collinfo->shardIds();
CoordTransactionID coordTransactionID = TRI_NewTickServer();
std::unordered_map<std::string, std::string> 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<ShardMap> shards = collinfo->shardIds();
CoordTransactionID coordTransactionID = TRI_NewTickServer();
std::unordered_map<std::string, std::string> 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<ShardMap> shards = collinfo->shardIds();
CoordTransactionID coordTransactionID = TRI_NewTickServer();
std::unordered_map<std::string, std::string> 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<std::pair<std::string, uint64_t>>& 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<LogicalCollection> collinfo;
collinfo = ci->getCollectionNT(dbname, cname);
if (collinfo == nullptr) {
return TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND;
}
auto shards = collinfo->shardIds();
std::shared_ptr<ShardMap> shards = collinfo->shardIds();
std::vector<ClusterCommRequest> requests;
auto body = std::make_shared<std::string>();
for (auto const& p : *shards) {
for (std::pair<ShardID, std::vector<ServerID>> 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<ShardMap> shards = collinfo->shardIds();
std::vector<ClusterCommRequest> requests;
std::string requestsUrl;
auto body = std::make_shared<std::string>();
@ -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<LogicalCollection> 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<ShardMap> 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<int, size_t>& 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<LogicalCollection> 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<ShardMap> 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<LogicalCollection> 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<ShardMap> shards = collinfo->shardIds();
CoordTransactionID coordTransactionID = TRI_NewTickServer();
std::unordered_map<std::string, std::string> 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<int, size_t>& 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<LogicalCollection> 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<ShardMap> 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<LogicalCollection> collinfo = ci->getCollection(dbname, collname);
std::shared_ptr<LogicalCollection> collinfo = ci->getCollectionNT(dbname, collname);
if (collinfo == nullptr) {
return TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND;
}
std::shared_ptr<std::unordered_map<std::string, std::vector<std::string>>> 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<std::unordered_map<std::string, std::string>>& headers,
arangodb::rest::ResponseCode& responseCode, std::unordered_map<int, size_t>& 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<LogicalCollection> collinfo = ci->getCollection(dbname, collname);
auto collid = std::to_string(collinfo->id());
std::shared_ptr<ShardMap> 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<int>(
resSlice, "errorNum", TRI_ERROR_INTERNAL);
if (code != TRI_ERROR_NO_ERROR) {
globalErrorCode = code;
}

View File

@ -40,12 +40,16 @@ namespace velocypack {
template <typename T>
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<std::pair<std::string, uint64_t>>& 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<int, size_t>& 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<int, size_t>& errorCounter,
std::shared_ptr<arangodb::velocypack::Builder>& 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<std::unordered_map<std::string, std::string>>& headers,
arangodb::rest::ResponseCode& responseCode, std::unordered_map<int, size_t>& 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

View File

@ -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();

View File

@ -298,3 +298,17 @@ void FollowerInfo::clear() {
auto v = std::make_shared<std::vector<ServerID>>();
_followers = v; // will cast to std::vector<ServerID> 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;
}

View File

@ -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
//////////////////////////////////////////////////////////////////////////////

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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<TransactionManager> ClusterEngine::createTransactionManager() {
return std::unique_ptr<TransactionManager>(new ClusterTransactionManager());
std::unique_ptr<transaction::Manager> ClusterEngine::createTransactionManager() {
return std::make_unique<transaction::Manager>(/*keepData*/ false);
}
std::unique_ptr<transaction::ContextData> ClusterEngine::createTransactionContextData() {
return std::unique_ptr<transaction::ContextData>(new ClusterTransactionContextData());
return std::unique_ptr<transaction::ContextData>(); // not used by coordinator
}
std::unique_ptr<TransactionState> ClusterEngine::createTransactionState(
TRI_vocbase_t& vocbase, transaction::Options const& options) {
return std::make_unique<ClusterTransactionState>(vocbase, TRI_NewTickServer(), options);
std::unique_ptr<TransactionState> ClusterEngine::createTransactionState(TRI_vocbase_t& vocbase,
TRI_voc_tid_t tid,
transaction::Options const& options) {
return std::make_unique<ClusterTransactionState>(vocbase, tid, options);
}
std::unique_ptr<TransactionCollection> ClusterEngine::createTransactionCollection(
@ -361,4 +362,4 @@ std::unique_ptr<TRI_vocbase_t> ClusterEngine::openExistingDatabase(
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -34,19 +34,6 @@
#include <velocypack/Slice.h>
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<TransactionManager> createTransactionManager() override;
std::unique_ptr<transaction::Manager> createTransactionManager() override;
std::unique_ptr<transaction::ContextData> createTransactionContextData() override;
std::unique_ptr<TransactionState> createTransactionState(TRI_vocbase_t& vocbase,
std::unique_ptr<TransactionState> createTransactionState(TRI_vocbase_t& vocbase, TRI_voc_tid_t tid,
transaction::Options const& options) override;
std::unique_ptr<TransactionCollection> createTransactionCollection(
TransactionState& state, TRI_voc_cid_t cid, AccessMode::Type accessType,
@ -272,4 +259,4 @@ class ClusterEngine final : public StorageEngine {
} // namespace arangodb
#endif
#endif

View File

@ -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 <rocksdb/utilities/transaction_db.h>
@ -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()));

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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<TRI_voc_tid_t> const& failedTransactions) override {
}
// unregister a list of failed transactions
void unregisterFailedTransactions(std::unordered_set<TRI_voc_tid_t> const& failedTransactions) override {
}
// return the set of failed transactions
std::unordered_set<TRI_voc_tid_t> getFailedTransactions() override {
return std::unordered_set<TRI_voc_tid_t>();
}
// register a transaction
void registerTransaction(TRI_voc_tid_t transactionId,
std::unique_ptr<TransactionData> 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<void(TRI_voc_tid_t, TransactionData const*)> const& callback) override {}
uint64_t getActiveTransactionCount() override { return _nrRunning; }
private:
std::atomic<uint64_t> _nrRunning;
};
} // namespace arangodb
#endif

View File

@ -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<ClusterTransactionData>());
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;
}

View File

@ -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;

View File

@ -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<arangodb::OperationCursor> 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<arangodb::OperationCursor> 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<OperationCursor>(_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<double>(
edge, _weightAttribute.c_str(), _defaultWeight);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Return name of the wrapped collection
////////////////////////////////////////////////////////////////////////////////

View File

@ -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<arangodb::OperationCursor> 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<arangodb::OperationCursor> 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; }
////////////////////////////////////////////////////////////////////////////////

View File

@ -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 <velocypack/Iterator.h>
namespace {

View File

@ -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

View File

@ -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<void*>(&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;

View File

@ -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) {

View File

@ -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<TransactionManager> MMFilesEngine::createTransactionManager() {
return std::unique_ptr<TransactionManager>(new MMFilesTransactionManager());
std::unique_ptr<transaction::Manager> MMFilesEngine::createTransactionManager() {
return std::make_unique<transaction::Manager>(/*keepData*/ true);
}
std::unique_ptr<transaction::ContextData> MMFilesEngine::createTransactionContextData() {
return std::unique_ptr<transaction::ContextData>(new MMFilesTransactionContextData());
return std::make_unique<MMFilesTransactionContextData>();
}
std::unique_ptr<TransactionState> MMFilesEngine::createTransactionState(
TRI_vocbase_t& vocbase, transaction::Options const& options) {
return std::unique_ptr<TransactionState>(
new MMFilesTransactionState(vocbase, TRI_NewTickServer(), options));
TRI_vocbase_t& vocbase, TRI_voc_tick_t tid, transaction::Options const& options) {
return std::make_unique<MMFilesTransactionState>(vocbase, tid, options);
}
std::unique_ptr<TransactionCollection> MMFilesEngine::createTransactionCollection(
@ -301,7 +300,6 @@ std::unique_ptr<TransactionCollection> MMFilesEngine::createTransactionCollectio
std::unique_ptr<PhysicalCollection> MMFilesEngine::createPhysicalCollection(
LogicalCollection& collection, velocypack::Slice const& info) {
TRI_ASSERT(EngineSelectorFeature::ENGINE == this);
return std::unique_ptr<PhysicalCollection>(new MMFilesCollection(collection, info));
}

View File

@ -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<VPackBuilder>& builderSPtr) override;
WalAccess const* walAccess() const override;
std::unique_ptr<TransactionManager> createTransactionManager() override;
std::unique_ptr<transaction::Manager> createTransactionManager() override;
std::unique_ptr<transaction::ContextData> createTransactionContextData() override;
std::unique_ptr<TransactionState> createTransactionState(TRI_vocbase_t& vocbase,
transaction::Options const& options) override;
std::unique_ptr<TransactionState> createTransactionState(
TRI_vocbase_t& vocbase, TRI_voc_tick_t, transaction::Options const& options) override;
std::unique_ptr<TransactionCollection> 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
#endif

View File

@ -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) {

View File

@ -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<MMFilesTransactionData>(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<size_t, MMFilesWalLogfile::IdType, MMFilesWalLogfile::IdType> MMFiles
};
// iterate over all active transactions
TransactionManagerFeature::manager()->iterateActiveTransactions(cb);
transaction::ManagerFeature::manager()->iterateActiveTransactions(cb);
return std::tuple<size_t, MMFilesWalLogfile::IdType, MMFilesWalLogfile::IdType>(
count, lastCollectedId, lastSealedId);

View File

@ -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

View File

@ -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<MMFilesTransactionCollection*>(&collection);
if (c->canAccess(AccessMode::Type::WRITE) &&

View File

@ -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());
}

View File

@ -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()) {

View File

@ -194,8 +194,7 @@ bool RestEdgesHandler::readEdges() {
VPackBuffer<uint8_t> 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) {

View File

@ -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()) {

View File

@ -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));

View File

@ -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<int>(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<TransactionManager> RocksDBEngine::createTransactionManager() {
return std::unique_ptr<TransactionManager>(new RocksDBTransactionManager());
std::unique_ptr<transaction::Manager> RocksDBEngine::createTransactionManager() {
return std::make_unique<transaction::Manager>(/*keepData*/ false);
}
std::unique_ptr<transaction::ContextData> RocksDBEngine::createTransactionContextData() {
return std::unique_ptr<transaction::ContextData>(new RocksDBTransactionContextData());
return std::unique_ptr<transaction::ContextData>(nullptr); // not used by rocksdb
}
std::unique_ptr<TransactionState> RocksDBEngine::createTransactionState(
TRI_vocbase_t& vocbase, transaction::Options const& options) {
return std::unique_ptr<TransactionState>(
new RocksDBTransactionState(vocbase, TRI_NewTickServer(), options));
TRI_vocbase_t& vocbase, TRI_voc_tid_t tid, transaction::Options const& options) {
return std::make_unique<RocksDBTransactionState>(vocbase, tid, options);
}
std::unique_ptr<TransactionCollection> RocksDBEngine::createTransactionCollection(

View File

@ -149,10 +149,10 @@ class RocksDBEngine final : public StorageEngine {
bool supportsDfdb() const override { return false; }
bool useRawDocumentPointers() override { return false; }
std::unique_ptr<TransactionManager> createTransactionManager() override;
std::unique_ptr<transaction::Manager> createTransactionManager() override;
std::unique_ptr<transaction::ContextData> createTransactionContextData() override;
std::unique_ptr<TransactionState> createTransactionState(TRI_vocbase_t& vocbase,
transaction::Options const& options) override;
std::unique_ptr<TransactionState> createTransactionState(
TRI_vocbase_t& vocbase, TRI_voc_tid_t, transaction::Options const& options) override;
std::unique_ptr<TransactionCollection> createTransactionCollection(
TransactionState& state, TRI_voc_cid_t cid, AccessMode::Type accessType,
int nestingLevel) override;

View File

@ -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) {

View File

@ -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<char>(_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<char>(_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<char>(_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<char>(_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<size_t>(indexValues.byteSize());
size_t keyLength = 2 * sizeof(uint64_t) + byteSize;
_buffer.clear();
_buffer.reserve(keyLength);
uint64ToPersistent(_buffer, indexId);
_buffer.append(reinterpret_cast<char const*>(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<char const*>(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<size_t>(indexValues.byteSize());
size_t keyLength = sizeof(uint64_t) + byteSize;
_buffer.clear();
_buffer.reserve(keyLength);
uint64ToPersistent(_buffer, indexId);
_buffer.append(reinterpret_cast<char const*>(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<char const*>(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<uint64_t>(_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<uint64_t>(*_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<char>(_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<char>(_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<char>(_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<char>(_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<char>(_type));
_buffer.push_back(static_cast<char>(st));
TRI_ASSERT(_buffer.size() == keyLength);
_slice = rocksdb::Slice(_buffer.data(), keyLength);
_buffer->clear();
_buffer->reserve(keyLength);
_buffer->push_back(static_cast<char>(_type));
_buffer->push_back(static_cast<char>(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<char>(_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<char>(_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<char>(_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<char>(_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<char>(_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<char>(_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) {

View File

@ -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<RocksDBEntryType>(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&);

View File

@ -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"

View File

@ -48,6 +48,9 @@ class Snapshot;
} // namespace rocksdb
namespace arangodb {
namespace basics {
class StringBuffer;
}
class RocksDBReplicationContext {
private:

View File

@ -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 <rocksdb/utilities/transaction_db.h>
@ -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()));

View File

@ -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

View File

@ -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<TRI_voc_tid_t> const& failedTransactions) override {
}
// unregister a list of failed transactions
void unregisterFailedTransactions(std::unordered_set<TRI_voc_tid_t> const& failedTransactions) override {
}
// return the set of failed transactions
std::unordered_set<TRI_voc_tid_t> getFailedTransactions() override {
return std::unordered_set<TRI_voc_tid_t>();
}
// register a transaction
void registerTransaction(TRI_voc_tid_t transactionId,
std::unique_ptr<TransactionData> 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<void(TRI_voc_tid_t, TransactionData const*)> const& callback) override {}
uint64_t getActiveTransactionCount() override { return _nrRunning; }
private:
std::atomic<uint64_t> _nrRunning;
};
} // namespace arangodb
#endif

View File

@ -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<RocksDBTransactionData>());
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());
}
}

View File

@ -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<RocksDBKey*, 32>::allocator_type::arena_type _arena;
SmallVector<RocksDBKey*, 32> _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

View File

@ -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();

View File

@ -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<TransactionManager> createTransactionManager() = 0;
virtual std::unique_ptr<transaction::Manager> createTransactionManager() = 0;
virtual std::unique_ptr<transaction::ContextData> createTransactionContextData() = 0;
virtual std::unique_ptr<TransactionState> 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<TransactionCollection> createTransactionCollection(
TransactionState& state, TRI_voc_cid_t cid, AccessMode::Type accessType,
int nestingLevel) = 0;

View File

@ -54,7 +54,7 @@ class TransactionCollection {
inline TRI_voc_cid_t id() const { return _cid; }
std::shared_ptr<LogicalCollection> const& collection() const {
return _collection; // vocbase collection pointer
return _collection; // vocbase collection pointer
}
std::string collectionName() const;

View File

@ -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<TRI_voc_tid_t> const& failedTransactions) = 0;
// unregister a list of failed transactions
virtual void unregisterFailedTransactions(std::unordered_set<TRI_voc_tid_t> const& failedTransactions) = 0;
// return the set of failed transactions
virtual std::unordered_set<TRI_voc_tid_t> getFailedTransactions() = 0;
// register a transaction
virtual void registerTransaction(TRI_voc_tid_t transactionId,
std::unique_ptr<TransactionData> 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<void(TRI_voc_tid_t, TransactionData const*)> const& callback) = 0;
virtual uint64_t getActiveTransactionCount() = 0;
};
} // namespace arangodb
#endif

View File

@ -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<bool(TransactionCollection&)> const& cb // callback to invoke
void TransactionState::allCollections( // iterate
std::function<bool(TransactionCollection&)> 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<std::string> 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());
}

View File

@ -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<TransactionCollection*>::allocator_type::arena_type _arena; // memory for collections
SmallVector<TransactionCollection*> _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<std::string> _lockedShards;
/// @brief reference counter of # of 'Methods' instances using this object
int _nestingLevel;
bool _registeredTransaction;
};
} // namespace arangodb

View File

@ -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();
}

View File

@ -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<arangodb::velocypack::CustomTypeHandler> 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<velocypack::CustomTypeHandler> _customTypeHandler;
@ -131,16 +141,17 @@ class Context {
SmallVector<arangodb::velocypack::Builder*, 32> _builders;
std::unique_ptr<arangodb::basics::StringBuffer> _stringBuffer;
std::unique_ptr<std::string> _stdString;
arangodb::velocypack::Options _options;
arangodb::velocypack::Options _dumpOptions;
private:
std::unique_ptr<transaction::ContextData> _contextData;
struct {
TRI_voc_tid_t id;
bool hasFailedOperations;
bool wasRegistered;
} _transaction;
bool _ownsResolver;

View File

@ -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;

View File

@ -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()),

View File

@ -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*);

View File

@ -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 <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>
namespace arangodb {
namespace transaction {
// register a list of failed transactions
void MMFilesTransactionManager::registerFailedTransactions(
std::unordered_set<TRI_voc_tid_t> const& failedTransactions) {
void Manager::registerFailedTransactions(std::unordered_set<TRI_voc_tid_t> 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<TRI_voc_tid_t> const& failedTransactions) {
void Manager::unregisterFailedTransactions(std::unordered_set<TRI_voc_tid_t> 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<TransactionData> data) {
TRI_ASSERT(data != nullptr);
void Manager::registerTransaction(TRI_voc_tid_t transactionId,
std::unique_ptr<TransactionData> 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<TRI_voc_tid_t> MMFilesTransactionManager::getFailedTransactions() {
std::unordered_set<TRI_voc_tid_t> Manager::getFailedTransactions() const {
std::unordered_set<TRI_voc_tid_t> failedTransactions;
{
@ -102,8 +120,11 @@ std::unordered_set<TRI_voc_tid_t> MMFilesTransactionManager::getFailedTransactio
return failedTransactions;
}
void MMFilesTransactionManager::iterateActiveTransactions(
void Manager::iterateActiveTransactions(
std::function<void(TRI_voc_tid_t, TransactionData const*)> 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

View File

@ -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 <atomic>
#include <vector>
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<void(TRI_voc_tid_t, TransactionData const*)> TrxCallback;
public:
// register a list of failed transactions
void registerFailedTransactions(std::unordered_set<TRI_voc_tid_t> const& failedTransactions) override;
void registerFailedTransactions(std::unordered_set<TRI_voc_tid_t> const& failedTransactions);
// unregister a list of failed transactions
void unregisterFailedTransactions(std::unordered_set<TRI_voc_tid_t> const& failedTransactions) override;
void unregisterFailedTransactions(std::unordered_set<TRI_voc_tid_t> const& failedTransactions);
// return the set of failed transactions
std::unordered_set<TRI_voc_tid_t> getFailedTransactions() override;
std::unordered_set<TRI_voc_tid_t> getFailedTransactions() const;
// register a transaction
void registerTransaction(TRI_voc_tid_t transactionId,
std::unique_ptr<TransactionData> data) override;
void registerTransaction(TRI_voc_tid_t, std::unique_ptr<TransactionData> 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<void(TRI_voc_tid_t, TransactionData const*)> 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<TRI_voc_cid_t>()(id) % numBuckets;
inline size_t getBucket(TRI_voc_tid_t tid) const {
return std::hash<TRI_voc_cid_t>()(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<TRI_voc_tid_t, std::unique_ptr<TransactionData>> _activeTransactions;
@ -79,8 +99,11 @@ class MMFilesTransactionManager final : public TransactionManager {
// set of failed transactions
std::unordered_set<TRI_voc_tid_t> _failedTransactions;
} _transactions[numBuckets];
};
/// Nr of running transactions
std::atomic<uint64_t> _nrRunning;
};
} // namespace transaction
} // namespace arangodb
#endif

View File

@ -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<TransactionManager> TransactionManagerFeature::MANAGER;
std::unique_ptr<transaction::Manager> 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

View File

@ -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<TransactionManager> MANAGER;
static std::unique_ptr<transaction::Manager> MANAGER;
};
} // namespace transaction
} // namespace arangodb
#endif
#endif

View File

@ -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<arangodb::aql::ConditionPart> parts;
parts.reserve(n);
std::pair<arangodb::aql::Variable const*, std::vector<arangodb::basics::AttributeName>> 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<ConditionData*>(parts[previousIn].data)->first = clone;
clone = ast->clone(root->getMember(i));
root->changeMember(i, clone);
static_cast<ConditionData*>(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<transaction::Context> const& trans
}
_state = parent;
TRI_ASSERT(_state != nullptr);
_state->increaseNesting();
} else { // non-embedded
@ -772,10 +772,10 @@ transaction::Methods::Methods(std::shared_ptr<transaction::Context> 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<transaction::Context> 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<int, size_t> errorCounter;
auto resultBody = std::make_shared<VPackBuilder>();
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<Result(void)> 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<int, size_t> errorCounter;
auto resultBody = std::make_shared<VPackBuilder>();
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<int, size_t> errorCounter;
auto resultBody = std::make_shared<VPackBuilder>();
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<int, size_t> errorCounter;
auto resultBody = std::make_shared<VPackBuilder>();
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<std::pair<std::string, uint64_t>> 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<IndexIterator> 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<IndexIterator> 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<std::shared_ptr<Index>> transaction::Methods::indexesForCollection(
LogicalCollection* document = documentCollection(trxCollection(cid));
std::vector<std::shared_ptr<Index>> 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<Index> 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<std::string>();
@ -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;
}

View File

@ -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<IndexHandle>&,
size_t& coveredAttributes);
ENTERPRISE_VIRT bool getIndexForSortCondition(std::string const&,
arangodb::aql::SortCondition const*,
arangodb::aql::Variable const*,
size_t, std::vector<IndexHandle>&,
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<IndexIterator> indexScanForCondition(IndexHandle const&, arangodb::aql::AstNode const*,
std::unique_ptr<IndexIterator> indexScanForCondition(IndexHandle const&,
arangodb::aql::AstNode const*,
arangodb::aql::Variable const*,
IndexIteratorOptions const&);

View File

@ -21,8 +21,6 @@
////////////////////////////////////////////////////////////////////////////////
#include "SmartContext.h"
#include "StorageEngine/TransactionManager.h"
#include "StorageEngine/TransactionState.h"
#include "Utils/CollectionNameResolver.h"
struct TRI_vocbase_t;

View File

@ -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;

View File

@ -25,7 +25,26 @@
#include <iostream>
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);

View File

@ -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

View File

@ -22,6 +22,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "V8Context.h"
#include "StorageEngine/TransactionState.h"
#include "Transaction/StandaloneContext.h"
#include "Utils/CollectionNameResolver.h"

View File

@ -97,4 +97,4 @@ class V8Context final : public Context {
} // namespace transaction
} // namespace arangodb
#endif
#endif

View File

@ -182,7 +182,7 @@ void V8DealerFeature::validateOptions(std::shared_ptr<ProgramOptions> 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<BooleanParameter>("console")->ptr))) {
// specifiying --console requires JavaScript, so we can only turn it off

View File

@ -121,6 +121,7 @@ class ReadWriteSpinLock {
void writeUnlock() { unlockWrite(); }
void unlockWrite() {
TRI_ASSERT(isWriteLocked());
_state.fetch_sub(WRITE_LOCK, std::memory_order_release);
}

View File

@ -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<VPackBuilder>();
std::string dbName = "UnitTestDB";

View File

@ -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

View File

@ -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
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -88,7 +88,7 @@ struct IResearchViewDBServerSetup {
agency = agencyCommManager->addConnection<GeneralClientConnectionAgencyMock>(_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
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -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<void()> PhysicalCollectionMock::before = []() -> void {};
PhysicalCollectionMock::PhysicalCollectionMock(arangodb::LogicalCollection& collection,
@ -1061,18 +1051,22 @@ std::unique_ptr<arangodb::TransactionCollection> StorageEngineMock::createTransa
}
std::unique_ptr<arangodb::transaction::ContextData> StorageEngineMock::createTransactionContextData() {
before();
return std::unique_ptr<arangodb::transaction::ContextData>(new ContextDataMock());
return std::unique_ptr<arangodb::transaction::ContextData>();
}
std::unique_ptr<arangodb::TransactionManager> StorageEngineMock::createTransactionManager() {
std::unique_ptr<arangodb::transaction::Manager> StorageEngineMock::createTransactionManager() {
TRI_ASSERT(false);
return nullptr;
}
std::unique_ptr<arangodb::TransactionState> StorageEngineMock::createTransactionState(
TRI_vocbase_t& vocbase, arangodb::transaction::Options const& options) {
return std::unique_ptr<arangodb::TransactionState>(new TransactionStateMock(vocbase, options));
TRI_vocbase_t& vocbase,
TRI_voc_tid_t tid,
arangodb::transaction::Options const& options
) {
return std::unique_ptr<arangodb::TransactionState>(
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<TRI_voc_tid_t&>(_id) =
0; // avoid use of TransactionManagerFeature::manager()->unregisterTransaction(...)
unuseCollections(nestingLevel());
// avoid use of TransactionManagerFeature::manager()->unregisterTransaction(...)
const_cast<TRI_voc_tid_t&>(_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<TRI_voc_tid_t&>(_id) =
0; // avoid use of TransactionManagerFeature::manager()->unregisterTransaction(...)
unuseCollections(nestingLevel());
// avoid use of TransactionManagerFeature::manager()->unregisterTransaction(...)
const_cast<TRI_voc_tid_t&>(_id) = 0;
return arangodb::Result();
}

View File

@ -43,14 +43,6 @@ class WalAccess;
} // arangodb
class ContextDataMock: public arangodb::transaction::ContextData {
public:
std::set<TRI_voc_cid_t> 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<void()> before;
@ -183,8 +175,8 @@ class StorageEngineMock: public arangodb::StorageEngine {
virtual arangodb::Result createTickRanges(VPackBuilder&) override;
virtual std::unique_ptr<arangodb::TransactionCollection> createTransactionCollection(arangodb::TransactionState& state, TRI_voc_cid_t cid, arangodb::AccessMode::Type, int nestingLevel) override;
virtual std::unique_ptr<arangodb::transaction::ContextData> createTransactionContextData() override;
virtual std::unique_ptr<arangodb::TransactionManager> createTransactionManager() override;
virtual std::unique_ptr<arangodb::TransactionState> createTransactionState(TRI_vocbase_t& vocbase, arangodb::transaction::Options const& options) override;
virtual std::unique_ptr<arangodb::transaction::Manager> createTransactionManager() override;
virtual std::unique_ptr<arangodb::TransactionState> 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;