mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of ssh://github.com/ArangoDB/ArangoDB into devel
This commit is contained in:
commit
16769c59b4
|
@ -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);
|
||||
|
|
|
@ -62,6 +62,7 @@ struct CustomTypeHandler {
|
|||
struct Options {
|
||||
enum UnsupportedTypeBehavior {
|
||||
NullifyUnsupportedType,
|
||||
ConvertUnsupportedType,
|
||||
FailOnUnsupportedType
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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&,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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>');
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
|
||||
continueRender: function() {
|
||||
var coords = this.coordinators.toJSON();
|
||||
console.log(coords);
|
||||
this.$el.html(this.template.render({
|
||||
coords: coords
|
||||
}));
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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]");
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue