mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'engine-api' of github.com:arangodb/arangodb into engine-api
This commit is contained in:
commit
ebddba07ec
|
@ -27,12 +27,11 @@
|
|||
#include "Basics/Common.h"
|
||||
#include "Aql/ExecutionPlan.h"
|
||||
#include "Basics/MutexLocker.h"
|
||||
#include "Basics/RollingVector.h"
|
||||
|
||||
#include <velocypack/Builder.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace arangodb {
|
||||
namespace aql {
|
||||
|
||||
|
@ -243,10 +242,13 @@ class Optimizer {
|
|||
/// @brief the following struct keeps a list (deque) of ExecutionPlan*
|
||||
/// and has some automatic convenience functions.
|
||||
struct PlanList {
|
||||
std::deque<ExecutionPlan*> list;
|
||||
std::deque<int> levelDone;
|
||||
RollingVector<ExecutionPlan*> list;
|
||||
RollingVector<int> levelDone;
|
||||
|
||||
PlanList() {}
|
||||
PlanList() {
|
||||
list.reserve(8);
|
||||
levelDone.reserve(8);
|
||||
}
|
||||
|
||||
/// @brief constructor with a plan
|
||||
PlanList(ExecutionPlan* p, int level) { push_back(p, level); }
|
||||
|
@ -296,13 +298,8 @@ class Optimizer {
|
|||
|
||||
/// @brief steals all the plans in b and clears b at the same time
|
||||
void steal(PlanList& b) {
|
||||
list.swap(b.list);
|
||||
levelDone.swap(b.levelDone);
|
||||
for (auto& p : b.list) {
|
||||
delete p;
|
||||
}
|
||||
b.list.clear();
|
||||
b.levelDone.clear();
|
||||
list = std::move(b.list);
|
||||
levelDone = std::move(b.levelDone);
|
||||
}
|
||||
|
||||
/// @brief appends all the plans to the target and clears *this at the same
|
||||
|
@ -365,7 +362,7 @@ class Optimizer {
|
|||
}
|
||||
|
||||
/// @brief getPlans, ownership of the plans remains with the optimizer
|
||||
std::deque<ExecutionPlan*>& getPlans() { return _plans.list; }
|
||||
RollingVector<ExecutionPlan*>& getPlans() { return _plans.list; }
|
||||
|
||||
/// @brief stealBest, ownership of the plan is handed over to the caller,
|
||||
/// all other plans are deleted
|
||||
|
@ -390,9 +387,8 @@ class Optimizer {
|
|||
|
||||
/// @brief stealPlans, ownership of the plans is handed over to the caller,
|
||||
/// the optimizer will forget about them!
|
||||
std::deque<ExecutionPlan*> stealPlans() {
|
||||
std::deque<ExecutionPlan*> res;
|
||||
res.swap(_plans.list);
|
||||
RollingVector<ExecutionPlan*> stealPlans() {
|
||||
RollingVector<ExecutionPlan*> res(std::move(_plans.list));
|
||||
_plans.levelDone.clear();
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -156,7 +156,6 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
|
|||
_ast(nullptr),
|
||||
_profile(nullptr),
|
||||
_state(INVALID_STATE),
|
||||
_plan(nullptr),
|
||||
_parser(nullptr),
|
||||
_trx(nullptr),
|
||||
_engine(nullptr),
|
||||
|
@ -224,7 +223,6 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
|
|||
_ast(nullptr),
|
||||
_profile(nullptr),
|
||||
_state(INVALID_STATE),
|
||||
_plan(nullptr),
|
||||
_parser(nullptr),
|
||||
_trx(nullptr),
|
||||
_engine(nullptr),
|
||||
|
@ -313,7 +311,7 @@ Query* Query::clone(QueryPart part, bool withPlan) {
|
|||
if (_plan != nullptr) {
|
||||
if (withPlan) {
|
||||
// clone the existing plan
|
||||
clone->setPlan(_plan->clone(*clone));
|
||||
clone->_plan.reset(_plan->clone(*clone));
|
||||
}
|
||||
|
||||
// clone all variables
|
||||
|
@ -326,7 +324,7 @@ Query* Query::clone(QueryPart part, bool withPlan) {
|
|||
|
||||
if (clone->_plan == nullptr) {
|
||||
// initialize an empty plan
|
||||
clone->setPlan(new ExecutionPlan(ast()));
|
||||
clone->_plan.reset(new ExecutionPlan(ast()));
|
||||
}
|
||||
|
||||
TRI_ASSERT(clone->_trx == nullptr);
|
||||
|
@ -566,7 +564,7 @@ QueryResult Query::prepare(QueryRegistry* registry) {
|
|||
|
||||
// If all went well so far, then we keep _plan, _parser and _trx and
|
||||
// return:
|
||||
_plan = plan.release();
|
||||
_plan = std::move(plan);
|
||||
_parser = parser.release();
|
||||
_engine = engine;
|
||||
return QueryResult();
|
||||
|
@ -1408,18 +1406,7 @@ void Query::cleanupPlanAndEngine(int errorCode, VPackBuilder* statsBuilder) {
|
|||
_parser = nullptr;
|
||||
}
|
||||
|
||||
if (_plan != nullptr) {
|
||||
delete _plan;
|
||||
_plan = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief set the plan for the query
|
||||
void Query::setPlan(ExecutionPlan* plan) {
|
||||
if (_plan != nullptr) {
|
||||
delete _plan;
|
||||
}
|
||||
_plan = plan;
|
||||
_plan.reset();
|
||||
}
|
||||
|
||||
/// @brief create a TransactionContext
|
||||
|
|
|
@ -268,16 +268,13 @@ class Query {
|
|||
inline arangodb::Transaction* trx() { return _trx; }
|
||||
|
||||
/// @brief get the plan for the query
|
||||
ExecutionPlan* plan() const { return _plan; }
|
||||
ExecutionPlan* plan() const { return _plan.get(); }
|
||||
|
||||
/// @brief whether or not the query returns verbose error messages
|
||||
bool verboseErrors() const {
|
||||
return getBooleanOption("verboseErrors", false);
|
||||
}
|
||||
|
||||
/// @brief set the plan for the query
|
||||
void setPlan(ExecutionPlan* plan);
|
||||
|
||||
/// @brief enter a V8 context
|
||||
void enterContext();
|
||||
|
||||
|
@ -438,7 +435,7 @@ class Query {
|
|||
ExecutionState _state;
|
||||
|
||||
/// @brief the ExecutionPlan object, if the query is prepared
|
||||
ExecutionPlan* _plan;
|
||||
std::unique_ptr<ExecutionPlan> _plan;
|
||||
|
||||
/// @brief the Parser object, if the query is prepared
|
||||
Parser* _parser;
|
||||
|
|
|
@ -246,7 +246,8 @@ bool GeneralCommTask::handleRequest(std::shared_ptr<RestHandler> handler) {
|
|||
}
|
||||
|
||||
// ok, we need to queue the request
|
||||
LOG_TOPIC(TRACE, Logger::THREADS) << "too much work, queuing handler";
|
||||
LOG_TOPIC(TRACE, Logger::THREADS) << "too much work, queuing handler: "
|
||||
<< _loop._scheduler->infoStatus();
|
||||
size_t queue = handler->queue();
|
||||
uint64_t messageId = handler->messageId();
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ class GeneralCommTask : public SocketTask {
|
|||
|
||||
void processResponse(GeneralResponse*);
|
||||
|
||||
virtual void handleSimpleError(rest::ResponseCode, uint64_t messagid) = 0;
|
||||
virtual void handleSimpleError(rest::ResponseCode, uint64_t messageId) = 0;
|
||||
|
||||
virtual void handleSimpleError(rest::ResponseCode, int code,
|
||||
std::string const& errorMessage,
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
#include "ScriptFeature.h"
|
||||
|
||||
#include "Basics/messages.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "ProgramOptions/ProgramOptions.h"
|
||||
#include "ProgramOptions/Section.h"
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
#include "UnitTestsFeature.h"
|
||||
|
||||
#include "Basics/messages.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "ProgramOptions/ProgramOptions.h"
|
||||
#include "ProgramOptions/Section.h"
|
||||
|
|
|
@ -428,9 +428,8 @@ void SocketTask::asyncReadSome() {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!processAll()) {
|
||||
return;
|
||||
}
|
||||
// ignore the result of processAll, try to read more bytes down below
|
||||
processAll();
|
||||
}
|
||||
} catch (boost::system::system_error& err) {
|
||||
LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "i/o stream failed with: "
|
||||
|
|
|
@ -90,7 +90,7 @@ int AqlTransaction::processCollectionNormal(aql::Collection* collection) {
|
|||
LogicalCollection* AqlTransaction::documentCollection(TRI_voc_cid_t cid) {
|
||||
TransactionCollection* trxColl = this->trxCollection(cid);
|
||||
TRI_ASSERT(trxColl != nullptr);
|
||||
return trxColl->_collection;
|
||||
return trxColl->collection();
|
||||
}
|
||||
|
||||
|
||||
|
@ -104,7 +104,7 @@ LogicalCollection* AqlTransaction::documentCollection(TRI_voc_cid_t cid) {
|
|||
int AqlTransaction::lockCollections() {
|
||||
auto trx = state();
|
||||
for (auto& trxCollection : trx->_collections) {
|
||||
int res = trxCollection->lock(trxCollection->_accessType, 0);
|
||||
int res = trxCollection->lock();
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
|
|
|
@ -82,8 +82,7 @@ TransactionCollection* SingleCollectionTransaction::trxCollection() {
|
|||
_trxCollection = _state->collection(_cid, _accessType);
|
||||
|
||||
if (_trxCollection != nullptr) {
|
||||
_documentCollection =
|
||||
_trxCollection->_collection;
|
||||
_documentCollection = _trxCollection->collection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,8 +137,8 @@ bool SingleCollectionTransaction::hasDitch() const {
|
|||
std::string SingleCollectionTransaction::name() {
|
||||
trxCollection(); // will ensure we have the _trxCollection object set
|
||||
TRI_ASSERT(_trxCollection != nullptr);
|
||||
TRI_ASSERT(_trxCollection->_collection != nullptr);
|
||||
return _trxCollection->_collection->name();
|
||||
TRI_ASSERT(_trxCollection->collection() != nullptr);
|
||||
return _trxCollection->collection()->name();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -618,8 +618,8 @@ std::vector<std::string> Transaction::collectionNames() const {
|
|||
result.reserve(_state->_collections.size());
|
||||
|
||||
for (auto& trxCollection : _state->_collections) {
|
||||
if (trxCollection->_collection != nullptr) {
|
||||
result.emplace_back(trxCollection->_collection->name());
|
||||
if (trxCollection->collection() != nullptr) {
|
||||
result.emplace_back(trxCollection->collection()->name());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -659,9 +659,9 @@ DocumentDitch* Transaction::orderDitch(TRI_voc_cid_t cid) {
|
|||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "unable to determine transaction collection");
|
||||
}
|
||||
|
||||
TRI_ASSERT(trxCollection->_collection != nullptr);
|
||||
TRI_ASSERT(trxCollection->collection() != nullptr);
|
||||
|
||||
DocumentDitch* ditch = _transactionContext->orderDitch(trxCollection->_collection);
|
||||
DocumentDitch* ditch = _transactionContext->orderDitch(trxCollection->collection());
|
||||
|
||||
if (ditch == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
|
@ -1178,7 +1178,7 @@ int Transaction::finish(int errorNum) {
|
|||
std::string Transaction::name(TRI_voc_cid_t cid) const {
|
||||
auto c = trxCollection(cid);
|
||||
TRI_ASSERT(c != nullptr);
|
||||
return c->_collection->name();
|
||||
return c->collection()->name();
|
||||
}
|
||||
|
||||
|
||||
|
@ -3065,9 +3065,9 @@ arangodb::LogicalCollection* Transaction::documentCollection(
|
|||
TRI_ASSERT(_state != nullptr);
|
||||
TRI_ASSERT(trxCollection != nullptr);
|
||||
TRI_ASSERT(getStatus() == Transaction::Status::RUNNING);
|
||||
TRI_ASSERT(trxCollection->_collection != nullptr);
|
||||
TRI_ASSERT(trxCollection->collection() != nullptr);
|
||||
|
||||
return trxCollection->_collection;
|
||||
return trxCollection->collection();
|
||||
}
|
||||
|
||||
/// @brief return the collection
|
||||
|
@ -3083,8 +3083,8 @@ arangodb::LogicalCollection* Transaction::documentCollection(
|
|||
}
|
||||
|
||||
TRI_ASSERT(trxCollection != nullptr);
|
||||
TRI_ASSERT(trxCollection->_collection != nullptr);
|
||||
return trxCollection->_collection;
|
||||
TRI_ASSERT(trxCollection->collection() != nullptr);
|
||||
return trxCollection->collection();
|
||||
}
|
||||
|
||||
/// @brief add a collection by id, with the name supplied
|
||||
|
|
|
@ -87,7 +87,7 @@ struct OperationCursor;
|
|||
struct OperationOptions;
|
||||
class TransactionContext;
|
||||
struct TransactionState;
|
||||
struct TransactionCollection;
|
||||
class TransactionCollection;
|
||||
|
||||
class Transaction {
|
||||
friend class traverser::BaseTraverserEngine;
|
||||
|
|
|
@ -45,6 +45,25 @@ static inline bool HasHint(TransactionState const* trx,
|
|||
static inline bool IsSingleOperationTransaction(TransactionState const* trx) {
|
||||
return HasHint(trx, TransactionHints::Hint::SINGLE_OPERATION);
|
||||
}
|
||||
|
||||
TransactionCollection::TransactionCollection(TransactionState* trx, TRI_voc_cid_t cid, AccessMode::Type accessType, int nestingLevel)
|
||||
: _transaction(trx),
|
||||
_cid(cid),
|
||||
_operations(nullptr),
|
||||
_originalRevision(0),
|
||||
_nestingLevel(nestingLevel),
|
||||
_compactionLocked(false),
|
||||
_waitForSync(false),
|
||||
_collection(nullptr),
|
||||
_accessType(accessType),
|
||||
_lockType(AccessMode::Type::NONE) {}
|
||||
|
||||
TransactionCollection::~TransactionCollection() {}
|
||||
|
||||
/// @brief request a main-level lock for a collection
|
||||
int TransactionCollection::lock() {
|
||||
return lock(_accessType, 0);
|
||||
}
|
||||
|
||||
/// @brief request a lock for a collection
|
||||
int TransactionCollection::lock(AccessMode::Type accessType,
|
||||
|
|
|
@ -34,14 +34,20 @@ struct MMFilesDocumentOperation;
|
|||
struct TransactionState;
|
||||
|
||||
/// @brief collection used in a transaction
|
||||
struct TransactionCollection {
|
||||
class TransactionCollection {
|
||||
friend struct TransactionState;
|
||||
|
||||
TransactionCollection(TransactionState* trx, TRI_voc_cid_t cid, AccessMode::Type accessType, int nestingLevel)
|
||||
: _transaction(trx), _cid(cid), _accessType(accessType), _nestingLevel(nestingLevel), _collection(nullptr), _operations(nullptr),
|
||||
_originalRevision(0), _lockType(AccessMode::Type::NONE), _compactionLocked(false), _waitForSync(false) {}
|
||||
|
||||
public:
|
||||
|
||||
TransactionCollection(TransactionCollection const&) = delete;
|
||||
TransactionCollection& operator=(TransactionCollection const&) = delete;
|
||||
|
||||
TransactionCollection(TransactionState* trx, TRI_voc_cid_t cid, AccessMode::Type accessType, int nestingLevel);
|
||||
~TransactionCollection();
|
||||
|
||||
/// @brief request a main-level lock for a collection
|
||||
int lock();
|
||||
|
||||
/// @brief request a lock for a collection
|
||||
int lock(AccessMode::Type, int nestingLevel);
|
||||
|
||||
|
@ -53,6 +59,10 @@ struct TransactionCollection {
|
|||
|
||||
/// @brief check whether a collection is locked at all
|
||||
bool isLocked() const;
|
||||
|
||||
LogicalCollection* collection() const {
|
||||
return _collection; // vocbase collection pointer
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief request a lock for a collection
|
||||
|
@ -61,18 +71,19 @@ struct TransactionCollection {
|
|||
/// @brief request an unlock for a collection
|
||||
int doUnlock(AccessMode::Type, int nestingLevel);
|
||||
|
||||
public:
|
||||
private:
|
||||
TransactionState* _transaction; // the transaction
|
||||
TRI_voc_cid_t const _cid; // collection id
|
||||
AccessMode::Type _accessType; // access type (read|write)
|
||||
int _nestingLevel; // the transaction level that added this collection
|
||||
LogicalCollection* _collection; // vocbase collection pointer
|
||||
std::vector<MMFilesDocumentOperation*>* _operations;
|
||||
TRI_voc_rid_t _originalRevision; // collection revision at trx start
|
||||
AccessMode::Type _lockType; // collection lock type
|
||||
int _nestingLevel; // the transaction level that added this collection
|
||||
bool
|
||||
_compactionLocked; // was the compaction lock grabbed for the collection?
|
||||
bool _waitForSync; // whether or not the collection has waitForSync
|
||||
|
||||
LogicalCollection* _collection; // vocbase collection pointer
|
||||
AccessMode::Type _accessType; // access type (read|write)
|
||||
AccessMode::Type _lockType; // collection lock type
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ class LogicalCollection;
|
|||
struct MMFilesDocumentOperation;
|
||||
class MMFilesWalMarker;
|
||||
class Transaction;
|
||||
struct TransactionCollection;
|
||||
class TransactionCollection;
|
||||
|
||||
/// @brief transaction type
|
||||
struct TransactionState {
|
||||
|
@ -97,6 +97,14 @@ struct TransactionState {
|
|||
return _hints.has(hint);
|
||||
}
|
||||
|
||||
/// @brief get the transaction id for usage in a marker
|
||||
TRI_voc_tid_t idForMarker() {
|
||||
if (_hints.has(TransactionHints::Hint::SINGLE_OPERATION)) {
|
||||
return 0;
|
||||
}
|
||||
return _id;
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief find a collection in the transaction's list of collections
|
||||
TransactionCollection* findCollection(TRI_voc_cid_t cid, size_t& position) const;
|
||||
|
@ -153,16 +161,6 @@ struct TransactionState {
|
|||
double _timeout; // timeout for lock acquisition
|
||||
};
|
||||
|
||||
/// @brief get the transaction id for usage in a marker
|
||||
static inline TRI_voc_tid_t TRI_MarkerIdTransaction(
|
||||
TransactionState const* trx) {
|
||||
if (trx->_hints.has(TransactionHints::Hint::SINGLE_OPERATION)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return trx->_id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2070,7 +2070,7 @@ int LogicalCollection::insert(Transaction* trx, VPackSlice const slice,
|
|||
// create marker
|
||||
MMFilesCrudMarker insertMarker(
|
||||
TRI_DF_MARKER_VPACK_DOCUMENT,
|
||||
TRI_MarkerIdTransaction(trx->state()), newSlice);
|
||||
trx->state()->idForMarker(), newSlice);
|
||||
|
||||
MMFilesWalMarker const* marker;
|
||||
if (options.recoveryMarker == nullptr) {
|
||||
|
@ -2266,7 +2266,7 @@ int LogicalCollection::update(Transaction* trx, VPackSlice const newSlice,
|
|||
// create marker
|
||||
MMFilesCrudMarker updateMarker(
|
||||
TRI_DF_MARKER_VPACK_DOCUMENT,
|
||||
TRI_MarkerIdTransaction(trx->state()), builder->slice());
|
||||
trx->state()->idForMarker(), builder->slice());
|
||||
|
||||
MMFilesWalMarker const* marker;
|
||||
if (options.recoveryMarker == nullptr) {
|
||||
|
@ -2428,7 +2428,7 @@ int LogicalCollection::replace(Transaction* trx, VPackSlice const newSlice,
|
|||
// create marker
|
||||
MMFilesCrudMarker replaceMarker(
|
||||
TRI_DF_MARKER_VPACK_DOCUMENT,
|
||||
TRI_MarkerIdTransaction(trx->state()), builder->slice());
|
||||
trx->state()->idForMarker(), builder->slice());
|
||||
|
||||
MMFilesWalMarker const* marker;
|
||||
if (options.recoveryMarker == nullptr) {
|
||||
|
@ -2525,7 +2525,7 @@ int LogicalCollection::remove(arangodb::Transaction* trx,
|
|||
|
||||
// create marker
|
||||
MMFilesCrudMarker removeMarker(
|
||||
TRI_DF_MARKER_VPACK_REMOVE, TRI_MarkerIdTransaction(trx->state()),
|
||||
TRI_DF_MARKER_VPACK_REMOVE, trx->state()->idForMarker(),
|
||||
builder->slice());
|
||||
|
||||
MMFilesWalMarker const* marker;
|
||||
|
@ -2656,7 +2656,7 @@ int LogicalCollection::remove(arangodb::Transaction* trx,
|
|||
|
||||
// create marker
|
||||
MMFilesCrudMarker removeMarker(
|
||||
TRI_DF_MARKER_VPACK_REMOVE, TRI_MarkerIdTransaction(trx->state()),
|
||||
TRI_DF_MARKER_VPACK_REMOVE, trx->state()->idForMarker(),
|
||||
builder->slice());
|
||||
|
||||
MMFilesWalMarker const* marker = &removeMarker;
|
||||
|
|
|
@ -412,11 +412,11 @@ function ahuacatlMultiModifySuite () {
|
|||
},
|
||||
|
||||
testMultiRemove2 : function () {
|
||||
AQL_EXECUTE("FOR i IN 1..2000 INSERT { _key: CONCAT('test' + i) } IN @@cn1 INSERT { _key: CONCAT('test' + i) } IN @@cn2", { "@cn1" : cn1, "@cn2" : cn2 });
|
||||
AQL_EXECUTE("FOR i IN 1..2000 INSERT { _key: CONCAT('test', i) } IN @@cn1 INSERT { _key: CONCAT('test', i) } IN @@cn2", { "@cn1" : cn1, "@cn2" : cn2 });
|
||||
assertEqual(2000, c1.count());
|
||||
assertEqual(2000, c2.count());
|
||||
|
||||
AQL_EXECUTE("FOR i IN 1..2000 REMOVE { _key: CONCAT('test' + i) } IN @@cn1 REMOVE { _key: CONCAT('test' + i) } IN @@cn2", { "@cn1" : cn1, "@cn2" : cn2 });
|
||||
AQL_EXECUTE("FOR i IN 1..2000 REMOVE { _key: CONCAT('test', i) } IN @@cn1 REMOVE { _key: CONCAT('test', i) } IN @@cn2", { "@cn1" : cn1, "@cn2" : cn2 });
|
||||
assertEqual(0, c1.count());
|
||||
assertEqual(0, c2.count());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// 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 ARANGODB_BASICS_ROLLING_VECTOR_H
|
||||
#define ARANGODB_BASICS_ROLLING_VECTOR_H 1
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
/// @brief a vector wrapper that also provides amortized O(1) pop_front() functionality.
|
||||
/// pop_front() is implemented by adjusting a start index into the vector, which is
|
||||
/// initially zero. every call to pop_front() will only increase the start index by one,
|
||||
/// which is very efficient. the efficiency is "bought" by not reclaiming unused space
|
||||
/// for popped front elements.
|
||||
/// note that the elements popped with pop_front() will also not be destructed when popped.
|
||||
/// this means this container can only be used for managing trivial types (e.g. integers
|
||||
/// or pointers) that do not require ad-hoc destruction
|
||||
template<typename T>
|
||||
class RollingVector {
|
||||
public:
|
||||
RollingVector() : _start(0) {}
|
||||
explicit RollingVector(size_t size) : RollingVector() {
|
||||
_data.resize(size);
|
||||
}
|
||||
|
||||
RollingVector(RollingVector const& other) : _start(other._start), _data(other._data) {}
|
||||
RollingVector& operator=(RollingVector const& other) {
|
||||
if (this != &other) {
|
||||
_start = other._start;
|
||||
_data = other._data;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RollingVector(RollingVector&& other) : _start(other._start), _data(std::move(other._data)) {
|
||||
other.clear();
|
||||
}
|
||||
|
||||
RollingVector& operator=(RollingVector&& other) {
|
||||
if (this != &other) {
|
||||
_start = other._start;
|
||||
_data = std::move(other._data);
|
||||
other.clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~RollingVector() {}
|
||||
|
||||
typename std::vector<T>::iterator begin() {
|
||||
return _data.begin() + _start;
|
||||
}
|
||||
|
||||
typename std::vector<T>::iterator end() {
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
typename std::vector<T>::const_iterator begin() const {
|
||||
return _data.begin();
|
||||
}
|
||||
|
||||
typename std::vector<T>::const_iterator end() const {
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
T& operator[](size_t position) {
|
||||
return _data[_start + position];
|
||||
}
|
||||
|
||||
T const& operator[](size_t position) const {
|
||||
return _data[_start + position];
|
||||
}
|
||||
|
||||
T& at(size_t position) {
|
||||
return _data.at(_start + position);
|
||||
}
|
||||
|
||||
T const& at(size_t position) const {
|
||||
return _data.at(_start + position);
|
||||
}
|
||||
|
||||
void reserve(size_t size) {
|
||||
_data.reserve(_start + size);
|
||||
}
|
||||
|
||||
void push_back(T const& value) {
|
||||
_data.push_back(value);
|
||||
}
|
||||
|
||||
void pop_front() {
|
||||
TRI_ASSERT(!empty());
|
||||
++_start;
|
||||
if (_start == _data.size()) {
|
||||
// use the opportunity to reset the start value
|
||||
_data.clear();
|
||||
_start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
TRI_ASSERT(!empty());
|
||||
_data.pop_back();
|
||||
if (_data.empty()) {
|
||||
// use the opportunity to reset the start value
|
||||
_start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
T const& front() const {
|
||||
TRI_ASSERT(!empty());
|
||||
return _data[_start];
|
||||
}
|
||||
|
||||
T& front() {
|
||||
return _data[_start];
|
||||
}
|
||||
|
||||
T const& back() const {
|
||||
TRI_ASSERT(!empty());
|
||||
return _data.back();
|
||||
}
|
||||
|
||||
T& back() {
|
||||
return _data.back();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return (_start >= _data.size());
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return _data.size() - _start;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_data.clear();
|
||||
_start = 0;
|
||||
}
|
||||
|
||||
void shrink_to_fit() {
|
||||
_data.shrink_to_fit();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _start;
|
||||
std::vector<T> _data;
|
||||
|
||||
static_assert(std::is_trivial<T>::value, "RollingVector is only safe for trivial types");
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -23,169 +23,48 @@
|
|||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief error number and system error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
struct ErrorContainer {
|
||||
int _number = TRI_ERROR_NO_ERROR;
|
||||
int _sys = TRI_ERROR_NO_ERROR;
|
||||
};
|
||||
|
||||
typedef struct tri_error_s {
|
||||
int _number;
|
||||
int _sys;
|
||||
} tri_error_t;
|
||||
/// @brief holds the last error that occurred in the current thread
|
||||
thread_local ErrorContainer LastError;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief already initialized
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the error messages, will be read-only after initialization
|
||||
static std::unordered_map<int, char const*> ErrorMessages;
|
||||
|
||||
static bool Initialized = false;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief holds the last error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef TRI_GCC_THREAD_LOCAL_STORAGE
|
||||
static __thread tri_error_t ErrorNumber;
|
||||
#elif defined(TRI_WIN32_THREAD_LOCAL_STORAGE)
|
||||
static __declspec(thread) tri_error_t ErrorNumber;
|
||||
#elif defined(TRI_HAVE_POSIX_THREADS)
|
||||
static pthread_key_t ErrorKey;
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the error messages
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static std::unordered_map<int, std::string> ErrorMessages;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief cleanup
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TRI_GCC_THREAD_LOCAL_STORAGE
|
||||
#ifdef TRI_HAVE_POSIX_THREADS
|
||||
|
||||
static void CleanupError(void* ptr) { TRI_Free(TRI_CORE_MEM_ZONE, ptr); }
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the last error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int TRI_errno() { return LastError._number; }
|
||||
|
||||
#if defined(TRI_GCC_THREAD_LOCAL_STORAGE) || \
|
||||
defined(TRI_WIN32_THREAD_LOCAL_STORAGE)
|
||||
|
||||
int TRI_errno() { return ErrorNumber._number; }
|
||||
|
||||
#elif defined(TRI_HAVE_POSIX_THREADS)
|
||||
|
||||
int TRI_errno() {
|
||||
tri_error_t* eptr;
|
||||
|
||||
eptr = static_cast<decltype(eptr)>(pthread_getspecific(ErrorKey));
|
||||
|
||||
if (eptr == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return eptr->_number;
|
||||
}
|
||||
|
||||
#else
|
||||
#error no TLS
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the last error as string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char const* TRI_last_error() {
|
||||
int err;
|
||||
int sys;
|
||||
|
||||
#if defined(TRI_GCC_THREAD_LOCAL_STORAGE) || \
|
||||
defined(TRI_WIN32_THREAD_LOCAL_STORAGE)
|
||||
|
||||
err = ErrorNumber._number;
|
||||
sys = ErrorNumber._sys;
|
||||
|
||||
#elif defined(TRI_HAVE_POSIX_THREADS)
|
||||
|
||||
tri_error_t* eptr = static_cast<decltype(eptr)>(pthread_getspecific(ErrorKey));
|
||||
|
||||
if (eptr == nullptr) {
|
||||
err = 0;
|
||||
sys = 0;
|
||||
} else {
|
||||
err = eptr->_number;
|
||||
sys = eptr->_sys;
|
||||
}
|
||||
|
||||
#else
|
||||
#error no TLS
|
||||
#endif
|
||||
int err = LastError._number;
|
||||
|
||||
if (err == TRI_ERROR_SYS_ERROR) {
|
||||
return strerror(sys);
|
||||
return strerror(LastError._sys);
|
||||
}
|
||||
|
||||
auto it = ErrorMessages.find(err);
|
||||
|
||||
if (it == ErrorMessages.end()) {
|
||||
return "general error";
|
||||
}
|
||||
|
||||
return (*it).second.c_str();
|
||||
return TRI_errno_string(err);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sets the last error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_set_errno(int error) {
|
||||
#if defined(TRI_GCC_THREAD_LOCAL_STORAGE) || \
|
||||
defined(TRI_WIN32_THREAD_LOCAL_STORAGE)
|
||||
|
||||
ErrorNumber._number = error;
|
||||
LastError._number = error;
|
||||
|
||||
if (error == TRI_ERROR_SYS_ERROR) {
|
||||
ErrorNumber._sys = errno;
|
||||
LastError._sys = errno;
|
||||
} else {
|
||||
ErrorNumber._sys = 0;
|
||||
LastError._sys = 0;
|
||||
}
|
||||
|
||||
#elif defined(TRI_HAVE_POSIX_THREADS)
|
||||
|
||||
int copyErrno = errno;
|
||||
|
||||
tri_error_t* eptr = static_cast<decltype(eptr)>(pthread_getspecific(ErrorKey));
|
||||
|
||||
if (eptr == nullptr) {
|
||||
eptr = static_cast<decltype(eptr)>(
|
||||
TRI_Allocate(TRI_CORE_MEM_ZONE, sizeof(tri_error_t), false));
|
||||
pthread_setspecific(ErrorKey, eptr);
|
||||
}
|
||||
|
||||
eptr->_number = error;
|
||||
|
||||
if (error == TRI_ERROR_SYS_ERROR) {
|
||||
eptr->_sys = copyErrno;
|
||||
} else {
|
||||
eptr->_sys = 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#error no TLS
|
||||
#endif
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief defines an error string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_set_errno_string(int code, char const* msg) {
|
||||
if (!ErrorMessages.emplace(code, std::string(msg)).second) {
|
||||
if (!ErrorMessages.emplace(code, msg).second) {
|
||||
// logic error, error number is redeclared
|
||||
printf("Error: duplicate declaration of error code %i in %s:%i\n", code,
|
||||
__FILE__, __LINE__);
|
||||
|
@ -193,10 +72,7 @@ void TRI_set_errno_string(int code, char const* msg) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return an error message for an error code
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char const* TRI_errno_string(int code) {
|
||||
auto it = ErrorMessages.find(code);
|
||||
|
||||
|
@ -205,37 +81,13 @@ char const* TRI_errno_string(int code) {
|
|||
return "unknown error";
|
||||
}
|
||||
|
||||
return (*it).second.c_str();
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initializes the error messages
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_InitializeError() {
|
||||
if (Initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
TRI_InitializeErrorMessages();
|
||||
|
||||
#if defined(TRI_GCC_THREAD_LOCAL_STORAGE) || \
|
||||
defined(TRI_WIN32_THREAD_LOCAL_STORAGE)
|
||||
ErrorNumber._number = 0;
|
||||
ErrorNumber._sys = 0;
|
||||
#elif defined(TRI_HAVE_POSIX_THREADS)
|
||||
pthread_key_create(&ErrorKey, CleanupError);
|
||||
#else
|
||||
#error no TLS
|
||||
#endif
|
||||
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shuts down the error messages
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_ShutdownError() {
|
||||
Initialized = false;
|
||||
}
|
||||
void TRI_ShutdownError() {}
|
||||
|
|
|
@ -475,6 +475,20 @@ void TRI_DisallowMemoryFailures() {
|
|||
}
|
||||
#endif
|
||||
|
||||
/// @brief securely zero memory
|
||||
void TRI_ZeroMemory(void* m, size_t size) {
|
||||
#ifdef _WIN32
|
||||
SecureZeroMemory(m, size);
|
||||
#else
|
||||
// use volatile in order to not optimize away the zeroing
|
||||
volatile char* ptr = reinterpret_cast<volatile char*>(m);
|
||||
volatile char* end = ptr + size;
|
||||
while (ptr < end) {
|
||||
*ptr++ = '\0';
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief initialize memory subsystem
|
||||
void TRI_InitializeMemory() {
|
||||
if (CoreInitialized == 0) {
|
||||
|
|
|
@ -151,6 +151,9 @@ void TRI_DisallowMemoryFailures();
|
|||
static inline void TRI_DisallowMemoryFailures() {}
|
||||
#endif
|
||||
|
||||
/// @brief securely zero memory
|
||||
void TRI_ZeroMemory(void* m, size_t size);
|
||||
|
||||
/// @brief initialize memory subsystem
|
||||
void TRI_InitializeMemory(void);
|
||||
|
||||
|
|
Loading…
Reference in New Issue