d7a9c5bab8
Summary: This is the first step in cutting the crazy dependencies of communication module to the whole database. Includes have been reorganized and conversion between DecodedValue and other Memgraph types (TypedValue and PropertyValue) has been extracted to a higher level component called `communication/conversion`. Encoder, like Decoder, now relies only on DecodedValue. Hopefully the conversion operations will not significantly slow down streaming Bolt data. Additionally, Bolt ID is now wrapped in a class. Our storage model uses *unsigned* int64, while Bolt expects *signed* int64. The implicit conversions may lead to encode/decode errors, so the wrapper should enforce some type safety to prevent such errors. Reviewers: mferencevic, buda, msantl, mtomic Reviewed By: mferencevic, mtomic Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1453
86 lines
2.6 KiB
C++
86 lines
2.6 KiB
C++
#pragma once
|
|
|
|
#include <chrono>
|
|
#include <experimental/optional>
|
|
#include <map>
|
|
#include <random>
|
|
#include <string>
|
|
|
|
#include "communication/bolt/client.hpp"
|
|
#include "communication/bolt/v1/decoder/decoded_value.hpp"
|
|
#include "utils/algorithm.hpp"
|
|
#include "utils/exceptions.hpp"
|
|
#include "utils/thread/sync.hpp"
|
|
#include "utils/timer.hpp"
|
|
|
|
using communication::ClientContext;
|
|
using communication::bolt::Client;
|
|
using communication::bolt::DecodedValue;
|
|
using io::network::Endpoint;
|
|
|
|
void PrintJsonDecodedValue(std::ostream &os, const DecodedValue &value) {
|
|
switch (value.type()) {
|
|
case DecodedValue::Type::Null:
|
|
os << "null";
|
|
break;
|
|
case DecodedValue::Type::Bool:
|
|
os << (value.ValueBool() ? "true" : "false");
|
|
break;
|
|
case DecodedValue::Type::Int:
|
|
os << value.ValueInt();
|
|
break;
|
|
case DecodedValue::Type::Double:
|
|
os << value.ValueDouble();
|
|
break;
|
|
case DecodedValue::Type::String:
|
|
os << "\"" << value.ValueString() << "\"";
|
|
break;
|
|
case DecodedValue::Type::List:
|
|
os << "[";
|
|
utils::PrintIterable(os, value.ValueList(), ", ",
|
|
[](auto &stream, const auto &item) {
|
|
PrintJsonDecodedValue(stream, item);
|
|
});
|
|
os << "]";
|
|
break;
|
|
case DecodedValue::Type::Map:
|
|
os << "{";
|
|
utils::PrintIterable(os, value.ValueMap(), ", ",
|
|
[](auto &stream, const auto &pair) {
|
|
PrintJsonDecodedValue(stream, {pair.first});
|
|
stream << ": ";
|
|
PrintJsonDecodedValue(stream, pair.second);
|
|
});
|
|
os << "}";
|
|
break;
|
|
default:
|
|
std::terminate();
|
|
}
|
|
}
|
|
|
|
std::pair<communication::bolt::QueryData, int> ExecuteNTimesTillSuccess(
|
|
Client &client, const std::string &query,
|
|
const std::map<std::string, communication::bolt::DecodedValue> ¶ms,
|
|
int max_attempts) {
|
|
static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()};
|
|
static thread_local std::uniform_int_distribution<> rand_dist_{10, 50};
|
|
int failed_attempts{0};
|
|
while (true) {
|
|
try {
|
|
auto ret = client.Execute(query, params);
|
|
return {ret, failed_attempts};
|
|
} catch (const utils::BasicException &e) {
|
|
VLOG(0) << "Error: " << e.what();
|
|
if (++failed_attempts == max_attempts) {
|
|
LOG(WARNING) << query << " failed " << failed_attempts << "times";
|
|
throw;
|
|
}
|
|
utils::Timer t;
|
|
std::chrono::microseconds to_sleep(rand_dist_(pseudo_rand_gen_));
|
|
while (t.Elapsed() < to_sleep) {
|
|
utils::CpuRelax();
|
|
}
|
|
}
|
|
}
|
|
}
|