1
0
Fork 0

Merge branch 'devel' of https://github.com/arangodb/arangodb into column-family

# Conflicts:
#	arangod/RocksDBEngine/RocksDBIndex.cpp
#	arangod/RocksDBEngine/RocksDBIndex.h
#	arangod/RocksDBEngine/RocksDBPrimaryIndex.cpp
#	arangod/RocksDBEngine/RocksDBPrimaryIndex.h
This commit is contained in:
Simon Grätzer 2017-05-23 11:17:30 +02:00
commit 88977d204a
48 changed files with 919 additions and 746 deletions

View File

@ -78,6 +78,13 @@ set(ARANGODB_VERSION_MINOR "2")
set(ARANGODB_VERSION_REVISION "devel")
set(ARANGODB_PACKAGE_REVISION "1")
# version for the windows rc file needs to be numeric:
if (ARANGODB_VERSION_REVISION GREATER -1)
set(ARANGODB_NUMERIC_VERSION_REVISION "${ARANGODB_VERSION_REVISION}")
else()
set(ARANGODB_NUMERIC_VERSION_REVISION 1337)
endif()
set(ARANGODB_VERSION
"${ARANGODB_VERSION_MAJOR}.${ARANGODB_VERSION_MINOR}.${ARANGODB_VERSION_REVISION}")
@ -94,7 +101,7 @@ set(ARANGODB_FRIENDLY_STRING "ArangoDB - the native multi-model NoSQL database")
set(ARANGO_BENCH_FRIENDLY_STRING "arangobench - stress test program")
set(ARANGO_DUMP_FRIENDLY_STRING "arangodump - export")
set(ARANGO_RESTORE_FRIENDLY_STRING "arangrestore - importer")
set(ARANGO_EXPORT_FRIENDLY_STRING "arangoexport - datae xporter")
set(ARANGO_EXPORT_FRIENDLY_STRING "arangoexport - datae xporter")
set(ARANGO_IMP_FRIENDLY_STRING "arangoimp - TSV/CSV/JSON importer")
set(ARANGOSH_FRIENDLY_STRING "arangosh - commandline client")
set(ARANGO_VPACK_FRIENDLY_STRING "arangovpack - vpack printer")

View File

@ -91,11 +91,6 @@ engine.
The RocksDB storage engine in this release has a few known issues and missing features.
These will be resolved in the following releases:
* index selectivity estimates are missing. All indexes will report their selectivity
estimate as `0.2`. This may lead to non-optimal indexes being used in a query.
* the geo index is not yet implemented
* the number of documents reported for collections (`db.<collection>.count()`) may be
slightly wrong during transactions
@ -106,6 +101,24 @@ These will be resolved in the following releases:
* the datafile debugger (arango-dfdb) cannot be used with this storage engine
* APIs that return collection properties or figures will return slightly different
attributes for the RocksDB engine than for the MMFiles engine. For example, the
attributes `journalSize`, `doCompact`, `indexBuckets` and `isVolatile` are present
in the MMFiles engine but not in the RocksDB engine. The memory usage figures reported
for collections in the RocksDB engine are estimate values, whereas they are
exact in the MMFiles engine.
* the RocksDB engine does not support some operations which only make sense in the
context of the MMFiles engine. These are:
- the `rotate` method on collections
- the `flush` method for WAL files
* the `any` operation to provide a random document from a collection is supported
by the RocksDB engine but the operation has much higher complexity than in the
MMFiles engine. It is therefore discouraged to call it for cases other than manual
inspection of a few documents in a collection.
### RocksDB storage engine: supported index types
@ -123,6 +136,8 @@ supported there:
"hash", "skiplist" and "persistent" are only used for compatibility with the MMFiles
engine where these indexes existed in previous and the current version of ArangoDB.
* geo: user-defined index for proximity searches
* fulltext: user-defined sorted reverted index on words occurring in documents

View File

@ -668,7 +668,7 @@ set -e
if test "${PARTIAL_STATE}" == 0; then
rm -rf CMakeFiles CMakeCache.txt CMakeCPackOptions.cmake cmake_install.cmake CPackConfig.cmake CPackSourceConfig.cmake
CFLAGS="${CFLAGS}" CXXFLAGS="${CXXFLAGS}" LDFLAGS="${LDFLAGS}" LIBS="${LIBS}" \
cmake "${SOURCE_DIR}" "${CONFIGURE_OPTIONS[@]}" -G "${GENERATOR}" || exit 1
cmake "${SOURCE_DIR}" ${CONFIGURE_OPTIONS[@]} -G "${GENERATOR}" || exit 1
fi
if [ -n "$CPACK" ] && [ -n "${TARGET_DIR}" ] && [ -z "${MSVC}" ]; then
@ -681,7 +681,7 @@ fi
TRIES=0;
set +e
while /bin/true; do
${MAKE_CMD_PREFIX} ${MAKE} "${MAKE_PARAMS[@]}"
${MAKE_CMD_PREFIX} ${MAKE} ${MAKE_PARAMS[@]}
RC=$?
if test "${isCygwin}" == 1 -a "${RC}" != 0 -a "${TRIES}" == 0; then
# sometimes windows will fail on a messed up working copy,

14
Installation/Windows/version/VersionInfo.in Normal file → Executable file
View File

@ -1,11 +1,11 @@
#pragma once
#ifndef PRODUCT_VERSION_MAJOR
#define PRODUCT_VERSION_MAJOR @PRODUCT_VERSION_MAJOR@
#define PRODUCT_VERSION_MAJOR @ARANGODB_VERSION_MAJOR@
#endif
#ifndef PRODUCT_VERSION_MINOR
#define PRODUCT_VERSION_MINOR @PRODUCT_VERSION_MINOR@
#define PRODUCT_VERSION_MINOR @ARANGODB_VERSION_MINOR@
#endif
#ifndef PRODUCT_VERSION_PATCH
@ -13,15 +13,15 @@
#endif
#ifndef PRODUCT_VERSION_BUILD
#define PRODUCT_VERSION_BUILD @PRODUCT_VERSION_REVISION@
#define PRODUCT_VERSION_BUILD @ARANGODB_NUMERIC_VERSION_REVISION@
#endif
#ifndef FILE_VERSION_MAJOR
#define FILE_VERSION_MAJOR @PRODUCT_VERSION_MAJOR@
#define FILE_VERSION_MAJOR @ARANGODB_VERSION_MAJOR@
#endif
#ifndef FILE_VERSION_MINOR
#define FILE_VERSION_MINOR @PRODUCT_VERSION_MINOR@
#define FILE_VERSION_MINOR @ARANGODB_VERSION_MINOR@
#endif
#ifndef FILE_VERSION_PATCH
@ -29,7 +29,7 @@
#endif
#ifndef FILE_VERSION_BUILD
#define FILE_VERSION_BUILD @PRODUCT_VERSION_REVISION@
#define FILE_VERSION_BUILD @ARANGODB_NUMERIC_VERSION_REVISION@
#endif
#ifndef __TO_STRING
@ -49,7 +49,7 @@
#define FILE_VERSION_RESOURCE FILE_VERSION_MAJOR,FILE_VERSION_MINOR,FILE_VERSION_PATCH,FILE_VERSION_BUILD
#define FILE_VERSION_RESOURCE_STR FILE_VERSION_FULL_STR "\0"
#ifndef PRODUCT_INON
#ifndef PRODUCT_ICON
#define PRODUCT_ICON "@PRODUCT_ICON@"
#endif

View File

@ -44,7 +44,7 @@ class BindParameters {
: _builder(nullptr), _parameters(), _processed(false) {}
/// @brief create the parameters
explicit BindParameters(std::shared_ptr<arangodb::velocypack::Builder> builder)
explicit BindParameters(std::shared_ptr<arangodb::velocypack::Builder> const& builder)
: _builder(builder), _parameters(), _processed(false) {}
/// @brief destroy the parameters

View File

@ -230,7 +230,7 @@ AqlItemBlock* EnumerateCollectionBlock::getSome(size_t, // atLeast,
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
}
bool tmp = _cursor->getMore(cb, atMost);
bool tmp = _cursor->next(cb, atMost);
if (!tmp) {
TRI_ASSERT(!_cursor->hasMore());
}

View File

@ -32,6 +32,7 @@
#include "Basics/Exceptions.h"
#include "Basics/ScopeGuard.h"
#include "Basics/StaticStrings.h"
#include "Cluster/ServerState.h"
#include "StorageEngine/DocumentIdentifierToken.h"
#include "Utils/OperationCursor.h"
#include "V8/v8-globals.h"
@ -417,7 +418,7 @@ bool IndexBlock::skipIndex(size_t atMost) {
// this is called every time we need to fetch data from the indexes
bool IndexBlock::readIndex(
size_t atMost,
std::function<void(DocumentIdentifierToken const&)>& callback) {
IndexIterator::TokenCallback const& callback) {
DEBUG_BEGIN_BLOCK();
// this is called every time we want to read the index.
// For the primary key index, this only reads the index once, and never
@ -451,7 +452,7 @@ bool IndexBlock::readIndex(
TRI_ASSERT(atMost >= _returned);
if (_cursor->getMore(callback, atMost - _returned)) {
if (_cursor->next(callback, atMost - _returned)) {
// We have returned enough.
// And this index could return more.
// We are good.
@ -498,7 +499,7 @@ AqlItemBlock* IndexBlock::getSome(size_t atLeast, size_t atMost) {
std::unique_ptr<AqlItemBlock> res;
std::function<void(DocumentIdentifierToken const& token)> callback;
IndexIterator::TokenCallback callback;
if (_indexes.size() > 1) {
// Activate uniqueness checks
callback = [&](DocumentIdentifierToken const& token) {

View File

@ -29,7 +29,7 @@
#include "Aql/ExecutionBlock.h"
#include "Aql/ExecutionNode.h"
#include "Aql/IndexNode.h"
#include "Indexes/IndexIterator.h"
#include "StorageEngine/DocumentIdentifierToken.h"
namespace arangodb {
@ -102,7 +102,7 @@ class IndexBlock final : public ExecutionBlock {
bool skipIndex(size_t atMost);
/// @brief continue fetching of documents
bool readIndex(size_t atMost, std::function<void(DocumentIdentifierToken const&)>&);
bool readIndex(size_t atMost, IndexIterator::TokenCallback const&);
/// @brief frees the memory for all non-constant expressions
void cleanupNonConstExpressions();

View File

@ -23,6 +23,7 @@
#include "Query.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Aql/AqlItemBlock.h"
#include "Aql/AqlTransaction.h"
#include "Aql/ExecutionBlock.h"
@ -42,6 +43,7 @@
#include "Cluster/ServerState.h"
#include "Logger/Logger.h"
#include "RestServer/AqlFeature.h"
#include "RestServer/QueryRegistryFeature.h"
#include "StorageEngine/TransactionState.h"
#include "Transaction/Methods.h"
#include "Transaction/StandaloneContext.h"
@ -69,23 +71,11 @@ static std::atomic<TRI_voc_tick_t> NextQueryId(1);
constexpr uint64_t DontCache = 0;
}
/// @brief global memory limit for AQL queries
uint64_t Query::MemoryLimitValue = 0;
/// @brief global threshold value for slow queries
double Query::SlowQueryThresholdValue = 10.0;
/// @brief whether or not query tracking is disabled globally
bool Query::DoDisableQueryTracking = false;
/// @brief whether a warning in an AQL query should raise an error
bool Query::DoFailOnWarning = false;
/// @brief creates a query
Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
char const* queryString, size_t queryLength,
std::shared_ptr<VPackBuilder> bindParameters,
std::shared_ptr<VPackBuilder> options, QueryPart part)
std::shared_ptr<VPackBuilder> const& bindParameters,
std::shared_ptr<VPackBuilder> const& options, QueryPart part)
: _id(0),
_resourceMonitor(),
_resources(&_resourceMonitor),
@ -102,6 +92,7 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
_maxWarningCount(10),
_warnings(),
_startTime(TRI_microtime()),
_queryRegistry(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")),
_part(part),
_contextOwnedByExterior(contextOwnedByExterior),
_killed(false),
@ -152,8 +143,8 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
/// @brief creates a query from VelocyPack
Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
std::shared_ptr<VPackBuilder> const queryStruct,
std::shared_ptr<VPackBuilder> options, QueryPart part)
std::shared_ptr<VPackBuilder> const& queryStruct,
std::shared_ptr<VPackBuilder> const& options, QueryPart part)
: _id(0),
_resourceMonitor(),
_resources(&_resourceMonitor),
@ -169,6 +160,7 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
_maxWarningCount(10),
_warnings(),
_startTime(TRI_microtime()),
_queryRegistry(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")),
_part(part),
_contextOwnedByExterior(contextOwnedByExterior),
_killed(false),
@ -211,21 +203,7 @@ Query::~Query() {
_executor.reset();
if (_context != nullptr) {
TRI_ASSERT(!_contextOwnedByExterior);
// unregister transaction and resolver in context
ISOLATE;
TRI_GET_GLOBALS();
auto ctx =
static_cast<arangodb::transaction::V8Context*>(v8g->_transactionContext);
if (ctx != nullptr) {
ctx->unregisterTransaction();
}
V8DealerFeature::DEALER->exitContext(_context);
_context = nullptr;
}
exitContext();
_ast.reset();
@ -376,10 +354,12 @@ void Query::registerErrorCustom(int code, char const* details) {
void Query::registerWarning(int code, char const* details) {
TRI_ASSERT(code != TRI_ERROR_NO_ERROR);
if (DoFailOnWarning) {
if (_queryRegistry->failOnWarning()) {
// make an error from each warning if requested
// note: this will throw!
registerErrorCustom(code, details);
if (details == nullptr) {
THROW_ARANGO_EXCEPTION(code);
}
THROW_ARANGO_EXCEPTION_MESSAGE(code, details);
}
if (_warnings.size() > _maxWarningCount) {
@ -1137,7 +1117,6 @@ void Query::exitContext() {
V8DealerFeature::DEALER->exitContext(_context);
_context = nullptr;
}
TRI_ASSERT(_context == nullptr);
}
}
@ -1471,8 +1450,18 @@ Graph const* Query::lookupGraphByName(std::string const& name) {
return g.release();
}
size_t Query::memoryLimit() const {
uint64_t globalLimit = _queryRegistry->queryMemoryLimit();
uint64_t value = getNumericOption<uint64_t>("memoryLimit", globalLimit);
if (value > 0) {
return static_cast<size_t>(value);
}
return 0;
}
/// @brief returns the next query id
TRI_voc_tick_t Query::NextId() {
return NextQueryId.fetch_add(1, std::memory_order_seq_cst);
}

View File

@ -53,6 +53,8 @@ namespace velocypack {
class Builder;
}
class QueryRegistryFeature;
namespace aql {
struct AstNode;
@ -75,12 +77,12 @@ class Query {
public:
Query(bool, TRI_vocbase_t*, char const*, size_t,
std::shared_ptr<arangodb::velocypack::Builder>,
std::shared_ptr<arangodb::velocypack::Builder>, QueryPart);
std::shared_ptr<arangodb::velocypack::Builder> const& bindParameters,
std::shared_ptr<arangodb::velocypack::Builder> const& options, QueryPart);
Query(bool, TRI_vocbase_t*,
std::shared_ptr<arangodb::velocypack::Builder> const,
std::shared_ptr<arangodb::velocypack::Builder>, QueryPart);
Query(bool contextOwnedByExterior, TRI_vocbase_t*,
std::shared_ptr<arangodb::velocypack::Builder> const& queryStruct,
std::shared_ptr<arangodb::velocypack::Builder> const& options, QueryPart);
~Query();
@ -185,13 +187,7 @@ class Query {
}
/// @brief memory limit for query
size_t memoryLimit() const {
uint64_t value = getNumericOption<decltype(MemoryLimitValue)>("memoryLimit", MemoryLimitValue);
if (value > 0) {
return static_cast<size_t>(value);
}
return 0;
}
size_t memoryLimit() const;
/// @brief maximum number of plans to produce
int64_t literalSizeThreshold() const {
@ -274,37 +270,6 @@ class Query {
/// NOTE: returns nullptr if there are no warnings.
std::shared_ptr<arangodb::velocypack::Builder> warningsToVelocyPack() const;
/// @brief fetch the query memory limit
static uint64_t MemoryLimit() { return MemoryLimitValue; }
/// @brief set the query memory limit
static void MemoryLimit(uint64_t value) {
MemoryLimitValue = value;
}
/// @brief fetch the global query tracking value
static bool DisableQueryTracking() { return DoDisableQueryTracking; }
/// @brief turn off tracking globally
static void DisableQueryTracking(bool value) {
DoDisableQueryTracking = value;
}
/// @brief whether a warning in an AQL query should raise an error
static bool FailOnWarning() { return DoFailOnWarning; }
static void FailOnWarning(bool value) {
DoFailOnWarning = value;
}
/// @brief fetch the global slow query threshold value
static double SlowQueryThreshold() { return SlowQueryThresholdValue; }
/// @brief set global slow query threshold value
static void SlowQueryThreshold(double value) {
SlowQueryThresholdValue = value;
}
/// @brief get a description of the query's current state
std::string getStateString() const;
@ -400,7 +365,7 @@ class Query {
/// @brief the currently used V8 context
V8Context* _context;
/// @brief warnings collected during execution
/// @brief graphs used in query, identified by name
std::unordered_map<std::string, Graph*> _graphs;
/// @brief the actual query string
@ -452,6 +417,8 @@ class Query {
/// @brief query start time
double _startTime;
QueryRegistryFeature const* _queryRegistry;
/// @brief the query part
QueryPart const _part;
@ -463,18 +430,6 @@ class Query {
/// @brief whether or not the query is a data modification query
bool _isModificationQuery;
/// @brief global memory limit for AQL queries
static uint64_t MemoryLimitValue;
/// @brief global threshold value for slow queries
static double SlowQueryThresholdValue;
/// @brief whether or not query tracking is disabled globally
static bool DoDisableQueryTracking;
/// @brief whether a warning in an AQL query should raise an error
static bool DoFailOnWarning;
};
}
}

View File

@ -21,7 +21,8 @@
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "Aql/QueryList.h"
#include "QueryList.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Aql/Query.h"
#include "Aql/QueryProfile.h"
#include "Basics/ReadLocker.h"
@ -29,8 +30,10 @@
#include "Basics/WriteLocker.h"
#include "Basics/Exceptions.h"
#include "Logger/Logger.h"
#include "RestServer/QueryRegistryFeature.h"
#include "VocBase/vocbase.h"
using namespace arangodb;
using namespace arangodb::aql;
QueryEntryCopy::QueryEntryCopy(TRI_voc_tick_t id,
@ -41,21 +44,17 @@ QueryEntryCopy::QueryEntryCopy(TRI_voc_tick_t id,
: id(id), queryString(std::move(queryString)), bindParameters(bindParameters),
started(started), runTime(runTime), state(state) {}
double const QueryList::DefaultSlowQueryThreshold = 10.0;
size_t const QueryList::DefaultMaxSlowQueries = 64;
size_t const QueryList::DefaultMaxQueryStringLength = 4096;
/// @brief create a query list
QueryList::QueryList(TRI_vocbase_t*)
: _lock(),
_current(),
_slow(),
_slowCount(0),
_enabled(!Query::DisableQueryTracking()),
_trackSlowQueries(!Query::DisableQueryTracking()),
_slowQueryThreshold(Query::SlowQueryThreshold()),
_maxSlowQueries(QueryList::DefaultMaxSlowQueries),
_maxQueryStringLength(QueryList::DefaultMaxQueryStringLength) {
_enabled(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")->queryTracking()),
_trackSlowQueries(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")->queryTracking()),
_slowQueryThreshold(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")->slowThreshold()),
_maxSlowQueries(defaultMaxSlowQueries),
_maxQueryStringLength(defaultMaxQueryStringLength) {
_current.reserve(64);
}

View File

@ -162,6 +162,12 @@ class QueryList {
private:
std::string extractQueryString(Query const* query, size_t maxLength) const;
/// @brief default maximum number of slow queries to keep in list
static constexpr size_t defaultMaxSlowQueries = 64;
/// @brief default max length of a query when returning it
static constexpr size_t defaultMaxQueryStringLength = 4096;
private:
/// @brief r/w lock for the list
arangodb::basics::ReadWriteLock _lock;
@ -189,15 +195,6 @@ class QueryList {
/// @brief max length of query strings to return
size_t _maxQueryStringLength;
/// @brief default threshold for slow queries
static double const DefaultSlowQueryThreshold;
/// @brief default maximum number of slow queries to keep in list
static size_t const DefaultMaxSlowQueries;
/// @brief default max length of a query when returning it
static size_t const DefaultMaxQueryStringLength;
};
}
}

View File

@ -128,7 +128,7 @@ bool SingleServerEdgeCursor::next(
auto cb = [&](DocumentIdentifierToken const& token) {
_cache.emplace_back(token);
};
bool tmp = cursor->getMore(cb, 1000);
bool tmp = cursor->next(cb, 1000);
TRI_ASSERT(tmp == cursor->hasMore());
}
} while (_cache.empty());
@ -174,8 +174,7 @@ void SingleServerEdgeCursor::readAll(
callback(edgeId, doc, cursorId);
}
};
while (cursor->getMore(cb, 1000)) {
}
cursor->all(cb);
}
}
}

View File

@ -46,15 +46,13 @@
#define ARANGOD_INDEXES_INDEX_ITERATOR_H 1
#include "Basics/Common.h"
#include "Cluster/ServerState.h"
#include "Indexes/IndexLookupContext.h"
#include "StorageEngine/StorageEngine.h"
#include "VocBase/ManagedDocumentResult.h"
#include "VocBase/vocbase.h"
namespace arangodb {
class Index;
class LogicalCollection;
class ManagedDocumentResult;
namespace transaction {
class Methods;
}
@ -62,7 +60,7 @@ class Methods;
/// @brief a base class to iterate over the index. An iterator is requested
/// at the index itself
class IndexIterator {
protected:
public:
typedef std::function<void(DocumentIdentifierToken const& token)> TokenCallback;
typedef std::function<void(DocumentIdentifierToken const& token,
arangodb::velocypack::Slice extra)>

View File

@ -391,7 +391,7 @@ void GraphStore<V, E>::_loadVertices(ShardID const& vertexShard,
edgeOffset += ventry._edgeCount;
}
};
while (cursor->getMore(cb, 1000)) {
while (cursor->next(cb, 1000)) {
if (_destroyed) {
LOG_TOPIC(WARN, Logger::PREGEL) << "Aborted loading graph";
break;
@ -474,8 +474,7 @@ void GraphStore<V, E>::_loadEdges(transaction::Methods* trx,
}
}
};
while (cursor->getMore(cb, 1000)) {
}
cursor->all(cb);
// Add up all added elements
vertexEntry._edgeCount += added;

View File

@ -87,8 +87,7 @@ void RestEdgesHandler::readCursor(
THROW_ARANGO_EXCEPTION(cursor->code);
}
while (cursor->getMore(cb, 1000)) {
}
cursor->all(cb);
}

View File

@ -30,6 +30,8 @@
#include "RestServer/DatabaseFeature.h"
#include "RestServer/ServerFeature.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::options;

View File

@ -23,12 +23,15 @@
#include "InitDatabaseFeature.h"
#include "Basics/FileUtils.h"
#include "Basics/terminal-utils.h"
#include "Logger/Logger.h"
#include "Logger/LoggerFeature.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "RestServer/DatabasePathFeature.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;

View File

@ -80,22 +80,7 @@ void QueryRegistryFeature::collectOptions(
new UInt64Parameter(&_queryCacheEntries));
}
void QueryRegistryFeature::validateOptions(
std::shared_ptr<ProgramOptions> options) {
}
void QueryRegistryFeature::prepare() {
// set query memory limit
arangodb::aql::Query::MemoryLimit(_queryMemoryLimit);
// set global query tracking flag
arangodb::aql::Query::DisableQueryTracking(!_queryTracking);
arangodb::aql::Query::FailOnWarning(_failOnWarning);
// set global threshold value for slow queries
arangodb::aql::Query::SlowQueryThreshold(_slowThreshold);
// configure the query cache
std::pair<std::string, size_t> cacheProperties{_queryCacheMode,
_queryCacheEntries};
@ -106,8 +91,7 @@ void QueryRegistryFeature::prepare() {
QUERY_REGISTRY = _queryRegistry.get();
}
void QueryRegistryFeature::start() {
}
void QueryRegistryFeature::start() {}
void QueryRegistryFeature::unprepare() {
// clear the query registery

View File

@ -39,11 +39,15 @@ class QueryRegistryFeature final : public application_features::ApplicationFeatu
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override final;
void validateOptions(std::shared_ptr<options::ProgramOptions>) override final;
void prepare() override final;
void start() override final;
void unprepare() override final;
bool queryTracking() const { return _queryTracking; }
bool failOnWarning() const { return _failOnWarning; }
uint64_t queryMemoryLimit() const { return _queryMemoryLimit; }
double slowThreshold() const { return _slowThreshold; }
private:
bool _queryTracking;
bool _failOnWarning;

View File

@ -33,6 +33,8 @@
#include "V8Server/V8Context.h"
#include "V8Server/V8DealerFeature.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::options;

View File

@ -628,7 +628,6 @@ void RocksDBCollection::invokeOnAllElements(
void RocksDBCollection::truncate(transaction::Methods* trx,
OperationOptions& options) {
// TODO FIXME -- improve transaction size
// TODO FIXME -- intermediate commit
TRI_ASSERT(_objectId != 0);
TRI_voc_cid_t cid = _logicalCollection->cid();
RocksDBTransactionState* state = rocksutils::toRocksTransactionState(trx);

View File

@ -65,7 +65,14 @@ void RocksDBCollectionExport::run(size_t limit) {
THROW_ARANGO_EXCEPTION(res);
}
_vpack.reserve(limit);
size_t maxDocuments = _collection->numberDocuments(&trx);
if (limit > 0 && limit < maxDocuments) {
maxDocuments = limit;
} else {
limit = maxDocuments;
}
_vpack.reserve(maxDocuments);
ManagedDocumentResult mmdr;
trx.invokeOnAllElements(

View File

@ -35,6 +35,8 @@
#include "VocBase/LogicalCollection.h"
#include "VocBase/ticks.h"
#include <rocksdb/comparator.h>
using namespace arangodb;
using namespace arangodb::rocksutils;
@ -196,16 +198,26 @@ void RocksDBIndex::truncate(transaction::Methods* trx) {
rocksdb::ReadOptions options = mthds->readOptions();
rocksdb::Slice end = indexBounds.end();
<<<<<<< HEAD
rocksdb::Comparator const* cmp = this->comparator();
options.iterate_upper_bound = &end;
=======
options.iterate_upper_bound = &end;
>>>>>>> b2cd86ad8b8ef12784583d289c4469a7e5cae3ac
std::unique_ptr<rocksdb::Iterator> iter = mthds->NewIterator(options, _cf);
iter->Seek(indexBounds.start());
<<<<<<< HEAD
while (iter->Valid() && cmp->Compare(iter->key(), end) < 0) {
TRI_ASSERT(_objectId == RocksDBKey::objectId(iter->key()));
Result r = mthds->Delete(_cf, iter->key());
=======
while (iter->Valid() && _cmp->Compare(iter->key(), end) < 0) {
Result r = mthds->Delete(iter->key());
>>>>>>> b2cd86ad8b8ef12784583d289c4469a7e5cae3ac
if (!r.ok()) {
THROW_ARANGO_EXCEPTION(r);
}

View File

@ -31,13 +31,11 @@
#include <rocksdb/status.h>
namespace rocksdb {class Comparator; class ColumnFamilyHandle;}
namespace arangodb {
namespace cache {
class Cache;
}
class LogicalCollection;
class RocksDBComparator;
class RocksDBCounterManager;
class RocksDBMethods;
@ -105,9 +103,12 @@ class RocksDBIndex : public Index {
virtual void recalculateEstimates();
<<<<<<< HEAD
rocksdb::ColumnFamilyHandle* columnFamily() const{
return _cf;
}
=======
>>>>>>> b2cd86ad8b8ef12784583d289c4469a7e5cae3ac
rocksdb::Comparator const* comparator() const;
protected:
@ -126,7 +127,11 @@ class RocksDBIndex : public Index {
protected:
uint64_t _objectId;
<<<<<<< HEAD
rocksdb::ColumnFamilyHandle* _cf;
=======
rocksdb::Comparator* _cmp;
>>>>>>> b2cd86ad8b8ef12784583d289c4469a7e5cae3ac
mutable std::shared_ptr<cache::Cache> _cache;
// we use this boolean for testing whether _cache is set.

View File

@ -197,7 +197,7 @@ bool RocksDBAllIndexIterator::nextWithKey(TokenKeyCallback const& cb,
size_t limit) {
TRI_ASSERT(_trx->state()->isRunning());
if (limit == 0 || !_iterator->Valid()) {
if (limit == 0 || !_iterator->Valid() || outOfRange()) {
// No limit no data, or we are actually done. The last call should have
// returned false
TRI_ASSERT(limit > 0); // Someone called with limit == 0. Api broken
@ -205,6 +205,9 @@ bool RocksDBAllIndexIterator::nextWithKey(TokenKeyCallback const& cb,
}
while (limit > 0) {
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
TRI_ASSERT(_index->objectId() == RocksDBKey::objectId(_iterator->key()));
#endif
RocksDBToken token(RocksDBValue::revisionId(_iterator->value()));
StringRef key = RocksDBKey::primaryKey(_iterator->key());
cb(token, key);
@ -282,7 +285,7 @@ RocksDBAnyIndexIterator::RocksDBAnyIndexIterator(
_iterator->Prev();
}
}
if (!_iterator->Valid()) {
if (!_iterator->Valid() || outOfRange()) {
_iterator->Seek(_bounds.start());
}
}
@ -562,8 +565,7 @@ void RocksDBPrimaryIndex::invokeOnAllElements(
cnt = callback(token);
}
};
while (cursor->next(cb, 1000) && cnt) {
}
while (cursor->next(cb, 1000) && cnt) {}
}
Result RocksDBPrimaryIndex::postprocessRemove(transaction::Methods* trx,

View File

@ -40,6 +40,7 @@
namespace rocksdb {
class Iterator;
class Comparator;
}
namespace arangodb {

View File

@ -50,7 +50,6 @@ class SortCondition;
struct Variable;
} // namespace aql
class LogicalCollection;
class RocksDBComparator;
class RocksDBPrimaryIndex;
class RocksDBVPackIndex;
namespace transaction {

View File

@ -843,7 +843,7 @@ OperationResult transaction::Methods::anyLocal(
skip, limit, 1000, false);
LogicalCollection* collection = cursor->collection();
cursor->getAll([&](DocumentIdentifierToken const& token) {
cursor->all([&](DocumentIdentifierToken const& token) {
if (collection->readDocument(this, token, mmdr)) {
mmdr.addToBuilder(resultBuilder, false);
}
@ -2139,8 +2139,7 @@ OperationResult transaction::Methods::allLocal(
}
};
while (cursor->getMore(cb, 1000)) {
}
cursor->all(cb);
resultBuilder.close();

View File

@ -52,14 +52,9 @@ void OperationCursor::reset() {
}
}
//////////////////////////////////////////////////////////////////////////////
/// @brief Calls cb for the next batchSize many elements
/// NOTE: This will throw on OUT_OF_MEMORY
//////////////////////////////////////////////////////////////////////////////
bool OperationCursor::getMore(
std::function<void(DocumentIdentifierToken const& token)> const& callback,
uint64_t batchSize) {
bool OperationCursor::next(IndexIterator::TokenCallback const& callback, uint64_t batchSize) {
if (!hasMore()) {
return false;
}
@ -97,13 +92,10 @@ bool OperationCursor::getMore(
return _hasMore;
}
//////////////////////////////////////////////////////////////////////////////
/// @brief Skip the next toSkip many elements.
/// skipped will be increased by the amount of skipped elements afterwards
/// Check hasMore()==true before using this
/// NOTE: This will throw on OUT_OF_MEMORY
//////////////////////////////////////////////////////////////////////////////
int OperationCursor::skip(uint64_t toSkip, uint64_t& skipped) {
if (!hasMore()) {
TRI_ASSERT(false);

View File

@ -91,36 +91,22 @@ struct OperationCursor {
return !successful();
}
//////////////////////////////////////////////////////////////////////////////
/// @brief Reset the cursor
//////////////////////////////////////////////////////////////////////////////
void reset();
//////////////////////////////////////////////////////////////////////////////
/// @brief Calls cb for the next batchSize many elements
//////////////////////////////////////////////////////////////////////////////
bool getMore(
std::function<void(DocumentIdentifierToken const& token)> const& callback,
bool next(IndexIterator::TokenCallback const& callback,
uint64_t batchSize);
//////////////////////////////////////////////////////////////////////////////
/// @brief convenience function to retrieve all results
//////////////////////////////////////////////////////////////////////////////
void getAll(
std::function<void(DocumentIdentifierToken const& token)> const& callback) {
while (getMore(callback, 1000)) {}
void all(IndexIterator::TokenCallback const& callback) {
while (next(callback, 1000)) {}
}
//////////////////////////////////////////////////////////////////////////////
/// @brief Skip the next toSkip many elements.
/// skipped will be increased by the amount of skipped elements afterwards
/// Check hasMore()==true before using this
/// NOTE: This will throw on OUT_OF_MEMORY
//////////////////////////////////////////////////////////////////////////////
int skip(uint64_t, uint64_t&);
};

View File

@ -255,7 +255,7 @@ static void JS_AllQuery(v8::FunctionCallbackInfo<v8::Value> const& args) {
VPackBuilder resultBuilder;
resultBuilder.openArray();
opCursor->getAll([&resultBuilder, &mmdr, &trx, &collection](DocumentIdentifierToken const& tkn) {
opCursor->all([&resultBuilder, &mmdr, &trx, &collection](DocumentIdentifierToken const& tkn) {
if (collection->readDocument(&trx, tkn, mmdr)) {
resultBuilder.add(VPackSlice(mmdr.vpack()));
}

View File

@ -36,6 +36,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/detail/xml_parser_utils.hpp>
#include <regex>
#include <iostream>
using namespace arangodb;
using namespace arangodb::basics;

View File

@ -33,6 +33,7 @@
#include "SimpleHttpClient/SimpleHttpClient.h"
#include <regex>
#include <iostream>
using namespace arangodb;
using namespace arangodb::basics;

View File

@ -32,6 +32,8 @@
#include "SimpleHttpClient/SimpleHttpClient.h"
#include "Ssl/ssl-helper.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::httpclient;

View File

@ -31,6 +31,8 @@
#include "ProgramOptions/Section.h"
#include "Shell/ClientFeature.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::options;

View File

@ -109,7 +109,7 @@ function isClusterReadyForBusiness () {
const coordIds = getPeerCoordinatorIds();
return parallelClusterRequests(function * () {
for (const coordId of coordIds) {
yield [coordId, 'GET', '/_api/foxx/_local/status'];
yield [coordId, 'GET', '/_api/version'];
}
}()).every(response => response.statusCode === 200);
}

View File

@ -29,6 +29,8 @@
#include "Logger/Logger.h"
#include "ProgramOptions/ArgumentParser.h"
#include <iostream>
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::options;

View File

@ -33,6 +33,7 @@
#include "ProgramOptions/IniFileParser.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "ProgramOptions/Translator.h"
using namespace arangodb;
using namespace arangodb::basics;
@ -71,7 +72,7 @@ void ConfigFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
void ConfigFeature::loadOptions(std::shared_ptr<ProgramOptions> options,
char const* binaryPath) {
for (auto const& def : _defines) {
DefineEnvironment(def);
arangodb::options::DefineEnvironment(def);
}
loadConfigFile(options, _progname, binaryPath);

View File

@ -188,6 +188,9 @@ add_library(${LIB_ARANGO} STATIC
Logger/LoggerBufferFeature.cpp
Logger/LoggerFeature.cpp
Logger/LoggerStream.cpp
ProgramOptions/Option.cpp
ProgramOptions/ProgramOptions.cpp
ProgramOptions/Section.cpp
ProgramOptions/Translator.cpp
Random/RandomFeature.cpp
Random/RandomGenerator.cpp

View File

@ -28,6 +28,10 @@
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#if _WIN32
#include <iostream>
#endif
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::options;

View File

@ -26,7 +26,6 @@
#include "Basics/FileUtils.h"
#include <fstream>
#include <iostream>
#include <regex>
#include "ProgramOptions/ProgramOptions.h"

View File

@ -0,0 +1,177 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "Option.h"
#include "ProgramOptions/Parameters.h"
#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>
#include <iostream>
using namespace arangodb::options;
// create an option, consisting of single string
Option::Option(std::string const& value, std::string const& description,
Parameter* parameter, bool hidden, bool obsolete)
: section(),
name(),
description(description),
shorthand(),
parameter(parameter),
hidden(hidden),
obsolete(obsolete) {
auto parts = splitName(value);
section = parts.first;
name = parts.second;
size_t const pos = name.find(',');
if (pos != std::string::npos) {
shorthand = stripShorthand(name.substr(pos + 1));
name = name.substr(0, pos);
}
}
void Option::toVPack(VPackBuilder& builder) const {
parameter->toVPack(builder);
}
// print help for an option
// the special search string "." will show help for all sections, even if hidden
void Option::printHelp(std::string const& search, size_t tw, size_t ow, bool) const {
if (search == "." || !hidden) {
std::cout << " " << pad(nameWithType(), ow) << " ";
std::string value = description;
if (obsolete) {
value += " (obsolete option)";
} else {
std::string description = parameter->description();
if (!description.empty()) {
value.append(". ");
value.append(description);
}
value += " (default: " + parameter->valueString() + ")";
}
auto parts = wordwrap(value, tw - ow - 6);
size_t const n = parts.size();
for (size_t i = 0; i < n; ++i) {
std::cout << trim(parts[i]) << std::endl;
if (i < n - 1) {
std::cout << " " << pad("", ow) << " ";
}
}
}
}
// determine the width of an option help string
size_t Option::optionsWidth() const {
if (hidden) {
return 0;
}
return nameWithType().size();
}
// strip the "--" from a string
std::string Option::stripPrefix(std::string const& name) {
size_t pos = name.find("--");
if (pos == 0) {
// strip initial "--"
return name.substr(2);
}
return name;
}
// strip the "-" from a string
std::string Option::stripShorthand(std::string const& name) {
size_t pos = name.find("-");
if (pos == 0) {
// strip initial "-"
return name.substr(1);
}
return name;
}
// split an option name at the ".", if it exists
std::pair<std::string, std::string> Option::splitName(std::string name) {
std::string section;
name = stripPrefix(name);
// split at "."
size_t pos = name.find(".");
if (pos == std::string::npos) {
// global option
section = "";
} else {
// section-specific option
section = name.substr(0, pos);
name = name.substr(pos + 1);
}
return std::make_pair(section, name);
}
std::vector<std::string> Option::wordwrap(std::string const& value,
size_t size) {
std::vector<std::string> result;
std::string next = value;
if (size > 0) {
while (next.size() > size) {
size_t m = next.find_last_of("., ", size - 1);
if (m == std::string::npos || m < size / 2) {
m = size;
} else {
m += 1;
}
result.emplace_back(next.substr(0, m));
next = next.substr(m);
}
}
result.emplace_back(next);
return result;
}
// right-pad a string
std::string Option::pad(std::string const& value, size_t length) {
size_t const valueLength = value.size();
if (valueLength > length) {
return value.substr(0, length);
}
if (valueLength == length) {
return value;
}
return value + std::string(length - valueLength, ' ');
}
std::string Option::trim(std::string const& value) {
size_t const pos = value.find_first_not_of(" \t\n\r");
if (pos == std::string::npos) {
return "";
}
return value.substr(pos);
}

View File

@ -27,41 +27,21 @@
#include "ProgramOptions/Parameters.h"
#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>
#include <iostream>
namespace arangodb {
namespace options {
struct Parameter;
// a single program option container
struct Option {
// options are default copy-constructible and default movable
// create an option, consisting of single string
Option(std::string const& value, std::string const& description,
Parameter* parameter, bool hidden, bool obsolete)
: section(),
name(),
description(description),
shorthand(),
parameter(parameter),
hidden(hidden),
obsolete(obsolete) {
auto parts = splitName(value);
section = parts.first;
name = parts.second;
Parameter* parameter, bool hidden, bool obsolete);
size_t const pos = name.find(',');
if (pos != std::string::npos) {
shorthand = stripShorthand(name.substr(pos + 1));
name = name.substr(0, pos);
}
}
void toVPack(VPackBuilder& builder) const {
parameter->toVPack(builder);
}
void toVPack(arangodb::velocypack::Builder& builder) const;
// get display name for the option
std::string displayName() const { return "--" + fullName(); }
@ -76,127 +56,31 @@ struct Option {
// print help for an option
// the special search string "." will show help for all sections, even if hidden
void printHelp(std::string const& search, size_t tw, size_t ow, bool) const {
if (search == "." || !hidden) {
std::cout << " " << pad(nameWithType(), ow) << " ";
std::string value = description;
if (obsolete) {
value += " (obsolete option)";
} else {
std::string description = parameter->description();
if (!description.empty()) {
value.append(". ");
value.append(description);
}
value += " (default: " + parameter->valueString() + ")";
}
auto parts = wordwrap(value, tw - ow - 6);
size_t const n = parts.size();
for (size_t i = 0; i < n; ++i) {
std::cout << trim(parts[i]) << std::endl;
if (i < n - 1) {
std::cout << " " << pad("", ow) << " ";
}
}
}
}
void printHelp(std::string const& search, size_t tw, size_t ow, bool) const;
std::string nameWithType() const {
return displayName() + " " + parameter->typeDescription();
}
// determine the width of an option help string
size_t optionsWidth() const {
if (hidden) {
return 0;
}
return nameWithType().size();
}
size_t optionsWidth() const;
// strip the "--" from a string
static std::string stripPrefix(std::string const& name) {
size_t pos = name.find("--");
if (pos == 0) {
// strip initial "--"
return name.substr(2);
}
return name;
}
static std::string stripPrefix(std::string const& name);
// strip the "-" from a string
static std::string stripShorthand(std::string const& name) {
size_t pos = name.find("-");
if (pos == 0) {
// strip initial "-"
return name.substr(1);
}
return name;
}
static std::string stripShorthand(std::string const& name);
// split an option name at the ".", if it exists
static std::pair<std::string, std::string> splitName(std::string name) {
std::string section;
name = stripPrefix(name);
// split at "."
size_t pos = name.find(".");
if (pos == std::string::npos) {
// global option
section = "";
} else {
// section-specific option
section = name.substr(0, pos);
name = name.substr(pos + 1);
}
return std::make_pair(section, name);
}
static std::pair<std::string, std::string> splitName(std::string name);
static std::vector<std::string> wordwrap(std::string const& value,
size_t size) {
std::vector<std::string> result;
std::string next = value;
if (size > 0) {
while (next.size() > size) {
size_t m = next.find_last_of("., ", size - 1);
if (m == std::string::npos || m < size / 2) {
m = size;
} else {
m += 1;
}
result.emplace_back(next.substr(0, m));
next = next.substr(m);
}
}
result.emplace_back(next);
return result;
}
size_t size);
// right-pad a string
static std::string pad(std::string const& value, size_t length) {
size_t const valueLength = value.size();
if (valueLength > length) {
return value.substr(0, length);
}
if (valueLength == length) {
return value;
}
return value + std::string(length - valueLength, ' ');
}
static std::string pad(std::string const& value, size_t length);
static std::string trim(std::string const& value) {
size_t const pos = value.find_first_not_of(" \t\n\r");
if (pos == std::string::npos) {
return "";
}
return value.substr(pos);
}
static std::string trim(std::string const& value);
std::string section;
std::string name;

View File

@ -0,0 +1,444 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "ProgramOptions.h"
#include "Basics/levenshtein.h"
#include "Basics/shell-colors.h"
#include "Basics/terminal-utils.h"
#include "ProgramOptions/Option.h"
#include "ProgramOptions/Section.h"
#include "ProgramOptions/Translator.h"
#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>
#include <iostream>
#define ARANGODB_PROGRAM_OPTIONS_PROGNAME "#progname#"
using namespace arangodb::options;
ProgramOptions::ProgramOptions(char const* progname, std::string const& usage,
std::string const& more,
char const* binaryPath)
: _progname(progname),
_usage(usage),
_more(more),
_terminalWidth(TRI_ColumnsWidth),
_similarity(TRI_Levenshtein),
_processingResult(),
_sealed(false),
_overrideOptions(false),
_binaryPath(binaryPath){
// find progname wildcard in string
size_t const pos = _usage.find(ARANGODB_PROGRAM_OPTIONS_PROGNAME);
if (pos != std::string::npos) {
// and replace it with actual program name
_usage = usage.substr(0, pos) + _progname +
_usage.substr(pos + strlen(ARANGODB_PROGRAM_OPTIONS_PROGNAME));
}
_translator = EnvironmentTranslator;
}
// sets a value translator
void ProgramOptions::setTranslator(
std::function<std::string(std::string const&, char const*)> translator) {
_translator = translator;
}
// prints usage information
void ProgramOptions::printUsage() const { std::cout << _usage << std::endl << std::endl; }
// prints a help for all options, or the options of a section
// the special search string "*" will show help for all sections
// the special search string "." will show help for all sections, even if
// hidden
void ProgramOptions::printHelp(std::string const& search) const {
bool const colors = (isatty(STDOUT_FILENO) != 0);
printUsage();
size_t const tw = _terminalWidth();
size_t const ow = optionsWidth();
for (auto const& it : _sections) {
if (search == "*" || search == "." || search == it.second.name) {
it.second.printHelp(search, tw, ow, colors);
}
}
if (search == "*") {
printSectionsHelp();
}
}
// prints the names for all section help options
void ProgramOptions::printSectionsHelp() const {
char const* colorStart;
char const* colorEnd;
if (isatty(STDOUT_FILENO)) {
colorStart = TRI_SHELL_COLOR_BRIGHT;
colorEnd = TRI_SHELL_COLOR_RESET;
} else {
colorStart = colorEnd = "";
}
// print names of sections
std::cout << _more;
for (auto const& it : _sections) {
if (!it.second.name.empty() && it.second.hasOptions()) {
std::cout << " " << colorStart << "--help-" << it.second.name
<< colorEnd;
}
}
std::cout << std::endl;
}
// returns a VPack representation of the option values
VPackBuilder ProgramOptions::toVPack(bool onlyTouched,
std::unordered_set<std::string> const& exclude) const {
VPackBuilder builder;
builder.openObject();
walk(
[&builder, &exclude](Section const&, Option const& option) {
std::string full(option.fullName());
if (exclude.find(full) != exclude.end()) {
// excluded option
return;
}
// add key
builder.add(VPackValue(full));
// add value
option.toVPack(builder);
},
onlyTouched);
builder.close();
return builder;
}
// translate a shorthand option
std::string ProgramOptions::translateShorthand(std::string const& name) const {
auto it = _shorthands.find(name);
if (it == _shorthands.end()) {
return name;
}
return (*it).second;
}
void ProgramOptions::walk(std::function<void(Section const&, Option const&)> const& callback,
bool onlyTouched) const {
for (auto const& it : _sections) {
if (it.second.obsolete) {
// obsolete section. ignore it
continue;
}
for (auto const& it2 : it.second.options) {
if (it2.second.obsolete) {
// obsolete option. ignore it
continue;
}
if (onlyTouched && !_processingResult.touched(it2.second.fullName())) {
// option not touched. skip over it
continue;
}
callback(it.second, it2.second);
}
}
}
// checks whether a specific option exists
// if the option does not exist, this will flag an error
bool ProgramOptions::require(std::string const& name) {
auto parts = Option::splitName(name);
auto it = _sections.find(parts.first);
if (it == _sections.end()) {
return unknownOption(name);
}
auto it2 = (*it).second.options.find(parts.second);
if (it2 == (*it).second.options.end()) {
return unknownOption(name);
}
return true;
}
// sets a value for an option
bool ProgramOptions::setValue(std::string const& name, std::string const& value) {
if (!_overrideOptions && _processingResult.frozen(name)) {
// option already frozen. don't override it
return true;
}
auto parts = Option::splitName(name);
auto it = _sections.find(parts.first);
if (it == _sections.end()) {
return unknownOption(name);
}
if ((*it).second.obsolete) {
// section is obsolete. ignore it
return true;
}
auto it2 = (*it).second.options.find(parts.second);
if (it2 == (*it).second.options.end()) {
return unknownOption(name);
}
auto& option = (*it2).second;
if (option.obsolete) {
// option is obsolete. ignore it
_processingResult.touch(name);
return true;
}
std::string result = option.parameter->set(_translator(value, _binaryPath));
if (!result.empty()) {
// parameter validation failed
return fail("error setting value for option '--" + name + "': " + result);
}
_processingResult.touch(name);
return true;
}
// finalizes a pass, copying touched into frozen
void ProgramOptions::endPass() {
if (_overrideOptions) {
return;
}
for (auto const& it : _processingResult._touched) {
_processingResult.freeze(it);
}
}
// check whether or not an option requires a value
bool ProgramOptions::requiresValue(std::string const& name) const {
auto parts = Option::splitName(name);
auto it = _sections.find(parts.first);
if (it == _sections.end()) {
return false;
}
auto it2 = (*it).second.options.find(parts.second);
if (it2 == (*it).second.options.end()) {
return false;
}
return (*it2).second.parameter->requiresValue();
}
// returns an option description
std::string ProgramOptions::getDescription(std::string const& name) {
auto parts = Option::splitName(name);
auto it = _sections.find(parts.first);
if (it == _sections.end()) {
return "";
}
auto it2 = (*it).second.options.find(parts.second);
if (it2 == (*it).second.options.end()) {
return "";
}
return (*it2).second.description;
}
// handle an unknown option
bool ProgramOptions::unknownOption(std::string const& name) {
char const* colorStart;
char const* colorEnd;
if (isatty(STDERR_FILENO)) {
colorStart = TRI_SHELL_COLOR_BRIGHT;
colorEnd = TRI_SHELL_COLOR_RESET;
} else {
colorStart = colorEnd = "";
}
fail(std::string("unknown option '") + colorStart + "--" + name + colorEnd +
"'");
auto similarOptions = similar(name, 8, 4);
if (!similarOptions.empty()) {
if (similarOptions.size() == 1) {
std::cerr << "Did you mean this?" << std::endl;
} else {
std::cerr << "Did you mean one of these?" << std::endl;
}
// determine maximum width
size_t maxWidth = 0;
for (auto const& it : similarOptions) {
maxWidth = (std::max)(maxWidth, it.size());
}
for (auto const& it : similarOptions) {
std::cerr << " " << colorStart << Option::pad(it, maxWidth) << colorEnd
<< " " << getDescription(it) << std::endl;
}
std::cerr << std::endl;
}
auto it = _oldOptions.find(name);
if (it != _oldOptions.end()) {
// a now removed or renamed option was specified...
auto& now = (*it).second;
if (now.empty()) {
std::cerr << "Please note that the specified option '" << colorStart
<< "--" << name << colorEnd
<< "' has been removed in this ArangoDB version";
} else {
std::cerr << "Please note that the specified option '" << colorStart
<< "--" << name << colorEnd << "' has been renamed to '--"
<< colorStart << now << colorEnd
<< "' in this ArangoDB version";
}
std::cerr
<< std::endl
<< "Please be sure to read the manual section about changed options"
<< std::endl
<< std::endl;
}
std::cerr << "Use " << colorStart << "--help" << colorEnd << " or "
<< colorStart << "--help-all" << colorEnd
<< " to get an overview of available options" << std::endl
<< std::endl;
return false;
}
// report an error (callback from parser)
bool ProgramOptions::fail(std::string const& message) {
_processingResult.failed(true);
std::cerr << "Error while processing " << _context << ":" << std::endl;
failNotice(message);
std::cerr << std::endl;
return false;
}
void ProgramOptions::failNotice(std::string const& message) {
_processingResult.failed(true);
std::cerr << " " << message << std::endl;
}
// add a positional argument (callback from parser)
void ProgramOptions::addPositional(std::string const& value) {
_processingResult._positionals.emplace_back(value);
}
// adds an option to the list of options
void ProgramOptions::addOption(Option const& option) {
checkIfSealed();
auto it = _sections.find(option.section);
if (it == _sections.end()) {
throw std::logic_error(
std::string("no section defined for program option ") +
option.displayName());
}
if (!option.shorthand.empty()) {
if (!_shorthands.emplace(option.shorthand, option.fullName()).second) {
throw std::logic_error(
std::string("shorthand option already defined for option ") +
option.displayName());
}
}
(*it).second.options.emplace(option.name, option);
}
// determine maximum width of all options labels
size_t ProgramOptions::optionsWidth() const {
size_t width = 0;
for (auto const& it : _sections) {
width = (std::max)(width, it.second.optionsWidth());
}
return width;
}
// check if the options are already sealed and throw if yes
void ProgramOptions::checkIfSealed() const {
if (_sealed) {
throw std::logic_error("program options are already sealed");
}
}
// get a list of similar options
std::vector<std::string> ProgramOptions::similar(std::string const& value, int cutOff,
size_t maxResults) {
std::vector<std::string> result;
if (_similarity != nullptr) {
// build a sorted map of similar values first
std::multimap<int, std::string> distances;
// walk over all options
walk(
[this, &value, &distances](Section const&, Option const& option) {
if (option.fullName() != value) {
distances.emplace(_similarity(value, option.fullName()),
option.displayName());
}
},
false);
// now return the ones that have an edit distance not higher than the
// cutOff value
int last = 0;
for (auto const& it : distances) {
if (last > 1 && it.first > 2 * last) {
break;
}
if (it.first > cutOff) {
continue;
}
result.emplace_back(it.second);
if (result.size() >= maxResults) {
break;
}
last = it.first;
}
}
return result;
}

View File

@ -25,16 +25,10 @@
#include "Basics/Common.h"
#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>
#include "Basics/levenshtein.h"
#include "Basics/terminal-utils.h"
#include "ProgramOptions/Option.h"
#include "ProgramOptions/Section.h"
#include "ProgramOptions/Translator.h"
#define ARANGODB_PROGRAM_OPTIONS_PROGNAME "#progname#"
#include <velocypack/Builder.h>
namespace arangodb {
namespace options {
@ -102,35 +96,11 @@ class ProgramOptions {
ProgramOptions(char const* progname, std::string const& usage,
std::string const& more,
const char *binaryPath,
TerminalWidthFuncType const& terminalWidth = TRI_ColumnsWidth,
SimilarityFuncType const& similarity = TRI_Levenshtein)
: _progname(progname),
_usage(usage),
_more(more),
_terminalWidth(terminalWidth),
_similarity(similarity),
_processingResult(),
_sealed(false),
_overrideOptions(false),
_binaryPath(binaryPath){
// find progname wildcard in string
size_t const pos = _usage.find(ARANGODB_PROGRAM_OPTIONS_PROGNAME);
if (pos != std::string::npos) {
// and replace it with actual program name
_usage = usage.substr(0, pos) + _progname +
_usage.substr(pos + strlen(ARANGODB_PROGRAM_OPTIONS_PROGNAME));
}
_translator = EnvironmentTranslator;
}
char const* binaryPath);
// sets a value translator
void setTranslator(
std::function<std::string(std::string const&, char const*)> translator) {
_translator = translator;
}
std::function<std::string(std::string const&, char const*)> translator);
// return a const reference to the processing result
ProcessingResult const& processingResult() const { return _processingResult; }
@ -205,201 +175,40 @@ class ProgramOptions {
}
// prints usage information
void printUsage() const { std::cout << _usage << std::endl << std::endl; }
void printUsage() const;
// prints a help for all options, or the options of a section
// the special search string "*" will show help for all sections
// the special search string "." will show help for all sections, even if
// hidden
void printHelp(std::string const& search) const {
bool const colors = (isatty(STDOUT_FILENO) != 0);
printUsage();
size_t const tw = _terminalWidth();
size_t const ow = optionsWidth();
for (auto const& it : _sections) {
if (search == "*" || search == "." || search == it.second.name) {
it.second.printHelp(search, tw, ow, colors);
}
}
if (search == "*") {
printSectionsHelp();
}
}
void printHelp(std::string const& search) const;
// prints the names for all section help options
void printSectionsHelp() const {
char const* colorStart;
char const* colorEnd;
if (isatty(STDOUT_FILENO)) {
colorStart = TRI_SHELL_COLOR_BRIGHT;
colorEnd = TRI_SHELL_COLOR_RESET;
} else {
colorStart = colorEnd = "";
}
// print names of sections
std::cout << _more;
for (auto const& it : _sections) {
if (!it.second.name.empty() && it.second.hasOptions()) {
std::cout << " " << colorStart << "--help-" << it.second.name
<< colorEnd;
}
}
std::cout << std::endl;
}
void printSectionsHelp() const;
// returns a VPack representation of the option values
VPackBuilder toVPack(bool onlyTouched,
std::unordered_set<std::string> const& exclude) const {
VPackBuilder builder;
builder.openObject();
walk(
[&builder, &exclude](Section const&, Option const& option) {
std::string full(option.fullName());
if (exclude.find(full) != exclude.end()) {
// excluded option
return;
}
// add key
builder.add(VPackValue(full));
// add value
option.toVPack(builder);
},
onlyTouched);
builder.close();
return builder;
}
arangodb::velocypack::Builder toVPack(bool onlyTouched,
std::unordered_set<std::string> const& exclude) const;
// translate a shorthand option
std::string translateShorthand(std::string const& name) const {
auto it = _shorthands.find(name);
if (it == _shorthands.end()) {
return name;
}
return (*it).second;
}
std::string translateShorthand(std::string const& name) const;
void walk(std::function<void(Section const&, Option const&)> const& callback,
bool onlyTouched) const {
for (auto const& it : _sections) {
if (it.second.obsolete) {
// obsolete section. ignore it
continue;
}
for (auto const& it2 : it.second.options) {
if (it2.second.obsolete) {
// obsolete option. ignore it
continue;
}
if (onlyTouched && !_processingResult.touched(it2.second.fullName())) {
// option not touched. skip over it
continue;
}
callback(it.second, it2.second);
}
}
}
bool onlyTouched) const;
// checks whether a specific option exists
// if the option does not exist, this will flag an error
bool require(std::string const& name) {
auto parts = Option::splitName(name);
auto it = _sections.find(parts.first);
if (it == _sections.end()) {
return unknownOption(name);
}
auto it2 = (*it).second.options.find(parts.second);
if (it2 == (*it).second.options.end()) {
return unknownOption(name);
}
return true;
}
bool require(std::string const& name);
// sets a value for an option
bool setValue(std::string const& name, std::string const& value) {
if (!_overrideOptions && _processingResult.frozen(name)) {
// option already frozen. don't override it
return true;
}
auto parts = Option::splitName(name);
auto it = _sections.find(parts.first);
if (it == _sections.end()) {
return unknownOption(name);
}
if ((*it).second.obsolete) {
// section is obsolete. ignore it
return true;
}
auto it2 = (*it).second.options.find(parts.second);
if (it2 == (*it).second.options.end()) {
return unknownOption(name);
}
auto& option = (*it2).second;
if (option.obsolete) {
// option is obsolete. ignore it
_processingResult.touch(name);
return true;
}
std::string result = option.parameter->set(_translator(value, _binaryPath));
if (!result.empty()) {
// parameter validation failed
return fail("error setting value for option '--" + name + "': " + result);
}
_processingResult.touch(name);
return true;
}
bool setValue(std::string const& name, std::string const& value);
// finalizes a pass, copying touched into frozen
void endPass() {
if (_overrideOptions) {
return;
}
for (auto const& it : _processingResult._touched) {
_processingResult.freeze(it);
}
}
void endPass();
// check whether or not an option requires a value
bool requiresValue(std::string const& name) const {
auto parts = Option::splitName(name);
auto it = _sections.find(parts.first);
if (it == _sections.end()) {
return false;
}
auto it2 = (*it).second.options.find(parts.second);
if (it2 == (*it).second.options.end()) {
return false;
}
return (*it2).second.parameter->requiresValue();
}
bool requiresValue(std::string const& name) const;
// returns a pointer to an option value, specified by option name
// returns a nullptr if the option is unknown
template <typename T>
@ -423,184 +232,32 @@ class ProgramOptions {
}
// returns an option description
std::string getDescription(std::string const& name) {
auto parts = Option::splitName(name);
auto it = _sections.find(parts.first);
if (it == _sections.end()) {
return "";
}
auto it2 = (*it).second.options.find(parts.second);
if (it2 == (*it).second.options.end()) {
return "";
}
return (*it2).second.description;
}
std::string getDescription(std::string const& name);
// handle an unknown option
bool unknownOption(std::string const& name) {
char const* colorStart;
char const* colorEnd;
if (isatty(STDERR_FILENO)) {
colorStart = TRI_SHELL_COLOR_BRIGHT;
colorEnd = TRI_SHELL_COLOR_RESET;
} else {
colorStart = colorEnd = "";
}
fail(std::string("unknown option '") + colorStart + "--" + name + colorEnd +
"'");
auto similarOptions = similar(name, 8, 4);
if (!similarOptions.empty()) {
if (similarOptions.size() == 1) {
std::cerr << "Did you mean this?" << std::endl;
} else {
std::cerr << "Did you mean one of these?" << std::endl;
}
// determine maximum width
size_t maxWidth = 0;
for (auto const& it : similarOptions) {
maxWidth = (std::max)(maxWidth, it.size());
}
for (auto const& it : similarOptions) {
std::cerr << " " << colorStart << Option::pad(it, maxWidth) << colorEnd
<< " " << getDescription(it) << std::endl;
}
std::cerr << std::endl;
}
auto it = _oldOptions.find(name);
if (it != _oldOptions.end()) {
// a now removed or renamed option was specified...
auto& now = (*it).second;
if (now.empty()) {
std::cerr << "Please note that the specified option '" << colorStart
<< "--" << name << colorEnd
<< "' has been removed in this ArangoDB version";
} else {
std::cerr << "Please note that the specified option '" << colorStart
<< "--" << name << colorEnd << "' has been renamed to '--"
<< colorStart << now << colorEnd
<< "' in this ArangoDB version";
}
std::cerr
<< std::endl
<< "Please be sure to read the manual section about changed options"
<< std::endl
<< std::endl;
}
std::cerr << "Use " << colorStart << "--help" << colorEnd << " or "
<< colorStart << "--help-all" << colorEnd
<< " to get an overview of available options" << std::endl
<< std::endl;
return false;
}
bool unknownOption(std::string const& name);
// report an error (callback from parser)
bool fail(std::string const& message) {
_processingResult.failed(true);
std::cerr << "Error while processing " << _context << ":" << std::endl;
failNotice(message);
std::cerr << std::endl;
return false;
}
bool fail(std::string const& message);
void failNotice(std::string const& message) {
_processingResult.failed(true);
std::cerr << " " << message << std::endl;
}
void failNotice(std::string const& message);
// add a positional argument (callback from parser)
void addPositional(std::string const& value) {
_processingResult._positionals.emplace_back(value);
}
void addPositional(std::string const& value);
private:
// adds an option to the list of options
void addOption(Option const& option) {
checkIfSealed();
auto it = _sections.find(option.section);
if (it == _sections.end()) {
throw std::logic_error(
std::string("no section defined for program option ") +
option.displayName());
}
if (!option.shorthand.empty()) {
if (!_shorthands.emplace(option.shorthand, option.fullName()).second) {
throw std::logic_error(
std::string("shorthand option already defined for option ") +
option.displayName());
}
}
(*it).second.options.emplace(option.name, option);
}
void addOption(Option const& option);
// determine maximum width of all options labels
size_t optionsWidth() const {
size_t width = 0;
for (auto const& it : _sections) {
width = (std::max)(width, it.second.optionsWidth());
}
return width;
}
size_t optionsWidth() const;
// check if the options are already sealed and throw if yes
void checkIfSealed() const {
if (_sealed) {
throw std::logic_error("program options are already sealed");
}
}
void checkIfSealed() const;
// get a list of similar options
std::vector<std::string> similar(std::string const& value, int cutOff,
size_t maxResults) {
std::vector<std::string> result;
if (_similarity != nullptr) {
// build a sorted map of similar values first
std::multimap<int, std::string> distances;
// walk over all options
walk(
[this, &value, &distances](Section const&, Option const& option) {
if (option.fullName() != value) {
distances.emplace(_similarity(value, option.fullName()),
option.displayName());
}
},
false);
// now return the ones that have an edit distance not higher than the
// cutOff value
int last = 0;
for (auto const& it : distances) {
if (last > 1 && it.first > 2 * last) {
break;
}
if (it.first > cutOff) {
continue;
}
result.emplace_back(it.second);
if (result.size() >= maxResults) {
break;
}
last = it.first;
}
}
return result;
}
size_t maxResults);
private:
// name of binary (i.e. argv[0])

View File

@ -0,0 +1,81 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "Section.h"
#include "Basics/shell-colors.h"
#include "ProgramOptions/Option.h"
#include <iostream>
using namespace arangodb::options;
// adds a program option to the section
void Section::addOption(Option const& option) { options.emplace(option.name, option); }
// whether or not the section has (displayable) options
bool Section::hasOptions() const {
if (!hidden) {
for (auto const& it : options) {
if (!it.second.hidden) {
return true;
}
}
}
return false;
}
// print help for a section
// the special search string "." will show help for all sections, even if hidden
void Section::printHelp(std::string const& search, size_t tw, size_t ow, bool colors) const {
if (search != "." && (hidden || !hasOptions())) {
return;
}
if (colors) {
std::cout << "Section '" << TRI_SHELL_COLOR_BRIGHT << displayName() << TRI_SHELL_COLOR_RESET << "' (" << description << ")"
<< std::endl;
} else {
std::cout << "Section '" << displayName() << "' (" << description << ")"
<< std::endl;
}
// propagate print command to options
for (auto const& it : options) {
it.second.printHelp(search, tw, ow, colors);
}
std::cout << std::endl;
}
// determine display width for a section
size_t Section::optionsWidth() const {
size_t width = 0;
if (!hidden) {
for (auto const& it : options) {
width = (std::max)(width, it.second.optionsWidth());
}
}
return width;
}

View File

@ -24,8 +24,6 @@
#define ARANGODB_PROGRAM_OPTIONS_SECTION_H 1
#include "Basics/Common.h"
#include "Basics/shell-colors.h"
#include "ProgramOptions/Option.h"
namespace arangodb {
@ -44,58 +42,20 @@ struct Section {
obsolete(obsolete) {}
// adds a program option to the section
void addOption(Option const& option) { options.emplace(option.name, option); }
void addOption(Option const& option);
// get display name for the section
std::string displayName() const { return alias.empty() ? name : alias; }
// whether or not the section has (displayable) options
bool hasOptions() const {
if (!hidden) {
for (auto const& it : options) {
if (!it.second.hidden) {
return true;
}
}
}
return false;
}
bool hasOptions() const;
// print help for a section
// the special search string "." will show help for all sections, even if hidden
void printHelp(std::string const& search, size_t tw, size_t ow, bool colors) const {
if (search != "." && (hidden || !hasOptions())) {
return;
}
if (colors) {
std::cout << "Section '" << TRI_SHELL_COLOR_BRIGHT << displayName() << TRI_SHELL_COLOR_RESET << "' (" << description << ")"
<< std::endl;
} else {
std::cout << "Section '" << displayName() << "' (" << description << ")"
<< std::endl;
}
// propagate print command to options
for (auto const& it : options) {
it.second.printHelp(search, tw, ow, colors);
}
std::cout << std::endl;
}
void printHelp(std::string const& search, size_t tw, size_t ow, bool colors) const;
// determine display width for a section
size_t optionsWidth() const {
size_t width = 0;
if (!hidden) {
for (auto const& it : options) {
width = (std::max)(width, it.second.optionsWidth());
}
}
return width;
}
size_t optionsWidth() const;
std::string name;
std::string description;