//////////////////////////////////////////////////////////////////////////////// /// 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_UTILS_TRANSACTION_H #define ARANGOD_UTILS_TRANSACTION_H 1 #include "Basics/Common.h" #include "Basics/Exceptions.h" #include "Utils/OperationOptions.h" #include "Utils/OperationResult.h" #include "VocBase/transaction.h" #include "VocBase/vocbase.h" #include "VocBase/voc-types.h" #include #define TRI_DEFAULT_BATCH_SIZE 1000 namespace arangodb { namespace basics { struct AttributeName; } namespace velocypack { class Builder; } class Index; namespace aql { class Ast; struct AstNode; class SortCondition; struct Variable; } ////////////////////////////////////////////////////////////////////////////// /// @brief forward declarations ////////////////////////////////////////////////////////////////////////////// class CollectionNameResolver; class DocumentDitch; struct OperationCursor; class TransactionContext; class Transaction { public: class IndexHandle { friend class Transaction; std::shared_ptr _index; public: IndexHandle() { } void toVelocyPack(arangodb::velocypack::Builder& builder, bool withFigures) const; bool operator==(IndexHandle const& other) const { return other._index.get() == _index.get(); } bool operator!=(IndexHandle const& other) const { return other._index.get() != _index.get(); } explicit IndexHandle(std::shared_ptr idx) : _index(idx) { } private: std::shared_ptr getIndex() const; }; using VPackBuilder = arangodb::velocypack::Builder; using VPackSlice = arangodb::velocypack::Slice; ////////////////////////////////////////////////////////////////////////////// /// @brief Transaction ////////////////////////////////////////////////////////////////////////////// private: Transaction() = delete; Transaction(Transaction const&) = delete; Transaction& operator=(Transaction const&) = delete; protected: ////////////////////////////////////////////////////////////////////////////// /// @brief create the transaction ////////////////////////////////////////////////////////////////////////////// Transaction(std::shared_ptr transactionContext, TRI_voc_tid_t externalId); public: ////////////////////////////////////////////////////////////////////////////// /// @brief destroy the transaction ////////////////////////////////////////////////////////////////////////////// virtual ~Transaction(); public: ////////////////////////////////////////////////////////////////////////////// /// @brief Type of cursor ////////////////////////////////////////////////////////////////////////////// enum class CursorType { ALL = 0, ANY, INDEX }; ////////////////////////////////////////////////////////////////////////////// /// @brief return database of transaction ////////////////////////////////////////////////////////////////////////////// inline TRI_vocbase_t* vocbase() const { return _vocbase; } ////////////////////////////////////////////////////////////////////////////// /// @brief return internals of transaction ////////////////////////////////////////////////////////////////////////////// inline TRI_transaction_t* getInternals() const { return _trx; } ////////////////////////////////////////////////////////////////////////////// /// @brief return a pointer to the transaction context ////////////////////////////////////////////////////////////////////////////// std::shared_ptr transactionContext() const { return _transactionContext; } ////////////////////////////////////////////////////////////////////////////// /// @brief add a transaction hint ////////////////////////////////////////////////////////////////////////////// void inline addHint(TRI_transaction_hint_e hint, bool passthrough) { _hints |= (TRI_transaction_hint_t)hint; if (passthrough && _trx != nullptr) { _trx->_hints |= ((TRI_transaction_hint_t)hint); } } ////////////////////////////////////////////////////////////////////////////// /// @brief remove a transaction hint ////////////////////////////////////////////////////////////////////////////// void inline removeHint(TRI_transaction_hint_e hint, bool passthrough) { _hints &= ~((TRI_transaction_hint_t)hint); if (passthrough && _trx != nullptr) { _trx->_hints &= ~((TRI_transaction_hint_t)hint); } } ////////////////////////////////////////////////////////////////////////////// /// @brief return the registered error data ////////////////////////////////////////////////////////////////////////////// std::string const getErrorData() const { return _errorData; } ////////////////////////////////////////////////////////////////////////////// /// @brief return the names of all collections used in the transaction ////////////////////////////////////////////////////////////////////////////// std::vector collectionNames() const; ////////////////////////////////////////////////////////////////////////////// /// @brief return the collection name resolver ////////////////////////////////////////////////////////////////////////////// CollectionNameResolver const* resolver() const; ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not the transaction is embedded ////////////////////////////////////////////////////////////////////////////// inline bool isEmbeddedTransaction() const { return (_nestingLevel > 0); } ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not the transaction consists of a single operation only ////////////////////////////////////////////////////////////////////////////// bool isSingleOperationTransaction() const { return TRI_IsSingleOperationTransaction(this->getInternals()); } ////////////////////////////////////////////////////////////////////////////// /// @brief get the status of the transaction ////////////////////////////////////////////////////////////////////////////// inline TRI_transaction_status_e getStatus() const { if (_trx != nullptr) { return _trx->_status; } return TRI_TRANSACTION_UNDEFINED; } int nestingLevel() const { return _nestingLevel; } ////////////////////////////////////////////////////////////////////////////// /// @brief begin the transaction ////////////////////////////////////////////////////////////////////////////// int begin(); ////////////////////////////////////////////////////////////////////////////// /// @brief commit / finish the transaction ////////////////////////////////////////////////////////////////////////////// int commit(); ////////////////////////////////////////////////////////////////////////////// /// @brief abort the transaction ////////////////////////////////////////////////////////////////////////////// int abort(); ////////////////////////////////////////////////////////////////////////////// /// @brief finish a transaction (commit or abort), based on the previous state ////////////////////////////////////////////////////////////////////////////// int finish(int errorNum); ////////////////////////////////////////////////////////////////////////////// /// @brief return a collection name ////////////////////////////////////////////////////////////////////////////// std::string name(TRI_voc_cid_t cid) const { auto c = trxCollection(cid); TRI_ASSERT(c != nullptr); return c->_collection->_name; } ////////////////////////////////////////////////////////////////////////////// /// @brief order a ditch for a collection ////////////////////////////////////////////////////////////////////////////// arangodb::DocumentDitch* orderDitch(TRI_voc_cid_t); ////////////////////////////////////////////////////////////////////////////// /// @brief extract the _key attribute from a slice ////////////////////////////////////////////////////////////////////////////// static std::string extractKey(VPackSlice const); ////////////////////////////////////////////////////////////////////////////// /// @brief extract the _id attribute from a slice, and convert it into a /// string ////////////////////////////////////////////////////////////////////////////// std::string extractIdString(VPackSlice const); static std::string extractIdString(CollectionNameResolver const*, VPackSlice const&, VPackSlice const&); ////////////////////////////////////////////////////////////////////////////// /// @brief read any (random) document ////////////////////////////////////////////////////////////////////////////// OperationResult any(std::string const&); ////////////////////////////////////////////////////////////////////////////// /// @brief read many documents, using skip and limit in arbitrary order /// The result guarantees that all documents are contained exactly once /// as long as the collection is not modified. ////////////////////////////////////////////////////////////////////////////// OperationResult any(std::string const&, uint64_t, uint64_t); ////////////////////////////////////////////////////////////////////////////// /// @brief add a collection to the transaction for read, at runtime ////////////////////////////////////////////////////////////////////////////// TRI_voc_cid_t addCollectionAtRuntime(TRI_voc_cid_t cid, std::string const& collectionName, TRI_transaction_type_e type = TRI_TRANSACTION_READ) { auto collection = this->trxCollection(cid); if (collection == nullptr) { int res = TRI_AddCollectionTransaction(this->getInternals(), cid, type, this->nestingLevel(), true, true); if (res != TRI_ERROR_NO_ERROR) { THROW_ARANGO_EXCEPTION(res); } TRI_EnsureCollectionsTransaction(this->getInternals()); collection = this->trxCollection(cid); if (collection == nullptr) { THROW_ARANGO_EXCEPTION_FORMAT(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND, "'%s'", collectionName.c_str()); } } TRI_ASSERT(collection != nullptr); return cid; } ////////////////////////////////////////////////////////////////////////////// /// @brief add a collection to the transaction for read, at runtime ////////////////////////////////////////////////////////////////////////////// TRI_voc_cid_t addCollectionAtRuntime(std::string const& collectionName); ////////////////////////////////////////////////////////////////////////////// /// @brief return the type of a collection ////////////////////////////////////////////////////////////////////////////// bool isEdgeCollection(std::string const& collectionName); bool isDocumentCollection(std::string const& collectionName); TRI_col_type_t getCollectionType(std::string const& collectionName); ////////////////////////////////////////////////////////////////////////////// /// @brief return the name of a collection ////////////////////////////////////////////////////////////////////////////// std::string collectionName(TRI_voc_cid_t cid); ////////////////////////////////////////////////////////////////////////////// /// @brief return the edge index handle of collection ////////////////////////////////////////////////////////////////////////////// IndexHandle edgeIndexHandle(std::string const&); ////////////////////////////////////////////////////////////////////////////// /// @brief Iterate over all elements of the collection. ////////////////////////////////////////////////////////////////////////////// void invokeOnAllElements(std::string const& collectionName, std::function); ////////////////////////////////////////////////////////////////////////////// /// @brief return one or multiple documents from a collection ////////////////////////////////////////////////////////////////////////////// OperationResult document(std::string const& collectionName, VPackSlice const value, OperationOptions& options); ////////////////////////////////////////////////////////////////////////////// /// @brief create one or multiple documents in a collection /// the single-document variant of this operation will either succeed or, /// if it fails, clean up after itself ////////////////////////////////////////////////////////////////////////////// OperationResult insert(std::string const& collectionName, VPackSlice const value, OperationOptions const& options); ////////////////////////////////////////////////////////////////////////////// /// @brief update/patch one or multiple documents in a collection /// the single-document variant of this operation will either succeed or, /// if it fails, clean up after itself ////////////////////////////////////////////////////////////////////////////// OperationResult update(std::string const& collectionName, VPackSlice const updateValue, OperationOptions const& options); ////////////////////////////////////////////////////////////////////////////// /// @brief replace one or multiple documents in a collection /// the single-document variant of this operation will either succeed or, /// if it fails, clean up after itself ////////////////////////////////////////////////////////////////////////////// OperationResult replace(std::string const& collectionName, VPackSlice const updateValue, OperationOptions const& options); ////////////////////////////////////////////////////////////////////////////// /// @brief remove one or multiple documents in a collection /// the single-document variant of this operation will either succeed or, /// if it fails, clean up after itself ////////////////////////////////////////////////////////////////////////////// OperationResult remove(std::string const& collectionName, VPackSlice const value, OperationOptions const& options); ////////////////////////////////////////////////////////////////////////////// /// @brief fetches all documents in a collection ////////////////////////////////////////////////////////////////////////////// OperationResult all(std::string const& collectionName, uint64_t skip, uint64_t limit, OperationOptions const& options); ////////////////////////////////////////////////////////////////////////////// /// @brief remove all documents in a collection ////////////////////////////////////////////////////////////////////////////// OperationResult truncate(std::string const& collectionName, OperationOptions const& options); ////////////////////////////////////////////////////////////////////////////// /// @brief count the number of documents in a collection ////////////////////////////////////////////////////////////////////////////// OperationResult count(std::string const& collectionName); ////////////////////////////////////////////////////////////////////////////// /// @brief Gets the best fitting index for an AQL condition. /// note: the caller must have read-locked the underlying collection when /// calling this method ////////////////////////////////////////////////////////////////////////////// std::pair getBestIndexHandlesForFilterCondition( std::string const&, arangodb::aql::Ast*, arangodb::aql::AstNode*, arangodb::aql::Variable const*, arangodb::aql::SortCondition const*, size_t, std::vector&, bool&); ////////////////////////////////////////////////////////////////////////////// /// @brief Checks if the index supports the filter condition. /// note: the caller must have read-locked the underlying collection when /// calling this method ////////////////////////////////////////////////////////////////////////////// bool supportsFilterCondition(IndexHandle const&, arangodb::aql::AstNode const*, arangodb::aql::Variable const*, size_t, size_t&, double&); ////////////////////////////////////////////////////////////////////////////// /// @brief Get the index features: /// Returns the covered attributes, and sets the first bool value /// to isSorted and the second bool value to isSparse ////////////////////////////////////////////////////////////////////////////// std::vector> getIndexFeatures( IndexHandle const&, bool&, bool&); ////////////////////////////////////////////////////////////////////////////// /// @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 ////////////////////////////////////////////////////////////////////////////// std::pair getIndexForSortCondition( std::string const&, arangodb::aql::SortCondition const*, arangodb::aql::Variable const*, size_t, std::vector&, size_t& coveredAttributes); ////////////////////////////////////////////////////////////////////////////// /// @brief factory for OperationCursor objects from AQL /// note: the caller must have read-locked the underlying collection when /// calling this method ////////////////////////////////////////////////////////////////////////////// std::shared_ptr indexScanForCondition( std::string const& collectionName, IndexHandle const& indexId, arangodb::aql::Ast*, arangodb::aql::AstNode const*, arangodb::aql::Variable const*, uint64_t, uint64_t, bool); ////////////////////////////////////////////////////////////////////////////// /// @brief factory for OperationCursor objects /// note: the caller must have read-locked the underlying collection when /// calling this method ////////////////////////////////////////////////////////////////////////////// std::shared_ptr indexScan(std::string const& collectionName, CursorType cursorType, IndexHandle const& indexId, VPackSlice const search, uint64_t skip, uint64_t limit, uint64_t batchSize, bool reverse); ////////////////////////////////////////////////////////////////////////////// /// @brief test if a collection is already locked ////////////////////////////////////////////////////////////////////////////// bool isLocked(TRI_document_collection_t*, TRI_transaction_type_e); ////////////////////////////////////////////////////////////////////////////// /// @brief return the setup state ////////////////////////////////////////////////////////////////////////////// int setupState() { return _setupState; } TRI_document_collection_t* documentCollection(TRI_voc_cid_t) const; ////////////////////////////////////////////////////////////////////////////// /// @brief get the index by it's identifier. Will either throw or /// return a valid index. nullptr is impossible. ////////////////////////////////////////////////////////////////////////////// IndexHandle getIndexByIdentifier( std::string const& collectionName, std::string const& indexHandle); ////////////////////////////////////////////////////////////////////////////// /// @brief get all indexes for a collection name ////////////////////////////////////////////////////////////////////////////// std::vector> indexesForCollection( std::string const&); private: ////////////////////////////////////////////////////////////////////////////// /// @brief build a VPack object with _id, _key and _rev and possibly /// oldRef (if given), the result is added to the builder in the /// argument as a single object. ////////////////////////////////////////////////////////////////////////////// void buildDocumentIdentity(VPackBuilder& builder, TRI_voc_cid_t cid, std::string const& key, VPackSlice const rid, VPackSlice const oldRid, TRI_doc_mptr_t const* oldMptr, TRI_doc_mptr_t const* newMptr); OperationResult documentCoordinator(std::string const& collectionName, VPackSlice const value, OperationOptions& options); OperationResult documentLocal(std::string const& collectionName, VPackSlice const value, OperationOptions& options); OperationResult insertCoordinator(std::string const& collectionName, VPackSlice const value, OperationOptions& options); OperationResult insertLocal(std::string const& collectionName, VPackSlice const value, OperationOptions& options); OperationResult updateCoordinator(std::string const& collectionName, VPackSlice const newValue, OperationOptions& options); OperationResult replaceCoordinator(std::string const& collectionName, VPackSlice const newValue, OperationOptions& options); OperationResult modifyLocal(std::string const& collectionName, VPackSlice const newValue, OperationOptions& options, TRI_voc_document_operation_e operation); OperationResult removeCoordinator(std::string const& collectionName, VPackSlice const value, OperationOptions& options); OperationResult removeLocal(std::string const& collectionName, VPackSlice const value, OperationOptions& options); OperationResult allCoordinator(std::string const& collectionName, uint64_t skip, uint64_t limit, OperationOptions& options); OperationResult allLocal(std::string const& collectionName, uint64_t skip, uint64_t limit, OperationOptions& options); OperationResult anyCoordinator(std::string const& collectionName, uint64_t skip, uint64_t limit); OperationResult anyLocal(std::string const& collectionName, uint64_t skip, uint64_t limit); OperationResult truncateCoordinator(std::string const& collectionName, OperationOptions& options); OperationResult truncateLocal(std::string const& collectionName, OperationOptions& options); OperationResult countCoordinator(std::string const& collectionName); OperationResult countLocal(std::string const& collectionName); protected: ////////////////////////////////////////////////////////////////////////////// /// @brief return the transaction collection for a document collection ////////////////////////////////////////////////////////////////////////////// TRI_transaction_collection_t* trxCollection(TRI_voc_cid_t cid) const; ////////////////////////////////////////////////////////////////////////////// /// @brief return the collection ////////////////////////////////////////////////////////////////////////////// TRI_document_collection_t* documentCollection( TRI_transaction_collection_t const*) const; ////////////////////////////////////////////////////////////////////////////// /// @brief add a collection by id, with the name supplied ////////////////////////////////////////////////////////////////////////////// int addCollection(TRI_voc_cid_t, char const*, TRI_transaction_type_e); ////////////////////////////////////////////////////////////////////////////// /// @brief add a collection by id, with the name supplied ////////////////////////////////////////////////////////////////////////////// int addCollection(TRI_voc_cid_t, std::string const&, TRI_transaction_type_e); ////////////////////////////////////////////////////////////////////////////// /// @brief add a collection by id ////////////////////////////////////////////////////////////////////////////// int addCollection(TRI_voc_cid_t, TRI_transaction_type_e); ////////////////////////////////////////////////////////////////////////////// /// @brief add a collection by name ////////////////////////////////////////////////////////////////////////////// int addCollection(std::string const&, TRI_transaction_type_e); ////////////////////////////////////////////////////////////////////////////// /// @brief set the lock acquisition timeout ////////////////////////////////////////////////////////////////////////////// void setTimeout(double timeout) { _timeout = timeout; } ////////////////////////////////////////////////////////////////////////////// /// @brief set the waitForSync property ////////////////////////////////////////////////////////////////////////////// void setWaitForSync() { _waitForSync = true; } ////////////////////////////////////////////////////////////////////////////// /// @brief set the allowImplicitCollections property ////////////////////////////////////////////////////////////////////////////// void setAllowImplicitCollections(bool value) { _allowImplicitCollections = value; } ////////////////////////////////////////////////////////////////////////////// /// @brief read- or write-lock a collection ////////////////////////////////////////////////////////////////////////////// int lock(TRI_transaction_collection_t*, TRI_transaction_type_e); ////////////////////////////////////////////////////////////////////////////// /// @brief read- or write-unlock a collection ////////////////////////////////////////////////////////////////////////////// int unlock(TRI_transaction_collection_t*, TRI_transaction_type_e); private: ////////////////////////////////////////////////////////////////////////////// /// @brief sort ORs for the same attribute so they are in ascending value /// order. this will only work if the condition is for a single attribute /// the usedIndexes vector may also be re-sorted ////////////////////////////////////////////////////////////////////////////// bool sortOrs(arangodb::aql::Ast* ast, arangodb::aql::AstNode* root, arangodb::aql::Variable const* variable, std::vector& usedIndexes) const; ////////////////////////////////////////////////////////////////////////////// /// @brief findIndexHandleForAndNode ////////////////////////////////////////////////////////////////////////////// std::pair findIndexHandleForAndNode( std::vector> indexes, arangodb::aql::AstNode* node, arangodb::aql::Variable const* reference, arangodb::aql::SortCondition const* sortCondition, size_t itemsInCollection, std::vector& usedIndexes, arangodb::aql::AstNode*& specializedCondition, bool& isSparse) const; ////////////////////////////////////////////////////////////////////////////// /// @brief Get one index by id for a collection name, coordinator case ////////////////////////////////////////////////////////////////////////////// std::shared_ptr indexForCollectionCoordinator( std::string const&, std::string const&) const; ////////////////////////////////////////////////////////////////////////////// /// @brief Get all indexes for a collection name, coordinator case ////////////////////////////////////////////////////////////////////////////// std::vector> indexesForCollectionCoordinator( std::string const&) const; ////////////////////////////////////////////////////////////////////////////// /// @brief register an error for the transaction ////////////////////////////////////////////////////////////////////////////// int registerError(int errorNum) { TRI_ASSERT(errorNum != TRI_ERROR_NO_ERROR); if (_setupState == TRI_ERROR_NO_ERROR) { _setupState = errorNum; } TRI_ASSERT(_setupState != TRI_ERROR_NO_ERROR); return errorNum; } ////////////////////////////////////////////////////////////////////////////// /// @brief add a collection to an embedded transaction ////////////////////////////////////////////////////////////////////////////// int addCollectionEmbedded(TRI_voc_cid_t, TRI_transaction_type_e); ////////////////////////////////////////////////////////////////////////////// /// @brief add a collection to a top-level transaction ////////////////////////////////////////////////////////////////////////////// int addCollectionToplevel(TRI_voc_cid_t, TRI_transaction_type_e); ////////////////////////////////////////////////////////////////////////////// /// @brief initialize the transaction /// this will first check if the transaction is embedded in a parent /// transaction. if not, it will create a transaction of its own ////////////////////////////////////////////////////////////////////////////// int setupTransaction(); ////////////////////////////////////////////////////////////////////////////// /// @brief set up an embedded transaction ////////////////////////////////////////////////////////////////////////////// int setupEmbedded(); ////////////////////////////////////////////////////////////////////////////// /// @brief set up a top-level transaction ////////////////////////////////////////////////////////////////////////////// int setupToplevel(); ////////////////////////////////////////////////////////////////////////////// /// @brief free transaction ////////////////////////////////////////////////////////////////////////////// void freeTransaction(); private: ////////////////////////////////////////////////////////////////////////////// /// @brief external transaction id. used in replication only ////////////////////////////////////////////////////////////////////////////// TRI_voc_tid_t _externalId; ////////////////////////////////////////////////////////////////////////////// /// @brief error that occurred on transaction initialization (before begin()) ////////////////////////////////////////////////////////////////////////////// int _setupState; ////////////////////////////////////////////////////////////////////////////// /// @brief how deep the transaction is down in a nested transaction structure ////////////////////////////////////////////////////////////////////////////// int _nestingLevel; ////////////////////////////////////////////////////////////////////////////// /// @brief additional error data ////////////////////////////////////////////////////////////////////////////// std::string _errorData; ////////////////////////////////////////////////////////////////////////////// /// @brief transaction hints ////////////////////////////////////////////////////////////////////////////// TRI_transaction_hint_t _hints; ////////////////////////////////////////////////////////////////////////////// /// @brief timeout for lock acquisition ////////////////////////////////////////////////////////////////////////////// double _timeout; ////////////////////////////////////////////////////////////////////////////// /// @brief wait for sync property for transaction ////////////////////////////////////////////////////////////////////////////// bool _waitForSync; ////////////////////////////////////////////////////////////////////////////// /// @brief allow implicit collections for transaction ////////////////////////////////////////////////////////////////////////////// bool _allowImplicitCollections; ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not this is a "real" transaction ////////////////////////////////////////////////////////////////////////////// bool _isReal; protected: ////////////////////////////////////////////////////////////////////////////// /// @brief the C transaction struct ////////////////////////////////////////////////////////////////////////////// TRI_transaction_t* _trx; ////////////////////////////////////////////////////////////////////////////// /// @brief the vocbase ////////////////////////////////////////////////////////////////////////////// TRI_vocbase_t* const _vocbase; ////////////////////////////////////////////////////////////////////////////// /// @brief the transaction context ////////////////////////////////////////////////////////////////////////////// std::shared_ptr _transactionContext; ////////////////////////////////////////////////////////////////////////////// /// @brief makeNolockHeaders ////////////////////////////////////////////////////////////////////////////// public: static thread_local std::unordered_set* _makeNolockHeaders; }; class TransactionBuilderLeaser { public: explicit TransactionBuilderLeaser(arangodb::Transaction*); explicit TransactionBuilderLeaser(arangodb::TransactionContext*); ~TransactionBuilderLeaser(); arangodb::velocypack::Builder* builder() const { return _builder; } arangodb::velocypack::Builder* operator->() const { return _builder; } arangodb::velocypack::Builder* get() const { return _builder; } private: arangodb::TransactionContext* _transactionContext; arangodb::velocypack::Builder* _builder; }; } #endif