mirror of https://gitee.com/bigwinds/arangodb
added query tracking feature
This commit is contained in:
parent
4545136e06
commit
64d77cbe24
|
@ -34,6 +34,7 @@
|
|||
#include "Aql/ExecutionPlan.h"
|
||||
#include "Aql/Optimizer.h"
|
||||
#include "Aql/Parser.h"
|
||||
#include "Aql/QueryList.h"
|
||||
#include "Basics/JsonHelper.h"
|
||||
#include "Basics/json.h"
|
||||
#include "Basics/tri-strings.h"
|
||||
|
@ -53,6 +54,10 @@ using Json = triagens::basics::Json;
|
|||
// --SECTION-- static const values
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief names of query phases / states
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static std::string StateNames[] = {
|
||||
"initializing", // INITIALIZATION
|
||||
"parsing", // PARSING
|
||||
|
@ -75,9 +80,26 @@ static_assert(sizeof(StateNames) / sizeof(std::string) == static_cast<size_t>(Ex
|
|||
/// @brief create a profile
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Profile::Profile ()
|
||||
: results(static_cast<size_t>(INVALID_STATE)),
|
||||
Profile::Profile (Query* query)
|
||||
: query(query),
|
||||
results(static_cast<size_t>(INVALID_STATE)),
|
||||
stamp(TRI_microtime()) {
|
||||
|
||||
auto queryList = static_cast<QueryList*>(query->vocbase()->_queries);
|
||||
try {
|
||||
queryList->insert(query, stamp);
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroy a profile
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Profile::~Profile () {
|
||||
auto queryList = static_cast<QueryList*>(query->vocbase()->_queries);
|
||||
queryList->remove(query, stamp);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -89,7 +111,7 @@ void Profile::enter (ExecutionState state) {
|
|||
|
||||
if (state != ExecutionState::INVALID_STATE) {
|
||||
// record duration of state
|
||||
results.push_back(std::make_pair(state, now - stamp));
|
||||
results.emplace_back(std::make_pair(state, now - stamp));
|
||||
}
|
||||
|
||||
// set timestamp
|
||||
|
@ -128,7 +150,8 @@ Query::Query (triagens::arango::ApplicationV8* applicationV8,
|
|||
TRI_json_t* bindParameters,
|
||||
TRI_json_t* options,
|
||||
QueryPart part)
|
||||
: _applicationV8(applicationV8),
|
||||
: _id(TRI_NextQueryIdVocBase(vocbase)),
|
||||
_applicationV8(applicationV8),
|
||||
_vocbase(vocbase),
|
||||
_executor(nullptr),
|
||||
_context(nullptr),
|
||||
|
@ -155,9 +178,7 @@ Query::Query (triagens::arango::ApplicationV8* applicationV8,
|
|||
|
||||
TRI_ASSERT(_vocbase != nullptr);
|
||||
|
||||
if (profiling()) {
|
||||
_profile = new Profile;
|
||||
}
|
||||
_profile = new Profile(this);
|
||||
enterState(INITIALIZATION);
|
||||
|
||||
_ast = new Ast(this);
|
||||
|
@ -175,7 +196,8 @@ Query::Query (triagens::arango::ApplicationV8* applicationV8,
|
|||
triagens::basics::Json queryStruct,
|
||||
TRI_json_t* options,
|
||||
QueryPart part)
|
||||
: _applicationV8(applicationV8),
|
||||
: _id(TRI_NextQueryIdVocBase(vocbase)),
|
||||
_applicationV8(applicationV8),
|
||||
_vocbase(vocbase),
|
||||
_executor(nullptr),
|
||||
_context(nullptr),
|
||||
|
@ -202,9 +224,7 @@ Query::Query (triagens::arango::ApplicationV8* applicationV8,
|
|||
|
||||
TRI_ASSERT(_vocbase != nullptr);
|
||||
|
||||
if (profiling()) {
|
||||
_profile = new Profile;
|
||||
}
|
||||
_profile = new Profile(this);
|
||||
enterState(INITIALIZATION);
|
||||
|
||||
_ast = new Ast(this);
|
||||
|
@ -619,7 +639,7 @@ QueryResult Query::execute (QueryRegistry* registry) {
|
|||
result.json = jsonResult.steal();
|
||||
result.stats = stats.steal();
|
||||
|
||||
if (_profile != nullptr) {
|
||||
if (_profile != nullptr && profiling()) {
|
||||
result.profile = _profile->toJson(TRI_UNKNOWN_MEM_ZONE);
|
||||
}
|
||||
|
||||
|
@ -691,7 +711,7 @@ QueryResultV8 Query::executeV8 (v8::Isolate* isolate, QueryRegistry* registry) {
|
|||
result.warnings = warningsToJson(TRI_UNKNOWN_MEM_ZONE);
|
||||
result.stats = stats.steal();
|
||||
|
||||
if (_profile != nullptr) {
|
||||
if (_profile != nullptr && profiling()) {
|
||||
result.profile = _profile->toJson(TRI_UNKNOWN_MEM_ZONE);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "Aql/types.h"
|
||||
#include "Utils/AqlTransaction.h"
|
||||
#include "Utils/V8TransactionContext.h"
|
||||
#include "VocBase/voc-types.h"
|
||||
#include "V8Server/ApplicationV8.h"
|
||||
|
||||
struct TRI_json_t;
|
||||
|
@ -57,6 +58,7 @@ namespace triagens {
|
|||
class Executor;
|
||||
class Expression;
|
||||
class Parser;
|
||||
class Query;
|
||||
class QueryRegistry;
|
||||
struct Variable;
|
||||
|
||||
|
@ -106,12 +108,18 @@ namespace triagens {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct Profile {
|
||||
Profile ();
|
||||
Profile (Profile const&) = delete;
|
||||
Profile& operator= (Profile const&) = delete;
|
||||
|
||||
explicit Profile (Query*);
|
||||
|
||||
~Profile ();
|
||||
|
||||
void enter (ExecutionState);
|
||||
|
||||
TRI_json_t* toJson (TRI_memory_zone_t*);
|
||||
|
||||
Query* query;
|
||||
std::vector<std::pair<ExecutionState, double>> results;
|
||||
double stamp;
|
||||
};
|
||||
|
@ -196,6 +204,14 @@ namespace triagens {
|
|||
return _collections.collectionNames();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the query's id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_voc_tick_t id () const {
|
||||
return _id;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the query string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -478,6 +494,12 @@ namespace triagens {
|
|||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief query id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_voc_tick_t const _id;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief application v8 used in the query, we need this for V8 context access
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Aql, list of running queries
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014 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
|
||||
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Aql/QueryList.h"
|
||||
#include "Aql/Query.h"
|
||||
#include "Basics/ReadLocker.h"
|
||||
#include "Basics/WriteLocker.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
using namespace triagens::aql;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- struct QueryEntry
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QueryEntry::QueryEntry (TRI_voc_tick_t id,
|
||||
char const* queryString,
|
||||
size_t queryLength,
|
||||
double started)
|
||||
: id(id),
|
||||
queryString(queryString),
|
||||
queryLength(queryLength),
|
||||
started(started) {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- struct QueryEntryCopy
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QueryEntryCopy::QueryEntryCopy (TRI_voc_tick_t id,
|
||||
std::string const& queryString,
|
||||
double started,
|
||||
double runTime)
|
||||
: id(id),
|
||||
queryString(queryString),
|
||||
started(started),
|
||||
runTime(runTime) {
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class QueryList
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
double const QueryList::DefaultSlowQueryThreshold = 10.0;
|
||||
size_t const QueryList::DefaultMaxSlowQueries = 64;
|
||||
size_t const QueryList::DefaultMaxQueryStringLength = 4096;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors / destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a query list
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QueryList::QueryList (TRI_vocbase_t* vocbase)
|
||||
: _vocbase(vocbase),
|
||||
_lock(),
|
||||
_current(),
|
||||
_slow(),
|
||||
_slowCount(0),
|
||||
_enabled(false),
|
||||
_trackSlowQueries(true),
|
||||
_slowQueryThreshold(QueryList::DefaultSlowQueryThreshold),
|
||||
_maxSlowQueries(QueryList::DefaultMaxSlowQueries),
|
||||
_maxQueryStringLength(QueryList::DefaultMaxQueryStringLength) {
|
||||
|
||||
_current.reserve(64);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroy a query list
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QueryList::~QueryList () {
|
||||
WRITE_LOCKER(_lock);
|
||||
|
||||
for (auto it : _current) {
|
||||
delete it.second;
|
||||
}
|
||||
_current.clear();
|
||||
_slow.clear();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief insert a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void QueryList::insert (Query const* query,
|
||||
double stamp) {
|
||||
// no query string
|
||||
if (query->queryString() == nullptr || ! _enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
std::unique_ptr<QueryEntry> entry(new QueryEntry(
|
||||
query->id(),
|
||||
query->queryString(),
|
||||
query->queryLength(),
|
||||
stamp
|
||||
));
|
||||
|
||||
WRITE_LOCKER(_lock);
|
||||
auto it = _current.emplace(std::make_pair(query->id(), entry.get()));
|
||||
if (it.second) {
|
||||
entry.release();
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void QueryList::remove (Query const* query,
|
||||
double now) {
|
||||
// no query string
|
||||
if (query->queryString() == nullptr || ! _enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
QueryEntry* entry = nullptr;
|
||||
|
||||
{
|
||||
WRITE_LOCKER(_lock);
|
||||
auto it = _current.find(query->id());
|
||||
|
||||
if (it != _current.end()) {
|
||||
entry = (*it).second;
|
||||
_current.erase(it);
|
||||
|
||||
TRI_ASSERT(entry != nullptr);
|
||||
|
||||
try {
|
||||
// check if we need to push the query into the list of slow queries
|
||||
if (_slowQueryThreshold >= 0.0 &&
|
||||
now - entry->started >= _slowQueryThreshold) {
|
||||
// yes.
|
||||
|
||||
size_t const maxLength = _maxQueryStringLength;
|
||||
size_t length = entry->queryLength;
|
||||
if (length > maxLength) {
|
||||
length = maxLength;
|
||||
}
|
||||
|
||||
_slow.emplace_back(QueryEntryCopy(
|
||||
entry->id,
|
||||
std::string(entry->queryString, length).append(entry->queryLength > maxLength ? "..." : ""),
|
||||
entry->started,
|
||||
now - entry->started
|
||||
));
|
||||
|
||||
if (++_slowCount > _maxSlowQueries) {
|
||||
// free first element
|
||||
_slow.pop_front();
|
||||
--_slowCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entry != nullptr) {
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the list of currently running queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<QueryEntryCopy> QueryList::listCurrent () {
|
||||
double const now = TRI_microtime();
|
||||
|
||||
std::vector<QueryEntryCopy> result;
|
||||
|
||||
{
|
||||
size_t const maxLength = _maxQueryStringLength;
|
||||
|
||||
READ_LOCKER(_lock);
|
||||
result.reserve(_current.size());
|
||||
|
||||
for (auto const& it : _current) {
|
||||
auto entry = it.second;
|
||||
|
||||
if (entry == nullptr ||
|
||||
entry->queryString == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t length = entry->queryLength;
|
||||
if (length > maxLength) {
|
||||
length = maxLength;
|
||||
}
|
||||
|
||||
result.emplace_back(QueryEntryCopy(
|
||||
entry->id,
|
||||
std::string(entry->queryString, length).append(entry->queryLength > maxLength ? "..." : ""),
|
||||
entry->started,
|
||||
now - entry->started
|
||||
));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the list of slow queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<QueryEntryCopy> QueryList::listSlow () {
|
||||
std::vector<QueryEntryCopy> result;
|
||||
|
||||
{
|
||||
READ_LOCKER(_lock);
|
||||
result.reserve(_slow.size());
|
||||
result.assign(_slow.begin(), _slow.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clear the list of slow queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void QueryList::clearSlow () {
|
||||
WRITE_LOCKER(_lock);
|
||||
_slow.clear();
|
||||
_slowCount = 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -0,0 +1,331 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Aql, list of queries running in database
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014 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
|
||||
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_AQL_QUERY_LIST_H
|
||||
#define ARANGODB_AQL_QUERY_LIST_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/ReadWriteLock.h"
|
||||
#include "VocBase/voc-types.h"
|
||||
|
||||
struct TRI_vocbase_s;
|
||||
|
||||
namespace triagens {
|
||||
namespace aql {
|
||||
|
||||
class Query;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- struct QueryEntry
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct QueryEntry {
|
||||
QueryEntry (TRI_voc_tick_t,
|
||||
char const*,
|
||||
size_t,
|
||||
double);
|
||||
|
||||
TRI_voc_tick_t const id;
|
||||
char const* const queryString;
|
||||
size_t const queryLength;
|
||||
double const started;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- struct QueryEntryCopy
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct QueryEntryCopy {
|
||||
QueryEntryCopy (TRI_voc_tick_t,
|
||||
std::string const&,
|
||||
double,
|
||||
double);
|
||||
|
||||
TRI_voc_tick_t id;
|
||||
std::string queryString;
|
||||
double started;
|
||||
double runTime;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class QueryList
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class QueryList {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors / destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a query list
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
explicit QueryList (struct TRI_vocbase_s*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroy a query list
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
~QueryList ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not queries are tracked
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool enabled () const {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief toggle query tracking
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void enabled (bool value) {
|
||||
_enabled = value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not slow queries are tracked
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool trackSlowQueries () const {
|
||||
return _trackSlowQueries;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief toggle slow query tracking
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void trackSlowQueries (bool value) {
|
||||
_trackSlowQueries = value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief threshold for slow queries (in seconds)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline double slowQueryThreshold () const {
|
||||
return _slowQueryThreshold;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the slow query threshold
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void slowQueryThreshold (double value) {
|
||||
if (value < 0.0 || value == HUGE_VAL || value != value) {
|
||||
// sanity checks
|
||||
value = 0.0;
|
||||
}
|
||||
_slowQueryThreshold = value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the max number of slow queries to keep
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline size_t maxSlowQueries () const {
|
||||
return _maxSlowQueries;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the max number of slow queries to keep
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void maxSlowQueries (size_t value) {
|
||||
if (value > 16384) {
|
||||
// sanity checks
|
||||
value = 16384;
|
||||
}
|
||||
_maxSlowQueries = value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the max length of query strings that are stored / returned
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline size_t maxQueryStringLength () const {
|
||||
return _maxQueryStringLength;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the max length of query strings that are stored / returned
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void maxQueryStringLength (size_t value) {
|
||||
// sanity checks
|
||||
if (value < 64) {
|
||||
value = 64;
|
||||
}
|
||||
else if (value >= 8 * 1024 * 1024) {
|
||||
value = 8 * 1024 * 1024;
|
||||
}
|
||||
|
||||
_maxQueryStringLength = value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief enter a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void insert (Query const*,
|
||||
double);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void remove (Query const*,
|
||||
double);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the list of running queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<QueryEntryCopy> listCurrent ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the list of slow queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<QueryEntryCopy> listSlow ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clear the list of slow queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void clearSlow ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief vocbase
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TRI_vocbase_s* _vocbase;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief r/w lock for the list
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
triagens::basics::ReadWriteLock _lock;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief list of current queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<TRI_voc_tick_t, QueryEntry*> _current;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief list of slow queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::list<QueryEntryCopy> _slow;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief current number of slow queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t _slowCount;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not queries are tracked
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _enabled;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not slow queries are tracked
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _trackSlowQueries;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief threshold for slow queries (in seconds)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double _slowQueryThreshold;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief maximum number of slow queries to keep
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t _maxSlowQueries;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @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;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -56,6 +56,7 @@ add_executable(
|
|||
Aql/OptimizerRules.cpp
|
||||
Aql/Parser.cpp
|
||||
Aql/Query.cpp
|
||||
Aql/QueryList.cpp
|
||||
Aql/QueryRegistry.cpp
|
||||
Aql/RangeInfo.cpp
|
||||
Aql/Range.cpp
|
||||
|
|
|
@ -37,6 +37,7 @@ arangod_libarangod_a_SOURCES = \
|
|||
arangod/Aql/OptimizerRules.cpp \
|
||||
arangod/Aql/Parser.cpp \
|
||||
arangod/Aql/Query.cpp \
|
||||
arangod/Aql/QueryList.cpp \
|
||||
arangod/Aql/QueryRegistry.cpp \
|
||||
arangod/Aql/RangeInfo.cpp \
|
||||
arangod/Aql/Range.cpp \
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "v8-voccursor.h"
|
||||
|
||||
#include "Aql/Query.h"
|
||||
#include "Aql/QueryList.h"
|
||||
#include "Aql/QueryRegistry.h"
|
||||
#include "Basics/Utf8Helper.h"
|
||||
|
||||
|
@ -107,7 +108,7 @@ int32_t const WRP_VOCBASE_COL_TYPE = 2;
|
|||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- HELPER FUNCTIONS
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief wraps a C++ into a v8::Object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1406,6 +1407,166 @@ static void JS_ExecuteAql (const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
TRI_WrapGeneralCursor(args, cursor);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief retrieve global query options or configure them
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void JS_QueriesPropertiesAql (const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
TRI_vocbase_t* vocbase = GetContextVocBase(isolate);
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
auto queryList = static_cast<triagens::aql::QueryList*>(vocbase->_queries);
|
||||
TRI_ASSERT(queryList != nullptr);
|
||||
|
||||
|
||||
if (args.Length() > 1) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE("AQL_QUERIES_PROPERTIES(<options>)");
|
||||
}
|
||||
|
||||
if (args.Length() == 1) {
|
||||
// store options
|
||||
if (! args[0]->IsObject()) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE("AQL_QUERIES_PROPERTIES(<options>)");
|
||||
}
|
||||
|
||||
auto obj = args[0]->ToObject();
|
||||
if (obj->Has(TRI_V8_ASCII_STRING("enabled"))) {
|
||||
queryList->enabled(TRI_ObjectToBoolean(obj->Get(TRI_V8_ASCII_STRING("enabled"))));
|
||||
}
|
||||
if (obj->Has(TRI_V8_ASCII_STRING("trackSlowQueries"))) {
|
||||
queryList->trackSlowQueries(TRI_ObjectToBoolean(obj->Get(TRI_V8_ASCII_STRING("trackSlowQueries"))));
|
||||
}
|
||||
if (obj->Has(TRI_V8_ASCII_STRING("maxSlowQueries"))) {
|
||||
queryList->maxSlowQueries(static_cast<size_t>(TRI_ObjectToInt64(obj->Get(TRI_V8_ASCII_STRING("maxSlowQueries")))));
|
||||
}
|
||||
if (obj->Has(TRI_V8_ASCII_STRING("slowQueryThreshold"))) {
|
||||
queryList->slowQueryThreshold(TRI_ObjectToDouble(obj->Get(TRI_V8_ASCII_STRING("slowQueryThreshold"))));
|
||||
}
|
||||
if (obj->Has(TRI_V8_ASCII_STRING("maxQueryStringLength"))) {
|
||||
queryList->maxQueryStringLength(static_cast<size_t>(TRI_ObjectToInt64(obj->Get(TRI_V8_ASCII_STRING("maxQueryStringLength")))));
|
||||
}
|
||||
|
||||
// fall-through intentional
|
||||
}
|
||||
|
||||
// return current settings
|
||||
auto result = v8::Object::New(isolate);
|
||||
result->Set(TRI_V8_ASCII_STRING("enabled"), v8::Boolean::New(isolate, queryList->enabled()));
|
||||
result->Set(TRI_V8_ASCII_STRING("trackSlowQueries"), v8::Boolean::New(isolate, queryList->trackSlowQueries()));
|
||||
result->Set(TRI_V8_ASCII_STRING("maxSlowQueries"), v8::Number::New(isolate, static_cast<double>(queryList->maxSlowQueries())));
|
||||
result->Set(TRI_V8_ASCII_STRING("slowQueryThreshold"), v8::Number::New(isolate, queryList->slowQueryThreshold()));
|
||||
result->Set(TRI_V8_ASCII_STRING("maxQueryStringLength"), v8::Number::New(isolate, static_cast<double>(queryList->maxQueryStringLength())));
|
||||
|
||||
TRI_V8_RETURN(result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the list of currently running queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void JS_QueriesCurrentAql (const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
TRI_vocbase_t* vocbase = GetContextVocBase(isolate);
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
if (args.Length() != 0) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE("AQL_QUERIES_CURRENT()");
|
||||
}
|
||||
|
||||
|
||||
auto queryList = static_cast<triagens::aql::QueryList*>(vocbase->_queries);
|
||||
TRI_ASSERT(queryList != nullptr);
|
||||
|
||||
|
||||
try {
|
||||
auto const&& queries = queryList->listCurrent();
|
||||
|
||||
uint32_t i = 0;
|
||||
auto result = v8::Array::New(isolate, static_cast<int>(queries.size()));
|
||||
|
||||
for (auto it : queries) {
|
||||
auto const&& timeString = TRI_StringTimeStamp(it.started);
|
||||
|
||||
v8::Handle<v8::Object> obj = v8::Object::New(isolate);
|
||||
obj->Set(TRI_V8_ASCII_STRING("id"), V8TickId(isolate, it.id));
|
||||
obj->Set(TRI_V8_ASCII_STRING("query"), TRI_V8_STD_STRING(it.queryString));
|
||||
obj->Set(TRI_V8_ASCII_STRING("started"), TRI_V8_STD_STRING(timeString));
|
||||
obj->Set(TRI_V8_ASCII_STRING("runTime"), v8::Number::New(isolate, it.runTime));
|
||||
|
||||
result->Set(i++, obj);
|
||||
}
|
||||
|
||||
TRI_V8_RETURN(result);
|
||||
}
|
||||
catch (...) {
|
||||
TRI_V8_THROW_EXCEPTION_MEMORY();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the list of slow running queries or clears the list
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void JS_QueriesSlowAql (const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
TRI_vocbase_t* vocbase = GetContextVocBase(isolate);
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
auto queryList = static_cast<triagens::aql::QueryList*>(vocbase->_queries);
|
||||
TRI_ASSERT(queryList != nullptr);
|
||||
|
||||
|
||||
if (args.Length() == 1) {
|
||||
queryList->clearSlow();
|
||||
TRI_V8_RETURN_TRUE();
|
||||
}
|
||||
|
||||
if (args.Length() != 0) {
|
||||
TRI_V8_THROW_EXCEPTION_USAGE("AQL_QUERIES_SLOW()");
|
||||
}
|
||||
|
||||
try {
|
||||
auto const&& queries = queryList->listSlow();
|
||||
|
||||
uint32_t i = 0;
|
||||
auto result = v8::Array::New(isolate, static_cast<int>(queries.size()));
|
||||
|
||||
for (auto it : queries) {
|
||||
auto const&& timeString = TRI_StringTimeStamp(it.started);
|
||||
|
||||
v8::Handle<v8::Object> obj = v8::Object::New(isolate);
|
||||
obj->Set(TRI_V8_ASCII_STRING("id"), V8TickId(isolate, it.id));
|
||||
obj->Set(TRI_V8_ASCII_STRING("query"), TRI_V8_STD_STRING(it.queryString));
|
||||
obj->Set(TRI_V8_ASCII_STRING("started"), TRI_V8_STD_STRING(timeString));
|
||||
obj->Set(TRI_V8_ASCII_STRING("runTime"), v8::Number::New(isolate, it.runTime));
|
||||
|
||||
result->Set(i++, obj);
|
||||
}
|
||||
|
||||
TRI_V8_RETURN(result);
|
||||
}
|
||||
catch (...) {
|
||||
TRI_V8_THROW_EXCEPTION_MEMORY();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- TRI_VOCBASE_T FUNCTIONS
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -2678,6 +2839,9 @@ void TRI_InitV8VocBridge (v8::Isolate* isolate,
|
|||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_EXPLAIN"), JS_ExplainAql, true);
|
||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_PARSE"), JS_ParseAql, true);
|
||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_WARNING"), JS_WarningAql, true);
|
||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERIES_PROPERTIES"), JS_QueriesPropertiesAql, true);
|
||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERIES_CURRENT"), JS_QueriesCurrentAql, true);
|
||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERIES_SLOW"), JS_QueriesSlowAql, true);
|
||||
|
||||
TRI_InitV8replication(isolate, context, server, vocbase, loader, threadNumber, v8g);
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include <regex.h>
|
||||
|
||||
#include "Aql/QueryList.h"
|
||||
#include "Basics/conversions.h"
|
||||
#include "Basics/files.h"
|
||||
#include "Basics/hashes.h"
|
||||
|
@ -74,6 +75,8 @@
|
|||
// --SECTION-- private types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static std::atomic<TRI_voc_tick_t> QueryId(1);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief auxiliary struct for index iteration
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1350,6 +1353,18 @@ TRI_vocbase_t* TRI_CreateInitialVocBase (TRI_server_t* server,
|
|||
|
||||
vocbase->_oldTransactions = nullptr;
|
||||
|
||||
try {
|
||||
vocbase->_queries = new triagens::aql::QueryList(vocbase);
|
||||
}
|
||||
catch (...) {
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, vocbase->_name);
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, vocbase->_path);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, vocbase);
|
||||
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// use the defaults provided
|
||||
TRI_ApplyVocBaseDefaults(vocbase, defaults);
|
||||
|
||||
|
@ -1436,6 +1451,10 @@ void TRI_DestroyInitialVocBase (TRI_vocbase_t* vocbase) {
|
|||
TRI_DestroySpin(&vocbase->_usage._lock);
|
||||
|
||||
TRI_FreeStoreGeneralCursor(vocbase->_cursors);
|
||||
|
||||
if (vocbase->_queries != nullptr) {
|
||||
delete static_cast<triagens::aql::QueryList*>(vocbase->_queries);
|
||||
}
|
||||
|
||||
// free name and path
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, vocbase->_path);
|
||||
|
@ -2479,6 +2498,14 @@ bool TRI_IsAllowedNameVocBase (bool allowSystem,
|
|||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the next query id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_voc_tick_t TRI_NextQueryIdVocBase (TRI_vocbase_t* vocbase) {
|
||||
return QueryId.fetch_add(1, std::memory_order_seq_cst);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -311,6 +311,7 @@ typedef struct TRI_vocbase_s {
|
|||
|
||||
// structures for user-defined volatile data
|
||||
void* _userStructures;
|
||||
void* _queries;
|
||||
|
||||
TRI_associative_pointer_t _authInfo;
|
||||
TRI_associative_pointer_t _authCache;
|
||||
|
@ -648,6 +649,12 @@ bool TRI_IsSystemVocBase (TRI_vocbase_t*);
|
|||
bool TRI_IsAllowedNameVocBase (bool,
|
||||
char const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the next query id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_voc_tick_t TRI_NextQueryIdVocBase (TRI_vocbase_t*);
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*jshint strict: false */
|
||||
/*global require, AQL_PARSE */
|
||||
/*global require, AQL_PARSE, AQL_QUERIES_CURRENT, AQL_QUERIES_SLOW, AQL_QUERIES_PROPERTIES */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief query actions
|
||||
|
@ -34,9 +34,165 @@ var actions = require("org/arangodb/actions");
|
|||
var ArangoError = arangodb.ArangoError;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- global variables
|
||||
// --SECTION-- HTTP methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @startDocuBlock GetApiQueryCurrent
|
||||
/// @brief returns a list of currently running AQL queries
|
||||
///
|
||||
/// @RESTHEADER{GET /_api/query/current, Returns the currently running AQL queries}
|
||||
///
|
||||
/// @RESTRETURNCODES
|
||||
///
|
||||
/// @RESTRETURNCODE{200}
|
||||
/// Is returned when the list of queries can be retrieved successfully.
|
||||
///
|
||||
/// @RESTRETURNCODE{400}
|
||||
/// The server will respond with *HTTP 400* in case of a malformed request,
|
||||
///
|
||||
/// @endDocuBlock
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @startDocuBlock GetApiQuerySlow
|
||||
/// @brief returns a list of slow running AQL queries
|
||||
///
|
||||
/// @RESTHEADER{GET /_api/query/slow, Returns the list of slow AQL queries}
|
||||
///
|
||||
/// @RESTRETURNCODES
|
||||
///
|
||||
/// @RESTRETURNCODE{200}
|
||||
/// Is returned when the list of queries can be retrieved successfully.
|
||||
///
|
||||
/// @RESTRETURNCODE{400}
|
||||
/// The server will respond with *HTTP 400* in case of a malformed request,
|
||||
///
|
||||
/// @endDocuBlock
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @startDocuBlock GetApiQueryProperties
|
||||
/// @brief returns the configuration for the AQL query tracking
|
||||
///
|
||||
/// @RESTHEADER{GET /_api/query/properties, Returns the properties for the AQL query tracking}
|
||||
///
|
||||
/// @RESTRETURNCODES
|
||||
///
|
||||
/// @RESTRETURNCODE{200}
|
||||
/// Is returned when the list of queries can be retrieved successfully.
|
||||
///
|
||||
/// @RESTRETURNCODE{400}
|
||||
/// The server will respond with *HTTP 400* in case of a malformed request,
|
||||
///
|
||||
/// @endDocuBlock
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function get_api_query (req, res) {
|
||||
var suffixes = [ "slow", "current", "properties" ];
|
||||
|
||||
if (req.suffix.length !== 1 ||
|
||||
suffixes.indexOf(req.suffix[0]) === -1) {
|
||||
actions.resultNotFound(req,
|
||||
res,
|
||||
arangodb.ERROR_HTTP_NOT_FOUND,
|
||||
arangodb.errors.ERROR_HTTP_NOT_FOUND.message);
|
||||
return;
|
||||
}
|
||||
|
||||
var result;
|
||||
if (req.suffix[0] === "slow") {
|
||||
result = AQL_QUERIES_SLOW();
|
||||
}
|
||||
else if (req.suffix[0] === "current") {
|
||||
result = AQL_QUERIES_CURRENT();
|
||||
}
|
||||
else if (req.suffix[0] === "properties") {
|
||||
result = AQL_QUERIES_PROPERTIES();
|
||||
}
|
||||
|
||||
if (result instanceof ArangoError) {
|
||||
actions.resultBad(req, res, result.errorNum, result.errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
actions.resultOk(req, res, actions.HTTP_OK, result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @startDocuBlock DeleteApiQuerySlow
|
||||
/// @brief clears the list of slow AQL queries
|
||||
///
|
||||
/// @RESTHEADER{DELETE /_api/query/slow, Clears the list of slow AQL queries}
|
||||
///
|
||||
/// @RESTRETURNCODES
|
||||
///
|
||||
/// @RESTRETURNCODE{204}
|
||||
/// The server will respond with *HTTP 200* when the list of queries was
|
||||
/// cleared successfully.
|
||||
///
|
||||
/// @RESTRETURNCODE{400}
|
||||
/// The server will respond with *HTTP 400* in case of a malformed request.
|
||||
/// @endDocuBlock
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function delete_api_query (req, res) {
|
||||
if (req.suffix.length !== 1 || req.suffix[0] !== "slow") {
|
||||
actions.resultNotFound(req,
|
||||
res,
|
||||
arangodb.ERROR_HTTP_NOT_FOUND,
|
||||
arangodb.errors.ERROR_HTTP_NOT_FOUND.message);
|
||||
return;
|
||||
}
|
||||
|
||||
AQL_QUERIES_SLOW(true);
|
||||
actions.resultOk(req, res, actions.HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @startDocuBlock PutApiQueryProperties
|
||||
/// @brief chages the configuration for the AQL query tracking
|
||||
///
|
||||
/// @RESTHEADER{PUT /_api/query/properties, Changes the properties for the AQL query tracking}
|
||||
///
|
||||
/// @RESTRETURNCODES
|
||||
///
|
||||
/// @RESTRETURNCODE{200}
|
||||
/// Is returned if the properties were changed successfully.
|
||||
///
|
||||
/// @RESTRETURNCODE{400}
|
||||
/// The server will respond with *HTTP 400* in case of a malformed request,
|
||||
///
|
||||
/// @endDocuBlock
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function put_api_query (req, res) {
|
||||
|
||||
if (req.suffix.length !== 1 ||
|
||||
req.suffix[0] !== "properties") {
|
||||
actions.resultNotFound(req,
|
||||
res,
|
||||
arangodb.ERROR_HTTP_NOT_FOUND,
|
||||
arangodb.errors.ERROR_HTTP_NOT_FOUND.message);
|
||||
return;
|
||||
}
|
||||
|
||||
var json = actions.getJsonBody(req, res);
|
||||
|
||||
if (json === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var result = AQL_QUERIES_PROPERTIES(json);
|
||||
|
||||
if (result instanceof ArangoError) {
|
||||
actions.resultBad(req, res, result.errorNum, result.errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
actions.resultOk(req, res, actions.HTTP_OK, result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @startDocuBlock JSF_post_api_query
|
||||
/// @brief parse an AQL query and return information about it
|
||||
|
@ -144,10 +300,22 @@ actions.defineHttp({
|
|||
callback : function (req, res) {
|
||||
try {
|
||||
switch (req.requestType) {
|
||||
case actions.GET:
|
||||
get_api_query(req, res);
|
||||
break;
|
||||
|
||||
case actions.PUT:
|
||||
put_api_query(req, res);
|
||||
break;
|
||||
|
||||
case actions.POST:
|
||||
post_api_query(req, res);
|
||||
break;
|
||||
|
||||
|
||||
case actions.DELETE:
|
||||
delete_api_query(req, res);
|
||||
break;
|
||||
|
||||
default:
|
||||
actions.resultUnsupported(req, res);
|
||||
}
|
||||
|
|
|
@ -904,6 +904,22 @@ char* TRI_StringUInt64Octal (uint64_t attr) {
|
|||
return TRI_DuplicateString2(buffer, len);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief converts a time stamp to a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string TRI_StringTimeStamp (double stamp) {
|
||||
char buffer[32];
|
||||
size_t len;
|
||||
struct tm tb;
|
||||
time_t tt = static_cast<time_t>(stamp);
|
||||
|
||||
TRI_gmtime(tt, &tb);
|
||||
len = strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", &tb);
|
||||
|
||||
return std::string(buffer, len);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -318,6 +318,12 @@ char* TRI_StringUInt32Octal (uint32_t);
|
|||
|
||||
char* TRI_StringUInt64Octal (uint64_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief converts a time stamp to a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string TRI_StringTimeStamp (double);
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue