1
0
Fork 0

Merge branch 'devel' of ssh://github.com/ArangoDB/ArangoDB into devel

This commit is contained in:
Max Neunhoeffer 2016-04-18 16:24:28 +02:00
commit 16769c59b4
33 changed files with 1087 additions and 760 deletions

View File

@ -133,10 +133,13 @@ class Dumper {
}
}
void handleUnsupportedType(Slice const*) {
void handleUnsupportedType(Slice const* slice) {
if (options->unsupportedTypeBehavior == Options::NullifyUnsupportedType) {
_sink->append("null", 4);
return;
} else if (options->unsupportedTypeBehavior == Options::ConvertUnsupportedType) {
_sink->append(std::string("\"(non-representable type ") + slice->typeName() + ")\"");
return;
}
throw Exception(Exception::NoJsonEquivalent);

View File

@ -62,6 +62,7 @@ struct CustomTypeHandler {
struct Options {
enum UnsupportedTypeBehavior {
NullifyUnsupportedType,
ConvertUnsupportedType,
FailOnUnsupportedType
};

View File

@ -69,6 +69,9 @@ class Slice {
// creates a slice of type None
static Slice noneSlice() { return Slice("\x00"); }
// creates a slice of type Illegal
static Slice illegalSlice() { return Slice("\x17"); }
// creates a slice of type Null
static Slice nullSlice() { return Slice("\x18"); }
@ -114,12 +117,12 @@ class Slice {
// No destructor, does not take part in memory management,
// get the type for the slice
inline ValueType type() const { return TypeMap[head()]; }
inline ValueType type() const throw() { return TypeMap[head()]; }
char const* typeName() const { return valueTypeName(type()); }
// pointer to the head byte
uint8_t const* start() const { return _start; }
uint8_t const* start() const throw() { return _start; }
// Set new memory position
void set(uint8_t const* s) { _start = s; }
@ -131,7 +134,7 @@ class Slice {
}
// value of the head byte
inline uint8_t head() const { return *_start; }
inline uint8_t head() const throw() { return *_start; }
// hashes the binary representation of a value
inline uint64_t hash(uint64_t seed = 0xdeadbeef) const {
@ -144,76 +147,79 @@ class Slice {
uint64_t normalizedHash(uint64_t seed = 0xdeadbeef) const;
// check if slice is of the specified type
inline bool isType(ValueType t) const { return type() == t; }
inline bool isType(ValueType t) const throw() { return TypeMap[*_start] == t; }
// check if slice is a None object
bool isNone() const { return isType(ValueType::None); }
bool isNone() const throw() { return isType(ValueType::None); }
// check if slice is an Illegal object
bool isIllegal() const throw() { return isType(ValueType::Illegal); }
// check if slice is a Null object
bool isNull() const { return isType(ValueType::Null); }
bool isNull() const throw() { return isType(ValueType::Null); }
// check if slice is a Bool object
bool isBool() const { return isType(ValueType::Bool); }
bool isBool() const throw() { return isType(ValueType::Bool); }
// check if slice is a Bool object - this is an alias for isBool()
bool isBoolean() const { return isBool(); }
bool isBoolean() const throw() { return isBool(); }
// check if slice is the Boolean value true
bool isTrue() const { return head() == 0x1a; }
bool isTrue() const throw() { return head() == 0x1a; }
// check if slice is the Boolean value false
bool isFalse() const { return head() == 0x19; }
bool isFalse() const throw() { return head() == 0x19; }
// check if slice is an Array object
bool isArray() const { return isType(ValueType::Array); }
bool isArray() const throw() { return isType(ValueType::Array); }
// check if slice is an Object object
bool isObject() const { return isType(ValueType::Object); }
bool isObject() const throw() { return isType(ValueType::Object); }
// check if slice is a Double object
bool isDouble() const { return isType(ValueType::Double); }
bool isDouble() const throw() { return isType(ValueType::Double); }
// check if slice is a UTCDate object
bool isUTCDate() const { return isType(ValueType::UTCDate); }
bool isUTCDate() const throw() { return isType(ValueType::UTCDate); }
// check if slice is an External object
bool isExternal() const { return isType(ValueType::External); }
bool isExternal() const throw() { return isType(ValueType::External); }
// check if slice is a MinKey object
bool isMinKey() const { return isType(ValueType::MinKey); }
bool isMinKey() const throw() { return isType(ValueType::MinKey); }
// check if slice is a MaxKey object
bool isMaxKey() const { return isType(ValueType::MaxKey); }
bool isMaxKey() const throw() { return isType(ValueType::MaxKey); }
// check if slice is an Int object
bool isInt() const { return isType(ValueType::Int); }
bool isInt() const throw() { return isType(ValueType::Int); }
// check if slice is a UInt object
bool isUInt() const { return isType(ValueType::UInt); }
bool isUInt() const throw() { return isType(ValueType::UInt); }
// check if slice is a SmallInt object
bool isSmallInt() const { return isType(ValueType::SmallInt); }
bool isSmallInt() const throw() { return isType(ValueType::SmallInt); }
// check if slice is a String object
bool isString() const { return isType(ValueType::String); }
bool isString() const throw() { return isType(ValueType::String); }
// check if slice is a Binary object
bool isBinary() const { return isType(ValueType::Binary); }
bool isBinary() const throw() { return isType(ValueType::Binary); }
// check if slice is a BCD
bool isBCD() const { return isType(ValueType::BCD); }
bool isBCD() const throw() { return isType(ValueType::BCD); }
// check if slice is a Custom type
bool isCustom() const { return isType(ValueType::Custom); }
bool isCustom() const throw() { return isType(ValueType::Custom); }
// check if a slice is any number type
bool isInteger() const {
bool isInteger() const throw() {
return isType(ValueType::Int) || isType(ValueType::UInt) ||
isType(ValueType::SmallInt);
}
// check if slice is any Number-type object
bool isNumber() const { return isInteger() || isDouble(); }
bool isNumber() const throw() { return isInteger() || isDouble(); }
bool isSorted() const {
auto const h = head();
@ -599,6 +605,7 @@ class Slice {
ValueLength byteSize() const {
switch (type()) {
case ValueType::None:
case ValueType::Illegal:
case ValueType::Null:
case ValueType::Bool:
case ValueType::MinKey:
@ -736,6 +743,9 @@ class Slice {
std::string hexType() const;
private:
// translates an integer key into a string, without checks
Slice translateUnchecked() const;
Slice getFromCompactObject(std::string const& attribute) const;
ValueLength findDataOffset(uint8_t head) const {

View File

@ -35,8 +35,9 @@ namespace arangodb {
namespace velocypack {
enum class ValueType {
None, // not yet initialized
Null, // JSON null
None, // not yet initialized
Illegal, // illegal value
Null, // JSON null
Bool,
Array,
Object,

View File

@ -650,6 +650,11 @@ uint8_t* Builder::set(Value const& item) {
_pos += v;
break;
}
case ValueType::Illegal: {
reserveSpace(1);
_start[_pos++] = 0x17;
break;
}
case ValueType::MinKey: {
reserveSpace(1);
_start[_pos++] = 0x1e;

View File

@ -396,6 +396,7 @@ void Dumper::dumpValue(Slice const* slice, Slice const* base) {
break;
}
case ValueType::Illegal:
case ValueType::MinKey:
case ValueType::MaxKey: {
handleUnsupportedType(slice);

View File

@ -53,7 +53,7 @@ VT const Slice::TypeMap[256] = {
/* 0x10 */ VT::Object, /* 0x11 */ VT::Object,
/* 0x12 */ VT::Object, /* 0x13 */ VT::Array,
/* 0x14 */ VT::Object, /* 0x15 */ VT::None,
/* 0x16 */ VT::None, /* 0x17 */ VT::None,
/* 0x16 */ VT::None, /* 0x17 */ VT::Illegal,
/* 0x18 */ VT::Null, /* 0x19 */ VT::Bool,
/* 0x1a */ VT::Bool, /* 0x1b */ VT::Double,
/* 0x1c */ VT::UTCDate, /* 0x1d */ VT::External,
@ -231,12 +231,19 @@ Slice Slice::translate() const {
throw Exception(Exception::InvalidValueType,
"Cannot translate key of this type");
}
uint64_t id = getUInt();
if (attributeTranslator == nullptr) {
throw Exception(Exception::NeedAttributeTranslator);
}
return translateUnchecked();
}
return Slice(attributeTranslator->translate(id));
// translates an integer key into a string, without checks
Slice Slice::translateUnchecked() const {
uint8_t const* result = attributeTranslator->translate(getUInt());
if (result == nullptr) {
return Slice();
}
return Slice(result);
}
// check if two Slices are equal on the binary level
@ -581,7 +588,10 @@ Slice Slice::makeKey() const {
return *this;
}
if (isSmallInt() || isUInt()) {
return translate();
if (attributeTranslator == nullptr) {
throw Exception(Exception::NeedAttributeTranslator);
}
return translateUnchecked();
}
throw Exception(Exception::InvalidValueType,
@ -615,6 +625,8 @@ ValueLength Slice::getNthOffsetFromCompact(ValueLength index) const {
Slice Slice::searchObjectKeyLinear(std::string const& attribute,
ValueLength ieBase, ValueLength offsetSize,
ValueLength n) const {
bool const useTranslator = (attributeTranslator != nullptr);
for (ValueLength index = 0; index < n; ++index) {
ValueLength offset = ieBase + index * offsetSize;
Slice key(_start + readInteger<ValueLength>(_start + offset, offsetSize));
@ -625,7 +637,11 @@ Slice Slice::searchObjectKeyLinear(std::string const& attribute,
}
} else if (key.isSmallInt() || key.isUInt()) {
// translate key
if (!key.translate().isEqualString(attribute)) {
if (!useTranslator) {
// no attribute translator
throw Exception(Exception::NeedAttributeTranslator);
}
if (!key.translateUnchecked().isEqualString(attribute)) {
continue;
}
} else {
@ -645,6 +661,7 @@ Slice Slice::searchObjectKeyLinear(std::string const& attribute,
Slice Slice::searchObjectKeyBinary(std::string const& attribute,
ValueLength ieBase, ValueLength offsetSize,
ValueLength n) const {
bool const useTranslator = (attributeTranslator != nullptr);
VELOCYPACK_ASSERT(n > 0);
ValueLength l = 0;
@ -662,7 +679,11 @@ Slice Slice::searchObjectKeyBinary(std::string const& attribute,
res = key.compareString(attribute);
} else if (key.isSmallInt() || key.isUInt()) {
// translate key
res = key.translate().compareString(attribute);
if (!useTranslator) {
// no attribute translator
throw Exception(Exception::NeedAttributeTranslator);
}
res = key.translateUnchecked().compareString(attribute);
} else {
// invalid key
return Slice();

View File

@ -34,6 +34,8 @@ char const* arangodb::velocypack::valueTypeName(ValueType type) {
switch (type) {
case ValueType::None:
return "none";
case ValueType::Illegal:
return "illegal";
case ValueType::Null:
return "null";
case ValueType::Bool:

View File

@ -170,6 +170,8 @@ the sort parameter.
v2.8.8 (????-??-??)
-------------------
* fixed issue #1805: Query: internal error (location: arangod/Aql/AqlValue.cpp:182). Please report this error to arangodb.com (while executing)
* allow specifying collection name prefixes for `_from` and `_to` in arangoimp:
To avoid specifying complete document ids (consisting of collection names and document

View File

@ -220,6 +220,7 @@ bool Agent::recvAppendEntriesRPC (term_t term, id_t leaderId, index_t prevIndex,
<< " entries to state machine.";
/* bool success = */
_state.log (queries, term, leaderId, prevIndex, prevTerm);
// _constituent.vote();
} else {
// heart-beat
}
@ -370,7 +371,7 @@ void Agent::run() {
while (!this->isStopping() && size() > 1) { // need only to run in multi-host
if (leading())
_cv.wait(250000); // Only if leading
_cv.wait(500000); // Only if leading
else
_cv.wait(); // Just sit there doing nothing

View File

@ -107,24 +107,31 @@ duration_t Constituent::sleepFor (double min_t, double max_t) {
// Get my term
term_t Constituent::term() const {
MUTEX_LOCKER (guard, _castLock);
return _term;
}
// Update my term
void Constituent::term(term_t t) {
if (_term != t) {
term_t tmp;
{
MUTEX_LOCKER (guard, _castLock);
tmp = _term;
_term = t;
}
if (tmp != t) {
LOG_TOPIC(INFO, Logger::AGENCY) << "Updating term to " << t;
Builder body;
body.add(VPackValue(VPackValueType::Object));
std::ostringstream i_str;
i_str << std::setw(20) << std::setfill('0') << _term;
i_str << std::setw(20) << std::setfill('0') << t;
body.add("_key", Value(i_str.str()));
body.add("term", Value(_term));
body.add("term", Value(t));
body.add("voted_for", Value((uint32_t)_voted_for));
body.close();
@ -153,21 +160,24 @@ void Constituent::term(term_t t) {
/// @brief My role
role_t Constituent::role () const {
MUTEX_LOCKER (guard, _castLock);
return _role;
}
/// @brief Become follower in term
void Constituent::follow (term_t t) {
MUTEX_LOCKER(guard, _castLock);
if (_role != FOLLOWER) {
LOG_TOPIC(INFO, Logger::AGENCY)
<< "Role change: Converted to follower in term " << t;
<< "Role change: Converting to follower in term " << t;
}
this->term(t);
_term = t;
_role = FOLLOWER;
}
/// @brief Become leader
void Constituent::lead () {
MUTEX_LOCKER(guard, _castLock);
if (_role != LEADER) {
LOG_TOPIC(INFO, Logger::AGENCY)
<< "Role change: Converted to leader in term " << _term ;
@ -179,6 +189,7 @@ void Constituent::lead () {
/// @brief Become follower
void Constituent::candidate () {
MUTEX_LOCKER(guard, _castLock);
if (_role != CANDIDATE)
LOG_TOPIC(INFO, Logger::AGENCY)
<< "Role change: Converted to candidate in term " << _term ;
@ -187,16 +198,19 @@ void Constituent::candidate () {
/// @brief Leading?
bool Constituent::leading () const {
MUTEX_LOCKER(guard, _castLock);
return _role == LEADER;
}
/// @brief Following?
bool Constituent::following () const {
MUTEX_LOCKER(guard, _castLock);
return _role == FOLLOWER;
}
/// @brief Runnig as candidate?
bool Constituent::running () const {
MUTEX_LOCKER(guard, _castLock);
return _role == CANDIDATE;
}
@ -256,14 +270,25 @@ size_t Constituent::notifyAll () {
/// @brief Vote
bool Constituent::vote (
term_t term, id_t id, index_t prevLogIndex, term_t prevLogTerm) {
if (term > _term || (_term==term&&_leader_id==id)) {
term_t t = 0;
id_t lid = 0;
{
MUTEX_LOCKER(guard,_castLock);
t = _term;
lid = _leader_id;
}
if (term > t || (t == term && lid == id)) {
this->term(term);
_cast = true; // Note that I voted this time around.
_voted_for = id; // The guy I voted for I assume leader.
_leader_id = id;
if (_role>FOLLOWER)
{
MUTEX_LOCKER(guard,_castLock);
_cast = true; // Note that I voted this time around.
_voted_for = id; // The guy I voted for I assume leader.
_leader_id = id;
}
if (_role>FOLLOWER) {
follow (_term);
_agent->persist(_term,_voted_for);
}
_agent->persist(term,id);
_cv.signal();
return true;
} else { // Myself running or leading
@ -271,17 +296,6 @@ bool Constituent::vote (
}
}
/// @brief Implementation of a gossip protocol
void Constituent::gossip (const constituency_t& constituency) {
// TODO: Replace lame notification by gossip protocol
}
/// @brief Implementation of a gossip protocol
const constituency_t& Constituent::gossip () {
// TODO: Replace lame notification by gossip protocol
return _constituency;
}
/// @brief Call to election
void Constituent::callElection() {
@ -417,8 +431,11 @@ void Constituent::run() {
}
// Always start off as follower
while (!this->isStopping() && size() > 1) {
while (!this->isStopping() && size() > 1) {
if (_role == FOLLOWER) {
bool cast = false;
{
MUTEX_LOCKER(guard, _castLock);
_cast = false; // New round set not cast vote
@ -426,13 +443,15 @@ void Constituent::run() {
dist_t dis(config().min_ping, config().max_ping);
long rand_wait = static_cast<long>(dis(_gen)*1000000.0);
bool timedout = _cv.wait(rand_wait);
/*bool timedout =*/ _cv.wait(rand_wait);
{
MUTEX_LOCKER(guard, _castLock);
if (!_cast) {
candidate(); // Next round, we are running
}
cast = _cast;
}
if (!cast) {
candidate(); // Next round, we are running
}
} else {
callElection(); // Run for office

View File

@ -68,12 +68,6 @@ public:
/// @brief Get current role
role_t role() const;
/// @brief Gossip protocol: listen
void gossip(constituency_t const&);
/// @brief Gossip protocol: talk
const constituency_t& gossip();
/// @brief Are we leading?
bool leading() const;
@ -158,7 +152,7 @@ private:
id_t _voted_for;
arangodb::basics::ConditionVariable _cv; // agency callbacks
arangodb::Mutex _castLock;
mutable arangodb::Mutex _castLock;
};

View File

@ -75,7 +75,7 @@ void RestAgencyHandler::redirectRequest(id_t leaderId) {
try {
std::string url = Endpoint::uriForm(
_agent->config().end_points.at(leaderId));
_agent->config().end_points.at(leaderId)) + _request->requestPath();
createResponse(GeneralResponse::ResponseCode::TEMPORARY_REDIRECT);
static std::string const location = "location";
_response->setHeaderNC(location, url);

View File

@ -29,7 +29,7 @@ void SanityCheck::run() {
while (!this->isStopping()) {
if (_agent->leading()) {
timedout = _cv.wait(1000000);
timedout = _cv.wait(250000);//quarter second
} else {
_cv.wait();
}

View File

@ -909,6 +909,15 @@ void Store::dumpToBuilder (Builder& builder) const {
}
}
size_t Store::matchPath (std::vector<std::string> const& pv) const {
// Node* cur(this);
/* for (size_t i = 0; i < pv.size(); ++i) {
if (cur.find(pv.at(i))) {
}
}*/
return 0;
}
// Start thread
bool Store::start () {
Thread::start();

View File

@ -230,6 +230,9 @@ public:
/// @brief Notify observers
void notifyObservers () const;
/// @brief See how far the path matches anything in store
size_t matchPath (std::vector<std::string> const& pv) const;
private:
/// @brief Read individual entry specified in slice into builder
bool read (arangodb::velocypack::Slice const&,

View File

@ -96,7 +96,11 @@ QueryResult Parser::parse(bool withDetails) {
}
// end main scope
scopes->endCurrent();
TRI_ASSERT(scopes->numActive() > 0);
while (scopes->numActive() > 0) {
scopes->endCurrent();
}
TRI_ASSERT(scopes->numActive() == 0);

View File

@ -880,7 +880,6 @@ QueryResult Query::explain() {
enterState(FINALIZATION);
QueryResult result(TRI_ERROR_NO_ERROR);
QueryRegistry localRegistry;
if (allPlans()) {
result.result = std::make_shared<VPackBuilder>();

File diff suppressed because it is too large Load Diff

View File

@ -58,6 +58,33 @@ void Aqlerror (YYLTYPE* locp,
parser->registerParseError(TRI_ERROR_QUERY_PARSE, message, locp->first_line, locp->first_column);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check if any of variables used into the INTO expression was
/// introduced by the COLLECT itself, in which case it would fail
////////////////////////////////////////////////////////////////////////////////
static Variable const* CheckIntoVariables(AstNode const* collectVars,
std::unordered_set<Variable const*> const& vars) {
if (collectVars == nullptr || collectVars->type != NODE_TYPE_ARRAY) {
return nullptr;
}
size_t const n = collectVars->numMembers();
for (size_t i = 0; i < n; ++i) {
auto member = collectVars->getMember(i);
if (member != nullptr) {
TRI_ASSERT(member->type == NODE_TYPE_ASSIGN);
auto v = static_cast<Variable*>(member->getMember(0)->getData());
if (vars.find(v) != vars.end()) {
return v;
}
}
}
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief register variables in the scope
////////////////////////////////////////////////////////////////////////////////
@ -544,6 +571,17 @@ collect_statement:
YYABORT;
}
if ($3 != nullptr && $3->type == NODE_TYPE_ARRAY) {
std::unordered_set<Variable const*> vars;
Ast::getReferencedVariables($3->getMember(1), vars);
Variable const* used = CheckIntoVariables($2, vars);
if (used != nullptr) {
std::string msg("use of COLLECT variable '" + used->name + "' IN INTO expression");
parser->registerParseError(TRI_ERROR_QUERY_PARSE, msg.c_str(), yylloc.first_line, yylloc.first_column);
}
}
AstNode const* into = GetIntoVariable(parser, $3);
AstNode const* intoExpression = GetIntoExpression($3);
@ -563,6 +601,22 @@ collect_statement:
YYABORT;
}
if ($3 != nullptr && $3->type == NODE_TYPE_ARRAY) {
std::unordered_set<Variable const*> vars;
Ast::getReferencedVariables($3->getMember(1), vars);
Variable const* used = CheckIntoVariables($1, vars);
if (used != nullptr) {
std::string msg("use of COLLECT variable '" + used->name + "' IN INTO expression");
parser->registerParseError(TRI_ERROR_QUERY_PARSE, msg.c_str(), yylloc.first_line, yylloc.first_column);
}
used = CheckIntoVariables($2, vars);
if (used != nullptr) {
std::string msg("use of COLLECT variable '" + used->name + "' IN INTO expression");
parser->registerParseError(TRI_ERROR_QUERY_PARSE, msg.c_str(), yylloc.first_line, yylloc.first_column);
}
}
// note all group variables
std::unordered_set<Variable const*> groupVars;
size_t n = $1->numMembers();
@ -609,6 +663,17 @@ collect_statement:
RegisterAssignVariables(scopes, $1);
}
if ($2 != nullptr && $2->type == NODE_TYPE_ARRAY) {
std::unordered_set<Variable const*> vars;
Ast::getReferencedVariables($2->getMember(1), vars);
Variable const* used = CheckIntoVariables($1, vars);
if (used != nullptr) {
std::string msg("use of COLLECT variable '" + used->name + "' IN INTO expression");
parser->registerParseError(TRI_ERROR_QUERY_PARSE, msg.c_str(), yylloc.first_line, yylloc.first_column);
}
}
AstNode const* into = GetIntoVariable(parser, $2);
AstNode const* intoExpression = GetIntoExpression($2);
@ -627,6 +692,17 @@ collect_statement:
$3 != nullptr) {
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "use of 'KEEP' without 'INTO'", yylloc.first_line, yylloc.first_column);
}
if ($2 != nullptr && $2->type == NODE_TYPE_ARRAY) {
std::unordered_set<Variable const*> vars;
Ast::getReferencedVariables($2->getMember(1), vars);
Variable const* used = CheckIntoVariables($1, vars);
if (used != nullptr) {
std::string msg("use of COLLECT variable '" + used->name + "' IN INTO expression");
parser->registerParseError(TRI_ERROR_QUERY_PARSE, msg.c_str(), yylloc.first_line, yylloc.first_column);
}
}
AstNode const* into = GetIntoVariable(parser, $2);
AstNode const* intoExpression = GetIntoExpression($2);

View File

@ -73,6 +73,8 @@ add_executable(${BIN_ARANGOD}
Agency/ApplicationAgency.cpp
Agency/Constituent.cpp
Agency/SanityCheck.cpp
Agency/RestAgencyHandler.cpp
Agency/RestAgencyPrivHandler.cpp
Agency/State.cpp
Agency/Store.cpp
Agency/StoreCallback.cpp
@ -190,8 +192,6 @@ add_executable(${BIN_ARANGOD}
Replication/InitialSyncer.cpp
Replication/Syncer.cpp
RestHandler/RestAdminLogHandler.cpp
RestHandler/RestAgencyHandler.cpp
RestHandler/RestAgencyPrivHandler.cpp
RestHandler/RestBaseHandler.cpp
RestHandler/RestBatchHandler.cpp
RestHandler/RestCursorHandler.cpp

View File

@ -35,6 +35,8 @@
#include "Actions/actions.h"
#include "Agency/Agent.h"
#include "Agency/ApplicationAgency.h"
#include "Agency/RestAgencyHandler.h"
#include "Agency/RestAgencyPrivHandler.h"
#include "ApplicationServer/ApplicationServer.h"
#include "Aql/Query.h"
#include "Aql/QueryCache.h"
@ -65,8 +67,6 @@
#include "Rest/OperationMode.h"
#include "Rest/Version.h"
#include "RestHandler/RestAdminLogHandler.h"
#include "RestHandler/RestAgencyHandler.h"
#include "RestHandler/RestAgencyPrivHandler.h"
#include "RestHandler/RestBatchHandler.h"
#include "RestHandler/RestCursorHandler.h"
#include "RestHandler/RestDebugHandler.h"

View File

@ -150,7 +150,7 @@
rerenderValues: function(data) {
// TODO cache value state like graph data
//TODO cache value state like graph data
//Connections
this.renderValue('#clusterConnections', Math.round(data.clientConnectionsCurrent));
@ -160,12 +160,9 @@
var totalMem = data.physicalMemory;
var usedMem = data.residentSizeCurrent;
this.renderValue('#clusterRam', [usedMem, totalMem]);
//NODES
this.renderValue('#clusterNodes', this.statCollectCoord.size());
},
renderValue: function(id, value) {
renderValue: function(id, value, error) {
if (typeof value === 'number') {
$(id).html(value);
}
@ -175,11 +172,60 @@
var percent = 1 / (b/a) * 100;
$(id).html(percent.toFixed(1) + ' %');
}
else if (typeof value === 'string') {
$(id).html(value);
}
if (error) {
$(id).addClass('negative');
$(id).removeClass('positive');
}
else {
$(id).addClass('positive');
$(id).removeClass('negative');
}
},
updateValues: function() {
this.renderValue('#clusterNodes', this.statCollectCoord.size());
this.renderValue('#clusterRam', [1024, 4096]);
var self = this;
this.coordinators.fetch({
success: function() {
self.renderNode(true);
},
error: function() {
self.renderNode(false);
}
});
//this.renderValue('#clusterRam', [1024, 4096]);
},
renderNode: function(connection) {
var ok = 0, error = 0;
if (connection) {
this.coordinators.each(function(value) {
if (value.toJSON().status === 'ok') {
ok++;
}
else {
error++;
}
});
if (error > 0) {
var total = error + ok;
this.renderValue('#clusterNodes', ok + '/' + total, true);
}
else {
this.renderValue('#clusterNodes', ok);
}
}
else {
this.renderValue('#clusterNodes', 'OFFLINE', true);
}
},
initValues: function() {
@ -446,7 +492,6 @@
var mergeHistory = function(data) {
var onetime = ['times'];
var values = [
'physicalMemory',

View File

@ -18,7 +18,7 @@
initialize: function () {
//also server online check
var self = this;
window.setInterval(function(){
window.setInterval(function() {
self.getVersion();
}, 15000);
self.getVersion();
@ -51,45 +51,51 @@
else {
self.collection.fetch({
success: function() {
self.renderClusterState();
self.renderClusterState(true);
},
error: function() {
self.renderClusterState(false);
}
});
}
},
renderClusterState: function() {
renderClusterState: function(connection) {
var ok = 0, error = 0;
this.collection.each(function(value) {
if (value.toJSON().status === 'ok') {
ok++;
}
else {
error++;
}
});
if (connection) {
this.collection.each(function(value) {
if (value.toJSON().status === 'ok') {
ok++;
}
else {
error++;
}
});
if (error > 0) {
$('#healthStatus').removeClass('positive');
$('#healthStatus').addClass('negative');
if (error === 1) {
$('.health-state').html(error + ' NODE ERROR');
if (error > 0) {
$('#healthStatus').removeClass('positive');
$('#healthStatus').addClass('negative');
if (error === 1) {
$('.health-state').html(error + ' NODE ERROR');
}
else {
$('.health-state').html(error + ' NODES ERROR');
}
$('.health-icon').html('<i class="fa fa-exclamation-circle"></i>');
}
else {
$('.health-state').html(error + ' NODES ERROR');
$('#healthStatus').removeClass('negative');
$('#healthStatus').addClass('positive');
$('.health-state').html('NODES OK');
$('.health-icon').html('<i class="fa fa-check-circle"></i>');
}
$('.health-icon').html('<i class="fa fa-exclamation-circle"></i>');
}
else {
$('#healthStatus').removeClass('negative');
$('#healthStatus').addClass('positive');
if (ok === 1) {
$('.health-state').html(ok + ' NODE OK');
}
else {
$('.health-state').html(ok + ' NODES OK');
}
$('.health-icon').html('<i class="fa fa-check-circle"></i>');
$('#healthStatus').removeClass('positive');
$('#healthStatus').addClass('negative');
$('.health-state').html(window.location.host + ' OFFLINE');
$('.health-icon').html('<i class="fa fa-exclamation-circle"></i>');
}
},

View File

@ -34,17 +34,16 @@
},
breadcrumb: function(name) {
console.log("yes");
$('#subNavigationBar .breadcrumb').html("Node: " + name);
},
render: function () {
console.log(1);
this.$el.html(this.template.render({coords: []}));
var callback = function() {
this.continueRender();
this.breadcrumb(this.coordname);
$(window).trigger('resize');
}.bind(this);
if (!this.initDone) {
@ -58,6 +57,8 @@
},
continueRender: function() {
var self = this;
this.dashboards[this.coordinator.get('name')] = new window.DashboardView({
dygraphConfig: window.dygraphConfig,
database: window.App.arangoDatabase,
@ -69,6 +70,9 @@
}
});
this.dashboards[this.coordinator.get('name')].render();
window.setTimeout(function() {
self.dashboards[self.coordinator.get('name')].resize();
}, 100);
},
waitForCoordinators: function(callback) {

View File

@ -58,7 +58,6 @@
continueRender: function() {
var coords = this.coordinators.toJSON();
console.log(coords);
this.$el.html(this.template.render({
coords: coords
}));

View File

@ -17,11 +17,21 @@
border: 1px solid $c-content-border;
margin-left: -1px;
margin-top: -1px;
padding: {
bottom: 10px;
left: 20px;
right: 20px;
top: 20px;
}
.nv-controlsWrap {
display: none;
}
.nv-legendWrap {
margin-bottom: 10px;
}
svg {
height: 250px;
margin-left: -17px;
@ -42,10 +52,19 @@
margin-top: -1px;
.value {
color: $c-positive;
color: $c-black;
font-size: 24pt;
line-height: 150px;
text-align: center;
&.positive {
color: $c-positive;
}
&.negative {
color: $c-negative;
}
}
div:first-child {

View File

@ -1,5 +1,5 @@
/*jshint globalstrict:false, strict:false, maxlen: 500 */
/*global assertEqual, assertTrue, AQL_EXECUTE */
/*global assertEqual, assertTrue, fail, AQL_EXECUTE */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for COLLECT w/ INTO var = expr
@ -30,12 +30,23 @@
var jsunity = require("jsunity");
var db = require("@arangodb").db;
var internal = require("internal");
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function optimizerCollectExpressionTestSuite () {
var assertFailingQuery = function (query) {
try {
AQL_EXECUTE(query);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_QUERY_PARSE.code, err.errorNum);
}
};
var c;
return {
@ -202,6 +213,15 @@ function optimizerCollectExpressionTestSuite () {
for (i = 0; i < 500; ++i) {
assertTrue(typeof results.json[1].ages[i] === 'number');
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test expression
////////////////////////////////////////////////////////////////////////////////
testIntoWithOutVariableUsedInAssignment : function () {
assertFailingQuery("FOR doc IN [{ age: 1, value: 1 }, { age: 1, value: 2 }, { age: 2, value: 1 }, { age: 2, value: 2 }] COLLECT v1 = doc.age, v2 = doc.value INTO g = v1 RETURN [v1,v2,g]");
assertFailingQuery("FOR doc IN [{ age: 1, value: 1 }, { age: 1, value: 2 }, { age: 2, value: 1 }, { age: 2, value: 2 }] COLLECT v1 = doc.age AGGREGATE v2 = MAX(doc.value) INTO g = v2 RETURN [v1,v2,g]");
}
};

View File

@ -44,49 +44,6 @@ using VelocyPackHelper = arangodb::basics::VelocyPackHelper;
static std::unique_ptr<VPackAttributeTranslator> Translator;
static std::unique_ptr<VPackAttributeExcludeHandler> ExcludeHandler;
////////////////////////////////////////////////////////////////////////////////
/// @brief "constant" global object for NULL which can be shared by all
/// expressions but must never be freed
////////////////////////////////////////////////////////////////////////////////
static VPackBuilder NullBuilder;
////////////////////////////////////////////////////////////////////////////////
/// @brief "constant" global object for TRUE which can be shared by all
/// expressions but must never be freed
////////////////////////////////////////////////////////////////////////////////
static VPackBuilder TrueBuilder;
////////////////////////////////////////////////////////////////////////////////
/// @brief "constant" global object for FALSE which can be shared by all
/// expressions but must never be freed
////////////////////////////////////////////////////////////////////////////////
static VPackBuilder FalseBuilder;
////////////////////////////////////////////////////////////////////////////////
/// @brief "constant" global object for empty ARRAYs which can be shared by all
/// expressions but must never be freed
////////////////////////////////////////////////////////////////////////////////
static VPackBuilder EmptyArrayBuilder;
////////////////////////////////////////////////////////////////////////////////
/// @brief "constant" global object for empty OBJECTs which can be shared by all
/// expressions but must never be freed
////////////////////////////////////////////////////////////////////////////////
static VPackBuilder EmptyObjectBuilder;
////////////////////////////////////////////////////////////////////////////////
/// @brief "constant" global object for illegal slices
/// Are used in Array Indexes to distinguish NULL and not existent.
////////////////////////////////////////////////////////////////////////////////
static VPackBuilder IllegalBuilder;
// attribute exclude handler for skipping over system attributes
struct SystemAttributeExcludeHandler : public VPackAttributeExcludeHandler {
bool shouldExclude(VPackSlice const& key, int nesting) override final {
@ -122,73 +79,27 @@ void VelocyPackHelper::initialize() {
Translator.reset(new VPackAttributeTranslator);
// these attribute names will be translated into short integer values
Translator->add("_key", 1);
Translator->add("_rev", 2);
Translator->add("_id", 3);
Translator->add("_from", 4);
Translator->add("_to", 5);
Translator->add("_key", 1); // TRI_VOC_ATTRIBUTE_KEY
Translator->add("_rev", 2); // TRI_VOC_ATTRIBUTE_REV
Translator->add("_id", 3); // TRI_VOC_ATTRIBUTE_ID
Translator->add("_from", 4); // TRI_VOC_ATTRIBUTE_FROM
Translator->add("_to", 5); // TRI_VOC_ATTRIBUTE_TO
Translator->seal();
// set the attribute translator in the global options
VPackOptions::Defaults.attributeTranslator = Translator.get();
VPackSlice::attributeTranslator = Translator.get();
// VPackOptions::Defaults.unsupportedTypeBehavior = VPackOptions::ConvertUnsupportedType;
// initialize exclude handler for system attributes
ExcludeHandler.reset(new SystemAttributeExcludeHandler);
// Null value
NullBuilder.add(VPackValue(VPackValueType::Null));
// True value
TrueBuilder.add(VPackValue(true));
// False value
FalseBuilder.add(VPackValue(false));
// Array value (empty)
EmptyArrayBuilder.openArray();
EmptyArrayBuilder.close();
// Object value (empty)
EmptyObjectBuilder.openObject();
EmptyObjectBuilder.close();
// Illegal value
IllegalBuilder.add(VPackValue(VPackValueType::MinKey));
}
void VelocyPackHelper::disableAssemblerFunctions() {
arangodb::velocypack::disableAssemblerFunctions();
}
arangodb::velocypack::Slice VelocyPackHelper::NullValue() {
return NullBuilder.slice();
}
arangodb::velocypack::Slice VelocyPackHelper::TrueValue() {
return TrueBuilder.slice();
}
arangodb::velocypack::Slice VelocyPackHelper::FalseValue() {
return FalseBuilder.slice();
}
arangodb::velocypack::Slice VelocyPackHelper::BooleanValue(bool value) {
if (value) {
return TrueBuilder.slice();
}
return FalseBuilder.slice();
}
arangodb::velocypack::Slice VelocyPackHelper::EmptyArrayValue() {
return EmptyArrayBuilder.slice();
}
arangodb::velocypack::Slice VelocyPackHelper::EmptyObjectValue() {
return EmptyObjectBuilder.slice();
}
arangodb::velocypack::Slice VelocyPackHelper::IllegalValue() {
return IllegalBuilder.slice();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the (global) attribute exclude handler instance
////////////////////////////////////////////////////////////////////////////////
@ -222,7 +133,9 @@ bool VelocyPackHelper::VPackEqual::operator()(VPackSlice const& lhs, VPackSlice
static int TypeWeight(VPackSlice const& slice) {
switch (slice.type()) {
case VPackValueType::MinKey:
return -1;
return -99; // must be lowest
case VPackValueType::Illegal:
return -1;
case VPackValueType::None:
case VPackValueType::Null:
return 0;
@ -232,14 +145,19 @@ static int TypeWeight(VPackSlice const& slice) {
case VPackValueType::Int:
case VPackValueType::UInt:
case VPackValueType::SmallInt:
case VPackValueType::UTCDate:
case VPackValueType::BCD:
return 2;
case VPackValueType::String:
case VPackValueType::Binary:
case VPackValueType::Custom:
// custom type is used for id
// custom type is used for _id (which is a string)
return 3;
case VPackValueType::Array:
return 4;
case VPackValueType::Object:
case VPackValueType::External:
// External type is used for documents
return 5;
default:
// All other values have equal weight
@ -247,6 +165,41 @@ static int TypeWeight(VPackSlice const& slice) {
}
}
int VelocyPackHelper::compareNumberValues(VPackSlice const& lhs, VPackSlice const& rhs) {
VPackValueType const lType = lhs.type();
if (lType == rhs.type()) {
// both types are equal
if (lType == VPackValueType::Int || lType == VPackValueType::SmallInt) {
// use exact comparisons. no need to cast to double
int64_t l = lhs.getInt();
int64_t r = rhs.getInt();
if (l == r) {
return 0;
}
return (l < r ? -1 : 1);
}
if (lType == VPackValueType::UInt) {
// use exact comparisons. no need to cast to double
uint64_t l = lhs.getUInt();
uint64_t r = rhs.getUInt();
if (l == r) {
return 0;
}
return (l < r ? -1 : 1);
}
// fallthrough to double comparison
}
double left = lhs.getNumericValue<double>();
double right = rhs.getNumericValue<double>();
if (left == right) {
return 0;
}
return (left < right ? -1 : 1);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a boolean sub-element, or a default if it is does not exist
////////////////////////////////////////////////////////////////////////////////
@ -504,8 +457,10 @@ int VelocyPackHelper::compare(VPackSlice const& lhs, VPackSlice const& rhs,
}
switch (lhs.type()) {
case VPackValueType::Illegal:
case VPackValueType::MinKey:
return 0; // illegal is illegal
case VPackValueType::MaxKey:
return 0;
case VPackValueType::None:
case VPackValueType::Null:
return 0; // null == null;
@ -524,15 +479,7 @@ int VelocyPackHelper::compare(VPackSlice const& lhs, VPackSlice const& rhs,
case VPackValueType::Int:
case VPackValueType::UInt:
case VPackValueType::SmallInt: {
double left = lhs.getNumericValue<double>();
double right = rhs.getNumericValue<double>();
if (left == right) {
return 0;
}
if (left < right) {
return -1;
}
return 1;
return compareNumberValues(lhs, rhs);
}
case VPackValueType::Custom:
case VPackValueType::String: {
@ -683,6 +630,7 @@ double VelocyPackHelper::toDouble(VPackSlice const& slice, bool& failed) {
}
break;
}
case VPackValueType::Illegal:
case VPackValueType::Object:
case VPackValueType::UTCDate:
case VPackValueType::External:
@ -717,7 +665,7 @@ uint64_t VelocyPackHelper::hashByAttributes(
error = TRI_ERROR_CLUSTER_NOT_ALL_SHARDING_ATTRIBUTES_GIVEN;
}
// Null is equal to None/not present
sub = NullBuilder.slice();
sub = VPackSlice::nullSlice();
}
hash = sub.normalizedHash(hash);
}

View File

@ -199,6 +199,13 @@ class VelocyPackHelper {
static bool velocyPackToFile(char const*, VPackSlice const&, bool);
//////////////////////////////////////////////////////////////////////////////
/// @brief Compares two VelocyPack number values
//////////////////////////////////////////////////////////////////////////////
static int compareNumberValues(arangodb::velocypack::Slice const& lhs,
arangodb::velocypack::Slice const& rhs);
//////////////////////////////////////////////////////////////////////////////
/// @brief Compares two VelocyPack slices
//////////////////////////////////////////////////////////////////////////////
@ -227,13 +234,41 @@ class VelocyPackHelper {
static uint64_t hashByAttributes(VPackSlice, std::vector<std::string> const&,
bool, int&, std::string const& key = "");
static arangodb::velocypack::Slice NullValue();
static arangodb::velocypack::Slice TrueValue();
static arangodb::velocypack::Slice FalseValue();
static arangodb::velocypack::Slice BooleanValue(bool);
static arangodb::velocypack::Slice EmptyArrayValue();
static arangodb::velocypack::Slice EmptyObjectValue();
static arangodb::velocypack::Slice IllegalValue();
static inline arangodb::velocypack::Slice NullValue() {
return arangodb::velocypack::Slice::nullSlice();
}
static inline arangodb::velocypack::Slice TrueValue() {
return arangodb::velocypack::Slice::trueSlice();
}
static inline arangodb::velocypack::Slice FalseValue() {
return arangodb::velocypack::Slice::falseSlice();
}
static inline arangodb::velocypack::Slice BooleanValue(bool value) {
if (value) {
return arangodb::velocypack::Slice::trueSlice();
}
return arangodb::velocypack::Slice::falseSlice();
}
static inline arangodb::velocypack::Slice EmptyArrayValue() {
return arangodb::velocypack::Slice::emptyArraySlice();
}
static inline arangodb::velocypack::Slice EmptyObjectValue() {
return arangodb::velocypack::Slice::emptyObjectSlice();
}
//////////////////////////////////////////////////////////////////////////////
/// @brief "constant" global object for illegal slices
/// Are used in Array Indexes to distinguish NULL and not existent.
//////////////////////////////////////////////////////////////////////////////
static inline arangodb::velocypack::Slice IllegalValue() {
return arangodb::velocypack::Slice::illegalSlice();
}
};
}
}