mirror of https://github.com/sysown/proxysql
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
255 lines
6.2 KiB
255 lines
6.2 KiB
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
#include <sstream>
|
|
|
|
#include "proxysql_gtid.h"
|
|
|
|
// Initializes a trxid interval from a range.
|
|
TrxId_Interval::TrxId_Interval(const trxid_t _start, const trxid_t _end) {
|
|
start = _start;
|
|
end = _end;
|
|
|
|
if (start > end) {
|
|
std::swap(start, end);
|
|
}
|
|
}
|
|
|
|
TrxId_Interval::TrxId_Interval(const trxid_t trxid) : TrxId_Interval(trxid, trxid) {
|
|
}
|
|
|
|
// Initializes a trxid interval from a C string buffer, in [trxid]{-[trxid]} format.
|
|
TrxId_Interval::TrxId_Interval(const char *s) {
|
|
start = 0;
|
|
end = 0;
|
|
|
|
if (s == nullptr) {
|
|
return;
|
|
}
|
|
|
|
trxid_t _start = 0, _end = 0;
|
|
|
|
if (sscanf(s, "%ld-%ld", &_start, &_end) == 2) {
|
|
start = _start;
|
|
end = _end;
|
|
} else if (sscanf(s, "%ld", &_start) == 1) {
|
|
start = _start;
|
|
end = _start;
|
|
}
|
|
|
|
if (start > end) {
|
|
std::swap(start, end);
|
|
}
|
|
}
|
|
|
|
// Initializes a trxid interval from a string, in [trxid]{-[trxid]} format.
|
|
TrxId_Interval::TrxId_Interval(const std::string& s) : TrxId_Interval(s.c_str()) {
|
|
}
|
|
|
|
// Checks if another trxid interval is contained in this one,
|
|
const bool TrxId_Interval::contains(const TrxId_Interval& other) {
|
|
return (other.start >= start && other.end <= end);
|
|
}
|
|
|
|
// Checks if a given trxid is contained in this interval.
|
|
const bool TrxId_Interval::contains(trxid_t trxid) {
|
|
return (trxid >= start && trxid <= end);
|
|
}
|
|
|
|
// Yields a string representation for a trxid interval.
|
|
const std::string TrxId_Interval::to_string(void) {
|
|
if (start == end) {
|
|
return std::to_string(start);
|
|
}
|
|
return std::to_string(start) + "-" + std::to_string(end);
|
|
}
|
|
|
|
// Attempts to append a new interval to this interval's end. Returns true if the append succeded, false otherwise.
|
|
const bool TrxId_Interval::append(const TrxId_Interval& other) {
|
|
if (other.start >= start && other.end >= end && other.start <= (end+1)) {
|
|
// other overlaps interval at end
|
|
end = other.end;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Attempts to merge two trxid intervals. Returns true if the intervals were merged (and potentially modified), false otherwise.
|
|
const bool TrxId_Interval::merge(const TrxId_Interval& other) {
|
|
if (other.start >= start && other.end <= end) {
|
|
// other is contained by interval
|
|
return true;
|
|
}
|
|
if (other.start <= start && other.end >= end) {
|
|
// other contains whole of existing interval
|
|
start = other.start;
|
|
end = other.end;
|
|
return true;
|
|
}
|
|
if (other.start <= start && other.end >= (start-1)) {
|
|
// other overlaps interval at start
|
|
start = other.start;
|
|
return true;
|
|
}
|
|
if (other.end >= end && other.start <= (end+1)) {
|
|
// other overlaps interval at end
|
|
end = other.end;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Compares two trxid intervals, by strict weak ordering.
|
|
const int TrxId_Interval::cmp(const TrxId_Interval& other) {
|
|
if (start < other.start) {
|
|
return -1;
|
|
}
|
|
if (start > other.start) {
|
|
return 1;
|
|
}
|
|
if (end < other.end) {
|
|
return -1;
|
|
}
|
|
if (end > other.end) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const bool TrxId_Interval::operator<(const TrxId_Interval& other) {
|
|
return cmp(other) == -1;
|
|
}
|
|
|
|
const bool TrxId_Interval::operator==(const TrxId_Interval& other) {
|
|
return cmp(other) == 0;
|
|
}
|
|
|
|
const bool TrxId_Interval::operator!=(const TrxId_Interval& other) {
|
|
return cmp(other) != 0;
|
|
}
|
|
|
|
// Initializes a GTID set.
|
|
GTID_Set::GTID_Set() {}
|
|
|
|
// Creates a copy of this GTID set.
|
|
GTID_Set GTID_Set::copy() {
|
|
GTID_Set cp;
|
|
cp.map = map;
|
|
return cp;
|
|
}
|
|
|
|
// Clears all GTID set entries.
|
|
void GTID_Set::clear() {
|
|
map.clear();
|
|
}
|
|
|
|
// Adds a new trxid interval for a given UUID. Returns true if the set was modified, false otherwise.
|
|
bool GTID_Set::add(const std::string& uuid, const TrxId_Interval& iv) {
|
|
auto it = map.find(uuid);
|
|
if (it == map.end()) {
|
|
// new UUID entry
|
|
map[uuid].emplace_back(iv);
|
|
return true;
|
|
}
|
|
|
|
if (!it->second.empty()) {
|
|
auto& last = it->second.back();
|
|
if (last.contains(iv)) {
|
|
return false;
|
|
}
|
|
if (last.append(iv)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// insert/merge trxid interval...
|
|
auto pos = it->second.begin();
|
|
for (; pos != it->second.end(); ++pos) {
|
|
if (pos->contains(iv)) {
|
|
// trxid interval is already present, nothing to do
|
|
return false;
|
|
}
|
|
if (pos->merge(iv))
|
|
break;
|
|
}
|
|
if (pos == it->second.end()) {
|
|
it->second.emplace_back(iv);
|
|
}
|
|
|
|
// ...and merge overlapping trxid ranges, if any
|
|
it->second.sort();
|
|
auto a = it->second.begin();
|
|
while (a != it->second.end()) {
|
|
auto b = std::next(a);
|
|
if (b == it->second.end()) {
|
|
break;
|
|
}
|
|
if (a->merge(*b)) {
|
|
it->second.erase(b);
|
|
continue;
|
|
}
|
|
a++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Adds a single trxid for a given UUID. Returns true if the set was modified, false otherwise.
|
|
bool GTID_Set::add(const std::string& uuid, const trxid_t& trxid) {
|
|
return add(uuid, TrxId_Interval(trxid));
|
|
}
|
|
|
|
// Adds a new trxid range for a given UUID. Returns true if the set was modified, false otherwise.
|
|
bool GTID_Set::add(const std::string& uuid, const trxid_t& start, const trxid_t& end) {
|
|
return add(uuid, TrxId_Interval(start, end));
|
|
}
|
|
|
|
// Adds a new trxid range for a given UUID, as a C string buffer. Returns true if the set was modified, false otherwise.
|
|
bool GTID_Set::add(const std::string& uuid, const char *s) {
|
|
return add(uuid, TrxId_Interval(s));
|
|
}
|
|
|
|
// Adds a new trxid range for a given UUID, as a string. Returns true if the set was modified, false otherwise.
|
|
bool GTID_Set::add(const std::string& uuid, const std::string& s) {
|
|
return add(uuid, TrxId_Interval(s));
|
|
}
|
|
|
|
// Evaluates whether a trxid is present in any of the intervals for a given UUID.
|
|
const bool GTID_Set::has_gtid(const std::string& uuid, const trxid_t trxid) {
|
|
auto it = map.find(uuid);
|
|
if (it == map.end()) {
|
|
return false;
|
|
}
|
|
for (auto itr = it->second.begin(); itr != it->second.end(); ++itr) {
|
|
if (itr->contains(trxid)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Yields a string representation for a GTID set.
|
|
const std::string GTID_Set::to_string(void) {
|
|
std::stringstream out;
|
|
bool first_uuid = true;
|
|
for (auto it=map.begin(); it!=map.end(); ++it) {
|
|
if (!first_uuid) {
|
|
out << ",";
|
|
}
|
|
std::string uuid = it->first;
|
|
uuid.insert(8,"-");
|
|
uuid.insert(13,"-");
|
|
uuid.insert(18,"-");
|
|
uuid.insert(23,"-");
|
|
out << uuid;
|
|
for (auto itr = it->second.begin(); itr != it->second.end(); ++itr) {
|
|
out << ":" << itr->to_string();
|
|
}
|
|
first_uuid = false;
|
|
}
|
|
|
|
return out.str();
|
|
} |