/* * Copyright (C) 2017-present ScyllaDB */ /* * SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0 */ #pragma once #include #include "dht/i_partitioner.hh" #include "schema/schema.hh" #include "sstables/index_reader.hh" #include "reader_concurrency_semaphore.hh" #include "test/lib/log.hh" class index_reader_assertions { std::unique_ptr _r; public: // Must be called from a seastar thread ~index_reader_assertions() { close().get(); } index_reader_assertions(std::unique_ptr r) : _r(std::move(r)) { } index_reader_assertions& has_monotonic_positions(const schema& s) { tests::reader_concurrency_semaphore_wrapper semaphore; auto pos_cmp = sstables::promoted_index_block_compare(s); auto rp_cmp = dht::ring_position_comparator(s); auto prev = dht::ring_position::min(); _r->read_partition_data().get(); while (!_r->eof()) { if (auto k = _r->get_partition_key()) { auto rp = dht::ring_position(dht::decorate_key(s, *k)); if (rp_cmp(prev, rp) >= 0) { BOOST_FAIL(format("Partitions have invalid order: {} >= {}", prev, rp)); } prev = rp; } if (auto* r = dynamic_cast(_r.get())) { sstables::clustered_index_cursor* cur = r->current_clustered_cursor(); std::optional prev_end; while (auto ei_opt = cur->next_entry().get()) { sstables::clustered_index_cursor::entry_info& ei = *ei_opt; if (prev_end && pos_cmp(ei.start, sstables::to_view(*prev_end))) { BOOST_FAIL(seastar::format("Index blocks are not monotonic: {} > {}", *prev_end, ei.start)); } prev_end = sstables::materialize(ei.end); } } else { auto& ref = *_r; testlog.warn("Skipping row index monotonicity check for index type {}, because iteration over index blocks is not supported", typeid(ref).name()); } _r->advance_to_next_partition().get(); } return *this; } index_reader_assertions& is_empty(const schema& s) { if (auto* r = dynamic_cast(_r.get())) { _r->read_partition_data().get(); while (!_r->eof()) { BOOST_REQUIRE(r->get_promoted_index_size() == 0); _r->advance_to_next_partition().get(); } } else { auto& ref = *_r; testlog.warn("Skipping row index emptiness check for index type {}, because iteration over index blocks is not supported", typeid(ref).name()); } return *this; } future<> close() noexcept { if (_r) { auto r = std::move(_r); auto f = r->close(); return f.then([r = std::move(r)] {}); } return make_ready_future<>(); } }; inline index_reader_assertions assert_that(std::unique_ptr r) { return { std::move(r) }; }