#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "IO/WriteBufferFromString.h" #include #include namespace DB { class ParallelReplicasReadingCoordinator::Impl { public: using PartitionReadRequestPtr = std::unique_ptr; using PartToMarkRanges = std::map; struct PartitionReading { PartSegments part_ranges; PartToMarkRanges mark_ranges_in_part; }; using PartitionToBlockRanges = std::map; PartitionToBlockRanges partitions; std::mutex mutex; PartitionReadResponse handleRequest(PartitionReadRequest request); }; PartitionReadResponse ParallelReplicasReadingCoordinator::Impl::handleRequest(PartitionReadRequest request) { AtomicStopwatch watch; std::lock_guard lock(mutex); auto partition_it = partitions.find(request.partition_id); SCOPE_EXIT({ LOG_TRACE(&Poco::Logger::get("ParallelReplicasReadingCoordinator"), "Time for handling request: {}ns", watch.elapsed()); }); PartToRead::PartAndProjectionNames part_and_projection { .part = request.part_name, .projection = request.projection_name }; /// We are the first who wants to process parts in partition if (partition_it == partitions.end()) { PartitionReading partition_reading; PartToRead part_to_read; part_to_read.range = request.block_range; part_to_read.name = part_and_projection; partition_reading.part_ranges.addPart(std::move(part_to_read)); /// As this query is first in partition, we will accept all ranges from it. /// We need just to update our state. auto request_ranges = HalfIntervals::initializeFromMarkRanges(request.mark_ranges); auto mark_ranges_index = HalfIntervals::initializeWithEntireSpace(); mark_ranges_index.intersect(request_ranges.negate()); partition_reading.mark_ranges_in_part.insert({part_and_projection, std::move(mark_ranges_index)}); partitions.insert({request.partition_id, std::move(partition_reading)}); return {.denied = false, .mark_ranges = std::move(request.mark_ranges)}; } auto & partition_reading = partition_it->second; PartToRead part_to_read; part_to_read.range = request.block_range; part_to_read.name = part_and_projection; auto part_intersection_res = partition_reading.part_ranges.getIntersectionResult(part_to_read); switch (part_intersection_res) { case PartSegments::IntersectionResult::REJECT: { return {.denied = true, .mark_ranges = {}}; } case PartSegments::IntersectionResult::EXACTLY_ONE_INTERSECTION: { auto marks_it = partition_reading.mark_ranges_in_part.find(part_and_projection); auto & intervals_to_do = marks_it->second; auto result = HalfIntervals::initializeFromMarkRanges(request.mark_ranges); result.intersect(intervals_to_do); /// Update intervals_to_do intervals_to_do.intersect(HalfIntervals::initializeFromMarkRanges(std::move(request.mark_ranges)).negate()); auto result_ranges = result.convertToMarkRangesFinal(); const bool denied = result_ranges.empty(); return {.denied = denied, .mark_ranges = std::move(result_ranges)}; } case PartSegments::IntersectionResult::NO_INTERSECTION: { partition_reading.part_ranges.addPart(std::move(part_to_read)); auto mark_ranges_index = HalfIntervals::initializeWithEntireSpace().intersect( HalfIntervals::initializeFromMarkRanges(request.mark_ranges).negate() ); partition_reading.mark_ranges_in_part.insert({part_and_projection, std::move(mark_ranges_index)}); return {.denied = false, .mark_ranges = std::move(request.mark_ranges)}; } } __builtin_unreachable(); } PartitionReadResponse ParallelReplicasReadingCoordinator::handleRequest(PartitionReadRequest request) { return pimpl->handleRequest(std::move(request)); } ParallelReplicasReadingCoordinator::ParallelReplicasReadingCoordinator() { pimpl = std::make_unique(); } ParallelReplicasReadingCoordinator::~ParallelReplicasReadingCoordinator() = default; }