1
0
Fork 0

Merge branch 'engine-api' of github.com:arangodb/arangodb into engine-api

This commit is contained in:
Michael Hackstein 2017-02-07 13:47:07 +01:00
commit ebddba07ec
21 changed files with 305 additions and 255 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,7 +22,6 @@
#include "ScriptFeature.h"
#include "Basics/messages.h"
#include "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"

View File

@ -22,7 +22,6 @@
#include "UnitTestsFeature.h"
#include "Basics/messages.h"
#include "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"

View File

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

View File

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

View File

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

View File

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

View File

@ -87,7 +87,7 @@ struct OperationCursor;
struct OperationOptions;
class TransactionContext;
struct TransactionState;
struct TransactionCollection;
class TransactionCollection;
class Transaction {
friend class traverser::BaseTraverserEngine;

View File

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

View File

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

View File

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

View File

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

View File

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

176
lib/Basics/RollingVector.h Normal file
View File

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

View File

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

View File

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

View File

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