Skip to content

Commit 6c818f8

Browse files
committed
Merge 'sstables: generation_type tidy-up' from Michael Livshin
- Use `sstables::generation_type` in more places - Enforce conceptual separation of `sstables::generation_type` and `int64_t` - Fix `extremum_tracker` so that `sstables::generation_type` can be non-default-constructible Fixes scylladb#10796. Closes scylladb#10844 * github.com:scylladb/scylla: sstables: make generation_type an actual separate type sstables: use generation_type more soundly extremum_tracker: do not require default-constructible value types
2 parents 688fd31 + d7c90b5 commit 6c818f8

23 files changed

+180
-130
lines changed

api/storage_service.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1183,7 +1183,7 @@ void set_storage_service(http_context& ctx, routes& r, sharded<service::storage_
11831183
ss::sstable info;
11841184

11851185
info.timestamp = t;
1186-
info.generation = sstable->generation();
1186+
info.generation = sstables::generation_value(sstable->generation());
11871187
info.level = sstable->get_sstable_level();
11881188
info.size = sstable->bytes_on_disk();
11891189
info.data_size = sstable->ondisk_data_size();

replica/database.hh

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ private:
428428
std::vector<sstables::shared_sstable> _sstables_compacted_but_not_deleted;
429429
// sstables that should not be compacted (e.g. because they need to be used
430430
// to generate view updates later)
431-
std::unordered_map<uint64_t, sstables::shared_sstable> _sstables_staging;
431+
std::unordered_map<sstables::generation_type, sstables::shared_sstable> _sstables_staging;
432432
// Control background fibers waiting for sstables to be deleted
433433
seastar::gate _sstable_deletion_gate;
434434
// This semaphore ensures that an operation like snapshot won't have its selected
@@ -574,24 +574,24 @@ private:
574574
struct merge_comparator;
575575

576576
// update the sstable generation, making sure that new new sstables don't overwrite this one.
577-
void update_sstables_known_generation(unsigned generation) {
577+
void update_sstables_known_generation(sstables::generation_type generation) {
578578
if (!_sstable_generation) {
579579
_sstable_generation = 1;
580580
}
581-
_sstable_generation = std::max<uint64_t>(*_sstable_generation, generation / smp::count + 1);
581+
_sstable_generation = std::max<uint64_t>(*_sstable_generation, sstables::generation_value(generation) / smp::count + 1);
582582
}
583583

584584
sstables::generation_type calculate_generation_for_new_table() {
585585
assert(_sstable_generation);
586586
// FIXME: better way of ensuring we don't attempt to
587587
// overwrite an existing table.
588-
return (*_sstable_generation)++ * smp::count + this_shard_id();
588+
return sstables::generation_from_value((*_sstable_generation)++ * smp::count + this_shard_id());
589589
}
590590

591591
// inverse of calculate_generation_for_new_table(), used to determine which
592592
// shard a sstable should be opened at.
593-
static int64_t calculate_shard_from_sstable_generation(int64_t sstable_generation) {
594-
return sstable_generation % smp::count;
593+
static seastar::shard_id calculate_shard_from_sstable_generation(sstables::generation_type sstable_generation) {
594+
return sstables::generation_value(sstable_generation) % smp::count;
595595
}
596596
public:
597597
// This will update sstable lists on behalf of off-strategy compaction, where
@@ -668,7 +668,7 @@ public:
668668
// likely already called. We need to call this explicitly when we are sure we're ready
669669
// to issue disk operations safely.
670670
void mark_ready_for_writes() {
671-
update_sstables_known_generation(0);
671+
update_sstables_known_generation(sstables::generation_from_value(0));
672672
}
673673

674674
// Creates a mutation reader which covers all data sources for this column family.

replica/distributed_loader.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,9 @@ distributed_loader::reshard(sharded<sstables::sstable_directory>& dir, sharded<r
219219
co_await run_resharding_jobs(dir, std::move(destinations), db, ks_name, table_name, std::move(creator));
220220
}
221221

222-
future<int64_t>
222+
future<sstables::generation_type>
223223
highest_generation_seen(sharded<sstables::sstable_directory>& directory) {
224-
return directory.map_reduce0(std::mem_fn(&sstables::sstable_directory::highest_generation_seen), int64_t(0), [] (int64_t a, int64_t b) {
224+
return directory.map_reduce0(std::mem_fn(&sstables::sstable_directory::highest_generation_seen), sstables::generation_from_value(0), [] (sstables::generation_type a, sstables::generation_type b) {
225225
return std::max(a, b);
226226
});
227227
}
@@ -316,7 +316,7 @@ distributed_loader::process_upload_dir(distributed<replica::database>& db, distr
316316
process_sstable_dir(directory).get();
317317

318318
auto generation = highest_generation_seen(directory).get0();
319-
auto shard_generation_base = generation / smp::count + 1;
319+
auto shard_generation_base = sstables::generation_value(generation) / smp::count + 1;
320320

321321
// We still want to do our best to keep the generation numbers shard-friendly.
322322
// Each destination shard will manage its own generation counter.
@@ -329,14 +329,14 @@ distributed_loader::process_upload_dir(distributed<replica::database>& db, distr
329329
// we need generation calculated by instance of cf at requested shard
330330
auto gen = shard_gen[shard].fetch_add(smp::count, std::memory_order_relaxed);
331331

332-
return global_table->make_sstable(upload.native(), gen,
332+
return global_table->make_sstable(upload.native(), sstables::generation_from_value(gen),
333333
global_table->get_sstables_manager().get_highest_supported_format(),
334334
sstables::sstable::format_types::big, &error_handler_gen_for_upload_dir);
335335
}).get();
336336

337337
reshape(directory, db, sstables::reshape_mode::strict, ks, cf, [global_table, upload, &shard_gen] (shard_id shard) {
338338
auto gen = shard_gen[shard].fetch_add(smp::count, std::memory_order_relaxed);
339-
return global_table->make_sstable(upload.native(), gen,
339+
return global_table->make_sstable(upload.native(), sstables::generation_from_value(gen),
340340
global_table->get_sstables_manager().get_highest_supported_format(),
341341
sstables::sstable::format_types::big,
342342
&error_handler_gen_for_upload_dir);

sstables/generation_type.hh

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,64 @@
66
* SPDX-License-Identifier: AGPL-3.0-or-later
77
*/
88

9+
#pragma once
10+
911
#include <cstdint>
12+
#include <compare>
13+
#include <limits>
14+
#include <iostream>
15+
#include <seastar/core/sstring.hh>
1016

1117
namespace sstables {
12-
using generation_type = int64_t;
18+
19+
class generation_type {
20+
int64_t _value;
21+
public:
22+
generation_type() = delete;
23+
24+
explicit constexpr generation_type(int64_t value) noexcept: _value(value) {}
25+
constexpr int64_t value() const noexcept { return _value; }
26+
27+
constexpr bool operator==(const generation_type& other) const noexcept { return _value == other._value; }
28+
constexpr std::strong_ordering operator<=>(const generation_type& other) const noexcept { return _value <=> other._value; }
29+
};
30+
31+
constexpr generation_type generation_from_value(int64_t value) {
32+
return generation_type{value};
33+
}
34+
constexpr int64_t generation_value(generation_type generation) {
35+
return generation.value();
36+
}
37+
38+
} //namespace sstables
39+
40+
namespace seastar {
41+
template <typename string_type = sstring>
42+
string_type to_sstring(sstables::generation_type generation) {
43+
return to_sstring(sstables::generation_value(generation));
44+
}
45+
} //namespace seastar
46+
47+
namespace std {
48+
template <>
49+
struct hash<sstables::generation_type> {
50+
constexpr size_t operator()(const sstables::generation_type& generation) const noexcept {
51+
return hash<int64_t>{}(generation.value());
52+
}
53+
};
54+
55+
// for min_max_tracker
56+
template <>
57+
struct numeric_limits<sstables::generation_type> : public numeric_limits<int64_t> {
58+
static constexpr sstables::generation_type min() noexcept {
59+
return sstables::generation_type{numeric_limits<int64_t>::min()};
60+
}
61+
static constexpr sstables::generation_type max() noexcept {
62+
return sstables::generation_type{numeric_limits<int64_t>::max()};
63+
}
64+
};
65+
66+
[[maybe_unused]] static ostream& operator<<(ostream& s, const sstables::generation_type& generation) {
67+
return s << generation.value();
1368
}
69+
} //namespace std

sstables/sstable_directory.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ sstable_directory::sstable_directory(fs::path sstable_dir,
5050

5151
void
5252
sstable_directory::handle_component(scan_state& state, sstables::entry_descriptor desc, fs::path filename) {
53-
if ((desc.generation % smp::count) != this_shard_id()) {
53+
if ((generation_value(desc.generation) % smp::count) != this_shard_id()) {
5454
return;
5555
}
5656

@@ -142,7 +142,7 @@ sstable_directory::sort_sstable(sstables::shared_sstable sst) {
142142
});
143143
}
144144

145-
int64_t
145+
generation_type
146146
sstable_directory::highest_generation_seen() const {
147147
return _max_generation_seen;
148148
}
@@ -202,16 +202,16 @@ sstable_directory::process_sstable_dir(const ::io_priority_class& iop, bool sort
202202
state.descriptors.erase(desc.generation);
203203
}
204204

205-
_max_generation_seen = boost::accumulate(state.generations_found | boost::adaptors::map_keys, int64_t(0), [] (int64_t a, int64_t b) {
206-
return std::max<int64_t>(a, b);
205+
_max_generation_seen = boost::accumulate(state.generations_found | boost::adaptors::map_keys, generation_from_value(0), [] (generation_type a, generation_type b) {
206+
return std::max<generation_type>(a, b);
207207
});
208208

209209
dirlog.debug("After {} scanned, seen generation {}. {} descriptors found, {} different files found ",
210210
_sstable_dir, _max_generation_seen, state.descriptors.size(), state.generations_found.size());
211211

212212
// _descriptors is everything with a TOC. So after we remove this, what's left is
213213
// SSTables for which a TOC was not found.
214-
co_await parallel_for_each_restricted(state.descriptors, [this, sort_sstables_according_to_owner, &state, &iop] (std::tuple<int64_t, sstables::entry_descriptor>&& t) {
214+
co_await parallel_for_each_restricted(state.descriptors, [this, sort_sstables_according_to_owner, &state, &iop] (std::tuple<generation_type, sstables::entry_descriptor>&& t) {
215215
auto& desc = std::get<1>(t);
216216
state.generations_found.erase(desc.generation);
217217
// This will try to pre-load this file and throw an exception if it is invalid

sstables/sstable_directory.hh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ private:
8585
// How to create an SSTable object from an existing SSTable file (respecting generation, etc)
8686
sstable_object_from_existing_fn _sstable_object_from_existing_sstable;
8787

88-
int64_t _max_generation_seen = 0;
88+
generation_type _max_generation_seen = generation_from_value(0);
8989
sstables::sstable_version_types _max_version_seen = sstables::sstable_version_types::ka;
9090

9191
// SSTables that are unshared and belong to this shard. They are already stored as an
@@ -137,7 +137,7 @@ public:
137137
future<> move_foreign_sstables(sharded<sstable_directory>& source_directory);
138138

139139
// returns what is the highest generation seen in this directory.
140-
int64_t highest_generation_seen() const;
140+
generation_type highest_generation_seen() const;
141141

142142
// returns what is the highest version seen in this directory.
143143
sstables::sstable_version_types highest_version_seen() const;

sstables/sstable_set.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ class incremental_reader_selector : public reader_selector {
628628
lw_shared_ptr<const sstable_set> _sstables;
629629
tracing::trace_state_ptr _trace_state;
630630
std::optional<sstable_set::incremental_selector> _selector;
631-
std::unordered_set<int64_t> _read_sstable_gens;
631+
std::unordered_set<generation_type> _read_sstable_gens;
632632
sstable_reader_factory_type _fn;
633633

634634
flat_mutation_reader_v2 create_reader(shared_sstable sst) {

sstables/sstables.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2256,7 +2256,7 @@ static entry_descriptor make_entry_descriptor(sstring sstdir, sstring fname, sst
22562256
} else {
22572257
throw malformed_sstable_exception(seastar::format("invalid version for file {}. Name doesn't match any known version.", fname));
22582258
}
2259-
return entry_descriptor(sstdir, ks, cf, boost::lexical_cast<unsigned long>(generation), version, sstable::format_from_sstring(format), sstable::component_from_sstring(version, component));
2259+
return entry_descriptor(sstdir, ks, cf, generation_from_value(boost::lexical_cast<unsigned long>(generation)), version, sstable::format_from_sstring(format), sstable::component_from_sstring(version, component));
22602260
}
22612261

22622262
entry_descriptor entry_descriptor::make_descriptor(sstring sstdir, sstring fname) {

sstables/sstables.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ private:
504504
schema_ptr _schema;
505505
sstring _dir;
506506
std::optional<sstring> _temp_dir; // Valid while the sstable is being created, until sealed
507-
generation_type _generation = 0;
507+
generation_type _generation{0};
508508

509509
version_types _version;
510510
format_types _format;

test/boost/database_test.cc

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -253,25 +253,25 @@ SEASTAR_THREAD_TEST_CASE(test_distributed_loader_with_incomplete_sstables) {
253253
require_exist(file_name, true);
254254
};
255255

256-
auto temp_sst_dir = sst::temp_sst_dir(sst_dir, 2);
256+
auto temp_sst_dir = sst::temp_sst_dir(sst_dir, generation_from_value(2));
257257
touch_dir(temp_sst_dir);
258258

259-
temp_sst_dir = sst::temp_sst_dir(sst_dir, 3);
259+
temp_sst_dir = sst::temp_sst_dir(sst_dir, generation_from_value(3));
260260
touch_dir(temp_sst_dir);
261-
auto temp_file_name = sst::filename(temp_sst_dir, ks, cf, sst::version_types::mc, 3, sst::format_types::big, component_type::TemporaryTOC);
261+
auto temp_file_name = sst::filename(temp_sst_dir, ks, cf, sst::version_types::mc, generation_from_value(3), sst::format_types::big, component_type::TemporaryTOC);
262262
touch_file(temp_file_name);
263263

264-
temp_file_name = sst::filename(sst_dir, ks, cf, sst::version_types::mc, 4, sst::format_types::big, component_type::TemporaryTOC);
264+
temp_file_name = sst::filename(sst_dir, ks, cf, sst::version_types::mc, generation_from_value(4), sst::format_types::big, component_type::TemporaryTOC);
265265
touch_file(temp_file_name);
266-
temp_file_name = sst::filename(sst_dir, ks, cf, sst::version_types::mc, 4, sst::format_types::big, component_type::Data);
266+
temp_file_name = sst::filename(sst_dir, ks, cf, sst::version_types::mc, generation_from_value(4), sst::format_types::big, component_type::Data);
267267
touch_file(temp_file_name);
268268

269269
do_with_cql_env_thread([&sst_dir, &ks, &cf, &require_exist] (cql_test_env& e) {
270-
require_exist(sst::temp_sst_dir(sst_dir, 2), false);
271-
require_exist(sst::temp_sst_dir(sst_dir, 3), false);
270+
require_exist(sst::temp_sst_dir(sst_dir, generation_from_value(2)), false);
271+
require_exist(sst::temp_sst_dir(sst_dir, generation_from_value(3)), false);
272272

273-
require_exist(sst::filename(sst_dir, ks, cf, sst::version_types::mc, 4, sst::format_types::big, component_type::TemporaryTOC), false);
274-
require_exist(sst::filename(sst_dir, ks, cf, sst::version_types::mc, 4, sst::format_types::big, component_type::Data), false);
273+
require_exist(sst::filename(sst_dir, ks, cf, sst::version_types::mc, generation_from_value(4), sst::format_types::big, component_type::TemporaryTOC), false);
274+
require_exist(sst::filename(sst_dir, ks, cf, sst::version_types::mc, generation_from_value(4), sst::format_types::big, component_type::Data), false);
275275
}, db_cfg_ptr).get();
276276
}
277277

@@ -320,11 +320,11 @@ SEASTAR_THREAD_TEST_CASE(test_distributed_loader_with_pending_delete) {
320320
};
321321

322322
auto component_basename = [&ks, &cf] (int64_t gen, component_type ctype) {
323-
return sst::component_basename(ks, cf, sst::version_types::mc, gen, sst::format_types::big, ctype);
323+
return sst::component_basename(ks, cf, sst::version_types::mc, generation_from_value(gen), sst::format_types::big, ctype);
324324
};
325325

326326
auto gen_filename = [&sst_dir, &ks, &cf] (int64_t gen, component_type ctype) {
327-
return sst::filename(sst_dir, ks, cf, sst::version_types::mc, gen, sst::format_types::big, ctype);
327+
return sst::filename(sst_dir, ks, cf, sst::version_types::mc, generation_from_value(gen), sst::format_types::big, ctype);
328328
};
329329

330330
touch_dir(pending_delete_dir);

test/boost/mutation_reader_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3876,7 +3876,7 @@ static future<> do_test_clustering_order_merger_sstable_set(bool reversed) {
38763876
return sst.make_reader(query_schema, permit, pr,
38773877
query_slice, seastar::default_priority_class(), nullptr, fwd);
38783878
},
3879-
[included_gens] (const sstable& sst) { return included_gens.contains(sst.generation()); },
3879+
[included_gens] (const sstable& sst) { return included_gens.contains(generation_value(sst.generation())); },
38803880
pk, query_schema, permit, fwd, reversed);
38813881
return make_clustering_combined_reader(query_schema, permit, fwd, std::move(q));
38823882
};

test/boost/sstable_3_x_test.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3211,9 +3211,9 @@ static void compare_sstables(const std::filesystem::path& result_path, sstring t
32113211
component_type::Filter}) {
32123212
auto orig_filename =
32133213
sstable::filename(get_write_test_path(table_name),
3214-
"ks", table_name, sstables::sstable_version_types::mc, 1, big, file_type);
3214+
"ks", table_name, sstables::sstable_version_types::mc, generation_from_value(1), big, file_type);
32153215
auto result_filename =
3216-
sstable::filename(result_path.string(), "ks", table_name, version, 1, big, file_type);
3216+
sstable::filename(result_path.string(), "ks", table_name, version, generation_from_value(1), big, file_type);
32173217
compare_files(orig_filename, result_filename);
32183218
}
32193219
}
@@ -5194,7 +5194,7 @@ static void test_sstable_write_large_row_f(schema_ptr s, reader_permit permit, r
51945194
auto stop_manager = defer([&] { manager.close().get(); });
51955195
tmpdir dir;
51965196
auto sst = manager.make_sstable(
5197-
s, dir.path().string(), 1 /* generation */, version, sstables::sstable::format_types::big);
5197+
s, dir.path().string(), generation_from_value(1), version, sstables::sstable::format_types::big);
51985198

51995199
// The test provides thresholds values for the large row handler. Whether the handler gets
52005200
// trigger depends on the size of rows after they are written in the MC format and that size
@@ -5253,7 +5253,7 @@ static void test_sstable_log_too_many_rows_f(int rows, uint64_t threshold, bool
52535253
sstables_manager manager(handler, test_db_config, test_feature_service, tracker);
52545254
auto close_manager = defer([&] { manager.close().get(); });
52555255
tmpdir dir;
5256-
auto sst = manager.make_sstable(sc, dir.path().string(), 1, version, sstables::sstable::format_types::big);
5256+
auto sst = manager.make_sstable(sc, dir.path().string(), generation_from_value(1), version, sstables::sstable::format_types::big);
52575257
sst->write_components(mt->make_flat_reader(sc, semaphore.make_permit()), 1, sc, manager.configure_writer("test"), encoding_stats{}).get();
52585258

52595259
BOOST_REQUIRE_EQUAL(logged, expected);

0 commit comments

Comments
 (0)