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) { if (options->unsupportedTypeBehavior == Options::NullifyUnsupportedType) {
_sink->append("null", 4); _sink->append("null", 4);
return; return;
} else if (options->unsupportedTypeBehavior == Options::ConvertUnsupportedType) {
_sink->append(std::string("\"(non-representable type ") + slice->typeName() + ")\"");
return;
} }
throw Exception(Exception::NoJsonEquivalent); throw Exception(Exception::NoJsonEquivalent);

View File

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

View File

@ -69,6 +69,9 @@ class Slice {
// creates a slice of type None // creates a slice of type None
static Slice noneSlice() { return Slice("\x00"); } static Slice noneSlice() { return Slice("\x00"); }
// creates a slice of type Illegal
static Slice illegalSlice() { return Slice("\x17"); }
// creates a slice of type Null // creates a slice of type Null
static Slice nullSlice() { return Slice("\x18"); } static Slice nullSlice() { return Slice("\x18"); }
@ -114,12 +117,12 @@ class Slice {
// No destructor, does not take part in memory management, // No destructor, does not take part in memory management,
// get the type for the slice // 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()); } char const* typeName() const { return valueTypeName(type()); }
// pointer to the head byte // pointer to the head byte
uint8_t const* start() const { return _start; } uint8_t const* start() const throw() { return _start; }
// Set new memory position // Set new memory position
void set(uint8_t const* s) { _start = s; } void set(uint8_t const* s) { _start = s; }
@ -131,7 +134,7 @@ class Slice {
} }
// value of the head byte // 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 // hashes the binary representation of a value
inline uint64_t hash(uint64_t seed = 0xdeadbeef) const { inline uint64_t hash(uint64_t seed = 0xdeadbeef) const {
@ -144,76 +147,79 @@ class Slice {
uint64_t normalizedHash(uint64_t seed = 0xdeadbeef) const; uint64_t normalizedHash(uint64_t seed = 0xdeadbeef) const;
// check if slice is of the specified type // 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 // 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 // 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 // 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() // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // check if a slice is any number type
bool isInteger() const { bool isInteger() const throw() {
return isType(ValueType::Int) || isType(ValueType::UInt) || return isType(ValueType::Int) || isType(ValueType::UInt) ||
isType(ValueType::SmallInt); isType(ValueType::SmallInt);
} }
// check if slice is any Number-type object // check if slice is any Number-type object
bool isNumber() const { return isInteger() || isDouble(); } bool isNumber() const throw() { return isInteger() || isDouble(); }
bool isSorted() const { bool isSorted() const {
auto const h = head(); auto const h = head();
@ -599,6 +605,7 @@ class Slice {
ValueLength byteSize() const { ValueLength byteSize() const {
switch (type()) { switch (type()) {
case ValueType::None: case ValueType::None:
case ValueType::Illegal:
case ValueType::Null: case ValueType::Null:
case ValueType::Bool: case ValueType::Bool:
case ValueType::MinKey: case ValueType::MinKey:
@ -736,6 +743,9 @@ class Slice {
std::string hexType() const; std::string hexType() const;
private: private:
// translates an integer key into a string, without checks
Slice translateUnchecked() const;
Slice getFromCompactObject(std::string const& attribute) const; Slice getFromCompactObject(std::string const& attribute) const;
ValueLength findDataOffset(uint8_t head) const { ValueLength findDataOffset(uint8_t head) const {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -170,6 +170,8 @@ the sort parameter.
v2.8.8 (????-??-??) 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: * allow specifying collection name prefixes for `_from` and `_to` in arangoimp:
To avoid specifying complete document ids (consisting of collection names and document 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."; << " entries to state machine.";
/* bool success = */ /* bool success = */
_state.log (queries, term, leaderId, prevIndex, prevTerm); _state.log (queries, term, leaderId, prevIndex, prevTerm);
// _constituent.vote();
} else { } else {
// heart-beat // heart-beat
} }
@ -370,7 +371,7 @@ void Agent::run() {
while (!this->isStopping() && size() > 1) { // need only to run in multi-host while (!this->isStopping() && size() > 1) { // need only to run in multi-host
if (leading()) if (leading())
_cv.wait(250000); // Only if leading _cv.wait(500000); // Only if leading
else else
_cv.wait(); // Just sit there doing nothing _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 // Get my term
term_t Constituent::term() const { term_t Constituent::term() const {
MUTEX_LOCKER (guard, _castLock);
return _term; return _term;
} }
// Update my term // Update my term
void Constituent::term(term_t t) { void Constituent::term(term_t t) {
if (_term != t) { term_t tmp;
{
MUTEX_LOCKER (guard, _castLock);
tmp = _term;
_term = t; _term = t;
}
if (tmp != t) {
LOG_TOPIC(INFO, Logger::AGENCY) << "Updating term to " << t; LOG_TOPIC(INFO, Logger::AGENCY) << "Updating term to " << t;
Builder body; Builder body;
body.add(VPackValue(VPackValueType::Object)); body.add(VPackValue(VPackValueType::Object));
std::ostringstream i_str; 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("_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.add("voted_for", Value((uint32_t)_voted_for));
body.close(); body.close();
@ -153,21 +160,24 @@ void Constituent::term(term_t t) {
/// @brief My role /// @brief My role
role_t Constituent::role () const { role_t Constituent::role () const {
MUTEX_LOCKER (guard, _castLock);
return _role; return _role;
} }
/// @brief Become follower in term /// @brief Become follower in term
void Constituent::follow (term_t t) { void Constituent::follow (term_t t) {
MUTEX_LOCKER(guard, _castLock);
if (_role != FOLLOWER) { if (_role != FOLLOWER) {
LOG_TOPIC(INFO, Logger::AGENCY) 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; _role = FOLLOWER;
} }
/// @brief Become leader /// @brief Become leader
void Constituent::lead () { void Constituent::lead () {
MUTEX_LOCKER(guard, _castLock);
if (_role != LEADER) { if (_role != LEADER) {
LOG_TOPIC(INFO, Logger::AGENCY) LOG_TOPIC(INFO, Logger::AGENCY)
<< "Role change: Converted to leader in term " << _term ; << "Role change: Converted to leader in term " << _term ;
@ -179,6 +189,7 @@ void Constituent::lead () {
/// @brief Become follower /// @brief Become follower
void Constituent::candidate () { void Constituent::candidate () {
MUTEX_LOCKER(guard, _castLock);
if (_role != CANDIDATE) if (_role != CANDIDATE)
LOG_TOPIC(INFO, Logger::AGENCY) LOG_TOPIC(INFO, Logger::AGENCY)
<< "Role change: Converted to candidate in term " << _term ; << "Role change: Converted to candidate in term " << _term ;
@ -187,16 +198,19 @@ void Constituent::candidate () {
/// @brief Leading? /// @brief Leading?
bool Constituent::leading () const { bool Constituent::leading () const {
MUTEX_LOCKER(guard, _castLock);
return _role == LEADER; return _role == LEADER;
} }
/// @brief Following? /// @brief Following?
bool Constituent::following () const { bool Constituent::following () const {
MUTEX_LOCKER(guard, _castLock);
return _role == FOLLOWER; return _role == FOLLOWER;
} }
/// @brief Runnig as candidate? /// @brief Runnig as candidate?
bool Constituent::running () const { bool Constituent::running () const {
MUTEX_LOCKER(guard, _castLock);
return _role == CANDIDATE; return _role == CANDIDATE;
} }
@ -256,14 +270,25 @@ size_t Constituent::notifyAll () {
/// @brief Vote /// @brief Vote
bool Constituent::vote ( bool Constituent::vote (
term_t term, id_t id, index_t prevLogIndex, term_t prevLogTerm) { 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); this->term(term);
_cast = true; // Note that I voted this time around. {
_voted_for = id; // The guy I voted for I assume leader. MUTEX_LOCKER(guard,_castLock);
_leader_id = id; _cast = true; // Note that I voted this time around.
if (_role>FOLLOWER) _voted_for = id; // The guy I voted for I assume leader.
_leader_id = id;
}
if (_role>FOLLOWER) {
follow (_term); follow (_term);
_agent->persist(_term,_voted_for); }
_agent->persist(term,id);
_cv.signal(); _cv.signal();
return true; return true;
} else { // Myself running or leading } 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 /// @brief Call to election
void Constituent::callElection() { void Constituent::callElection() {
@ -417,8 +431,11 @@ void Constituent::run() {
} }
// Always start off as follower // Always start off as follower
while (!this->isStopping() && size() > 1) { while (!this->isStopping() && size() > 1) {
if (_role == FOLLOWER) { if (_role == FOLLOWER) {
bool cast = false;
{ {
MUTEX_LOCKER(guard, _castLock); MUTEX_LOCKER(guard, _castLock);
_cast = false; // New round set not cast vote _cast = false; // New round set not cast vote
@ -426,13 +443,15 @@ void Constituent::run() {
dist_t dis(config().min_ping, config().max_ping); dist_t dis(config().min_ping, config().max_ping);
long rand_wait = static_cast<long>(dis(_gen)*1000000.0); 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); MUTEX_LOCKER(guard, _castLock);
if (!_cast) { cast = _cast;
candidate(); // Next round, we are running }
}
if (!cast) {
candidate(); // Next round, we are running
} }
} else { } else {
callElection(); // Run for office callElection(); // Run for office

View File

@ -68,12 +68,6 @@ public:
/// @brief Get current role /// @brief Get current role
role_t role() const; 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? /// @brief Are we leading?
bool leading() const; bool leading() const;
@ -158,7 +152,7 @@ private:
id_t _voted_for; id_t _voted_for;
arangodb::basics::ConditionVariable _cv; // agency callbacks 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 { try {
std::string url = Endpoint::uriForm( std::string url = Endpoint::uriForm(
_agent->config().end_points.at(leaderId)); _agent->config().end_points.at(leaderId)) + _request->requestPath();
createResponse(GeneralResponse::ResponseCode::TEMPORARY_REDIRECT); createResponse(GeneralResponse::ResponseCode::TEMPORARY_REDIRECT);
static std::string const location = "location"; static std::string const location = "location";
_response->setHeaderNC(location, url); _response->setHeaderNC(location, url);

View File

@ -29,7 +29,7 @@ void SanityCheck::run() {
while (!this->isStopping()) { while (!this->isStopping()) {
if (_agent->leading()) { if (_agent->leading()) {
timedout = _cv.wait(1000000); timedout = _cv.wait(250000);//quarter second
} else { } else {
_cv.wait(); _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 // Start thread
bool Store::start () { bool Store::start () {
Thread::start(); Thread::start();

View File

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

View File

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

View File

@ -880,7 +880,6 @@ QueryResult Query::explain() {
enterState(FINALIZATION); enterState(FINALIZATION);
QueryResult result(TRI_ERROR_NO_ERROR); QueryResult result(TRI_ERROR_NO_ERROR);
QueryRegistry localRegistry;
if (allPlans()) { if (allPlans()) {
result.result = std::make_shared<VPackBuilder>(); 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); 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 /// @brief register variables in the scope
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -544,6 +571,17 @@ collect_statement:
YYABORT; 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* into = GetIntoVariable(parser, $3);
AstNode const* intoExpression = GetIntoExpression($3); AstNode const* intoExpression = GetIntoExpression($3);
@ -563,6 +601,22 @@ collect_statement:
YYABORT; 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 // note all group variables
std::unordered_set<Variable const*> groupVars; std::unordered_set<Variable const*> groupVars;
size_t n = $1->numMembers(); size_t n = $1->numMembers();
@ -609,6 +663,17 @@ collect_statement:
RegisterAssignVariables(scopes, $1); 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* into = GetIntoVariable(parser, $2);
AstNode const* intoExpression = GetIntoExpression($2); AstNode const* intoExpression = GetIntoExpression($2);
@ -627,6 +692,17 @@ collect_statement:
$3 != nullptr) { $3 != nullptr) {
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "use of 'KEEP' without 'INTO'", yylloc.first_line, yylloc.first_column); 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* into = GetIntoVariable(parser, $2);
AstNode const* intoExpression = GetIntoExpression($2); AstNode const* intoExpression = GetIntoExpression($2);

View File

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

View File

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

View File

@ -150,7 +150,7 @@
rerenderValues: function(data) { rerenderValues: function(data) {
// TODO cache value state like graph data //TODO cache value state like graph data
//Connections //Connections
this.renderValue('#clusterConnections', Math.round(data.clientConnectionsCurrent)); this.renderValue('#clusterConnections', Math.round(data.clientConnectionsCurrent));
@ -160,12 +160,9 @@
var totalMem = data.physicalMemory; var totalMem = data.physicalMemory;
var usedMem = data.residentSizeCurrent; var usedMem = data.residentSizeCurrent;
this.renderValue('#clusterRam', [usedMem, totalMem]); 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') { if (typeof value === 'number') {
$(id).html(value); $(id).html(value);
} }
@ -175,11 +172,60 @@
var percent = 1 / (b/a) * 100; var percent = 1 / (b/a) * 100;
$(id).html(percent.toFixed(1) + ' %'); $(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() { updateValues: function() {
this.renderValue('#clusterNodes', this.statCollectCoord.size()); var self = this;
this.renderValue('#clusterRam', [1024, 4096]);
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() { initValues: function() {
@ -446,7 +492,6 @@
var mergeHistory = function(data) { var mergeHistory = function(data) {
var onetime = ['times']; var onetime = ['times'];
var values = [ var values = [
'physicalMemory', 'physicalMemory',

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*jshint globalstrict:false, strict:false, maxlen: 500 */ /*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 /// @brief tests for COLLECT w/ INTO var = expr
@ -30,12 +30,23 @@
var jsunity = require("jsunity"); var jsunity = require("jsunity");
var db = require("@arangodb").db; var db = require("@arangodb").db;
var internal = require("internal");
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief test suite /// @brief test suite
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
function optimizerCollectExpressionTestSuite () { function optimizerCollectExpressionTestSuite () {
var assertFailingQuery = function (query) {
try {
AQL_EXECUTE(query);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_QUERY_PARSE.code, err.errorNum);
}
};
var c; var c;
return { return {
@ -202,6 +213,15 @@ function optimizerCollectExpressionTestSuite () {
for (i = 0; i < 500; ++i) { for (i = 0; i < 500; ++i) {
assertTrue(typeof results.json[1].ages[i] === 'number'); 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<VPackAttributeTranslator> Translator;
static std::unique_ptr<VPackAttributeExcludeHandler> ExcludeHandler; 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 // attribute exclude handler for skipping over system attributes
struct SystemAttributeExcludeHandler : public VPackAttributeExcludeHandler { struct SystemAttributeExcludeHandler : public VPackAttributeExcludeHandler {
bool shouldExclude(VPackSlice const& key, int nesting) override final { bool shouldExclude(VPackSlice const& key, int nesting) override final {
@ -122,73 +79,27 @@ void VelocyPackHelper::initialize() {
Translator.reset(new VPackAttributeTranslator); Translator.reset(new VPackAttributeTranslator);
// these attribute names will be translated into short integer values // these attribute names will be translated into short integer values
Translator->add("_key", 1); Translator->add("_key", 1); // TRI_VOC_ATTRIBUTE_KEY
Translator->add("_rev", 2); Translator->add("_rev", 2); // TRI_VOC_ATTRIBUTE_REV
Translator->add("_id", 3); Translator->add("_id", 3); // TRI_VOC_ATTRIBUTE_ID
Translator->add("_from", 4); Translator->add("_from", 4); // TRI_VOC_ATTRIBUTE_FROM
Translator->add("_to", 5); Translator->add("_to", 5); // TRI_VOC_ATTRIBUTE_TO
Translator->seal(); Translator->seal();
// set the attribute translator in the global options // set the attribute translator in the global options
VPackOptions::Defaults.attributeTranslator = Translator.get(); VPackOptions::Defaults.attributeTranslator = Translator.get();
VPackSlice::attributeTranslator = Translator.get(); VPackSlice::attributeTranslator = Translator.get();
// VPackOptions::Defaults.unsupportedTypeBehavior = VPackOptions::ConvertUnsupportedType;
// initialize exclude handler for system attributes // initialize exclude handler for system attributes
ExcludeHandler.reset(new SystemAttributeExcludeHandler); 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() { void VelocyPackHelper::disableAssemblerFunctions() {
arangodb::velocypack::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 /// @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) { static int TypeWeight(VPackSlice const& slice) {
switch (slice.type()) { switch (slice.type()) {
case VPackValueType::MinKey: case VPackValueType::MinKey:
return -1; return -99; // must be lowest
case VPackValueType::Illegal:
return -1;
case VPackValueType::None: case VPackValueType::None:
case VPackValueType::Null: case VPackValueType::Null:
return 0; return 0;
@ -232,14 +145,19 @@ static int TypeWeight(VPackSlice const& slice) {
case VPackValueType::Int: case VPackValueType::Int:
case VPackValueType::UInt: case VPackValueType::UInt:
case VPackValueType::SmallInt: case VPackValueType::SmallInt:
case VPackValueType::UTCDate:
case VPackValueType::BCD:
return 2; return 2;
case VPackValueType::String: case VPackValueType::String:
case VPackValueType::Binary:
case VPackValueType::Custom: case VPackValueType::Custom:
// custom type is used for id // custom type is used for _id (which is a string)
return 3; return 3;
case VPackValueType::Array: case VPackValueType::Array:
return 4; return 4;
case VPackValueType::Object: case VPackValueType::Object:
case VPackValueType::External:
// External type is used for documents
return 5; return 5;
default: default:
// All other values have equal weight // 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 /// @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()) { switch (lhs.type()) {
case VPackValueType::Illegal:
case VPackValueType::MinKey: case VPackValueType::MinKey:
return 0; // illegal is illegal case VPackValueType::MaxKey:
return 0;
case VPackValueType::None: case VPackValueType::None:
case VPackValueType::Null: case VPackValueType::Null:
return 0; // null == null; return 0; // null == null;
@ -524,15 +479,7 @@ int VelocyPackHelper::compare(VPackSlice const& lhs, VPackSlice const& rhs,
case VPackValueType::Int: case VPackValueType::Int:
case VPackValueType::UInt: case VPackValueType::UInt:
case VPackValueType::SmallInt: { case VPackValueType::SmallInt: {
double left = lhs.getNumericValue<double>(); return compareNumberValues(lhs, rhs);
double right = rhs.getNumericValue<double>();
if (left == right) {
return 0;
}
if (left < right) {
return -1;
}
return 1;
} }
case VPackValueType::Custom: case VPackValueType::Custom:
case VPackValueType::String: { case VPackValueType::String: {
@ -683,6 +630,7 @@ double VelocyPackHelper::toDouble(VPackSlice const& slice, bool& failed) {
} }
break; break;
} }
case VPackValueType::Illegal:
case VPackValueType::Object: case VPackValueType::Object:
case VPackValueType::UTCDate: case VPackValueType::UTCDate:
case VPackValueType::External: case VPackValueType::External:
@ -717,7 +665,7 @@ uint64_t VelocyPackHelper::hashByAttributes(
error = TRI_ERROR_CLUSTER_NOT_ALL_SHARDING_ATTRIBUTES_GIVEN; error = TRI_ERROR_CLUSTER_NOT_ALL_SHARDING_ATTRIBUTES_GIVEN;
} }
// Null is equal to None/not present // Null is equal to None/not present
sub = NullBuilder.slice(); sub = VPackSlice::nullSlice();
} }
hash = sub.normalizedHash(hash); hash = sub.normalizedHash(hash);
} }

View File

@ -199,6 +199,13 @@ class VelocyPackHelper {
static bool velocyPackToFile(char const*, VPackSlice const&, bool); 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 /// @brief Compares two VelocyPack slices
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -227,13 +234,41 @@ class VelocyPackHelper {
static uint64_t hashByAttributes(VPackSlice, std::vector<std::string> const&, static uint64_t hashByAttributes(VPackSlice, std::vector<std::string> const&,
bool, int&, std::string const& key = ""); bool, int&, std::string const& key = "");
static arangodb::velocypack::Slice NullValue(); static inline arangodb::velocypack::Slice NullValue() {
static arangodb::velocypack::Slice TrueValue(); return arangodb::velocypack::Slice::nullSlice();
static arangodb::velocypack::Slice FalseValue(); }
static arangodb::velocypack::Slice BooleanValue(bool);
static arangodb::velocypack::Slice EmptyArrayValue(); static inline arangodb::velocypack::Slice TrueValue() {
static arangodb::velocypack::Slice EmptyObjectValue(); return arangodb::velocypack::Slice::trueSlice();
static arangodb::velocypack::Slice IllegalValue(); }
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();
}
}; };
} }
} }