78 lines
3.5 KiB
C++
78 lines
3.5 KiB
C++
/*
|
|
* Copyright (C) 2022-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "readers/flat_mutation_reader_v2.hh"
|
|
#include "readers/flat_mutation_reader_fwd.hh"
|
|
|
|
// A mutation reader together with an upper bound on the set of positions of fragments
|
|
// that the reader will return. The upper bound does not need to be exact.
|
|
struct reader_and_upper_bound {
|
|
flat_mutation_reader_v2 reader;
|
|
position_in_partition upper_bound;
|
|
|
|
reader_and_upper_bound(flat_mutation_reader_v2 r, position_in_partition bound)
|
|
: reader(std::move(r)), upper_bound(std::move(bound)) {}
|
|
};
|
|
|
|
// A queue of mutation readers returning fragments with the same schema from the same single partition.
|
|
//
|
|
// Intuitively, the order of returned readers is such that the positions of the first fragments
|
|
// returned by the readers inside the partition (after `partition_start`) are ``mostly increasing''.
|
|
//
|
|
// More formally:
|
|
// 1. The queue contains a sequence of readers.
|
|
// Each call to `pop` consumes a batch of readers from the sequence.
|
|
// 2. Each position-in-partition `b` corresponds to a prefix of the sequence of readers in the queue.
|
|
// Let's call it `pref(b)`.
|
|
// 3. If `b1 <= b2`, then `pref(b1)` is a prefix of `pref(b2)`.
|
|
// 4. `pref(position_in_partition::after_all_clustered_rows())` is the entire sequence.
|
|
// 5. For each `b`, `pop(b)` returns only readers from `pref(b)`.
|
|
// 6. For each `b`, all readers that lie in the sequence after `pref(b)`
|
|
// satisfy the following property:
|
|
// the first fragment returned by the reader has a position greater than `b`.
|
|
// In other words, if `pop(b)` returns no readers, then we can be sure that all readers
|
|
// returned later by the queue return fragments with positions greater than `b`.
|
|
//
|
|
// Considering the above properties, a simple legal implementation of this interface would
|
|
// return all readers on the first call to `pop(after_all_clustered_rows())` and would not return
|
|
// any readers on `pop(b)` for `b < after_all_clustered_rows()`.
|
|
//
|
|
// Better implementations may use information about positions returned by the readers
|
|
// to return some readers earlier, but they must not break property 6.
|
|
// For example, the following scenario is illegal:
|
|
// 1. pop(for_key(10)) returns r1
|
|
// 2. pop(for_key(10)) returns no readers => all readers from pref(for_key(10)) have been popped
|
|
// 3. pop(for_key(20)) returns r2 => due to the previous step we know that r2 is not in pref(for_key(10))
|
|
// 4. the first fragment (excluding partition_start) returned by r2 has position for_key(10)
|
|
// => illegal, because for_key(10) is not greater than for_key(10).
|
|
// The first position returned by r2 must be after_key(10) or higher.
|
|
//
|
|
// With each reader also comes an upper bound on the set of positions of fragments that the reader will return.
|
|
class position_reader_queue {
|
|
public:
|
|
virtual ~position_reader_queue() = 0;
|
|
|
|
// `empty(b)` <=>
|
|
// we have popped all readers from `pref(b)` so `pop(b)`
|
|
// will not return any more readers.
|
|
virtual bool empty(position_in_partition_view bound) const = 0;
|
|
|
|
// Return the next batch of readers from `pref(b)`.
|
|
virtual std::vector<reader_and_upper_bound> pop(position_in_partition_view bound) = 0;
|
|
|
|
// Close all readers
|
|
virtual future<> close() noexcept = 0;
|
|
};
|
|
|
|
flat_mutation_reader_v2 make_clustering_combined_reader(schema_ptr schema,
|
|
reader_permit,
|
|
streamed_mutation::forwarding,
|
|
std::unique_ptr<position_reader_queue>);
|