Skip to content

Commit aa8c27b

Browse files
tchaikovdenesb
authored andcommitted
db: prevent accidental copies of result_set_row by making it move-only
result_set_row is a heavyweight object containing multiple cell types: regular columns, partition keys, and static values. To prevent expensive accidental copies, delete the copy constructor and replace it with: 1. A move constructor for efficient vector reallocation 2. An explicit copy() method when copies are actually needed This change reduces overhead in some non-hot paths by eliminating implicit deep copies. Please note, previously, in `create_view_from_mutation()`, we kept a copy of `result_set_row`, and then reused `table_rs` for holding the mutation for `scylla_tables`. Because we don't copy the `result_set_row` in this change, in order to avoid invalidating the `row` after reusing `table_rs` in the outer scope, we define a new `table_rs` shadowing the one in the out scope. Signed-off-by: Kefu Chai <[email protected]> Closes scylladb#22741
1 parent 57a06a4 commit aa8c27b

File tree

4 files changed

+13
-7
lines changed

4 files changed

+13
-7
lines changed

db/schema_applier.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ static std::optional<table_id> table_id_from_mutations(const schema_mutations& s
121121
if (table_rs.empty()) {
122122
return std::nullopt;
123123
}
124-
query::result_set_row table_row = table_rs.row(0);
124+
const query::result_set_row& table_row = table_rs.row(0);
125125
return table_id(table_row.get_nonnull<utils::UUID>("id"));
126126
}
127127

db/schema_tables.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,7 +1298,7 @@ future<lw_shared_ptr<keyspace_metadata>> create_keyspace_from_schema_partition(d
12981298
// Scylla-specific row will only be present if SCYLLA_KEYSPACES schema feature is available in the cluster
12991299
if (scylla_specific_rs) {
13001300
if (!scylla_specific_rs->empty()) {
1301-
auto row = scylla_specific_rs->row(0);
1301+
const auto& row = scylla_specific_rs->row(0);
13021302
auto storage_type = row.get<sstring>("storage_type");
13031303
auto options = row.get<map_type_impl::native_type>("storage_options");
13041304
if (storage_type && options) {
@@ -2188,7 +2188,7 @@ schema_ptr create_table_from_mutations(const schema_ctxt& ctxt, schema_mutations
21882188
slogger.trace("create_table_from_mutations: version={}, {}", version, sm);
21892189

21902190
auto table_rs = query::result_set(sm.columnfamilies_mutation());
2191-
query::result_set_row table_row = table_rs.row(0);
2191+
const query::result_set_row& table_row = table_rs.row(0);
21922192

21932193
auto ks_name = table_row.get_nonnull<sstring>("keyspace_name");
21942194
auto cf_name = table_row.get_nonnull<sstring>("table_name");
@@ -2459,7 +2459,7 @@ static index_metadata create_index_from_index_row(const query::result_set_row& r
24592459

24602460
view_ptr create_view_from_mutations(const schema_ctxt& ctxt, schema_mutations sm, std::optional<table_schema_version> version) {
24612461
auto table_rs = query::result_set(sm.columnfamilies_mutation());
2462-
query::result_set_row row = table_rs.row(0);
2462+
const query::result_set_row& row = table_rs.row(0);
24632463

24642464
auto ks_name = row.get_nonnull<sstring>("keyspace_name");
24652465
auto cf_name = row.get_nonnull<sstring>("view_name");
@@ -2469,7 +2469,7 @@ view_ptr create_view_from_mutations(const schema_ctxt& ctxt, schema_mutations sm
24692469
prepare_builder_from_table_row(ctxt, builder, row);
24702470

24712471
if (sm.scylla_tables()) {
2472-
table_rs = query::result_set(*sm.scylla_tables());
2472+
auto table_rs = query::result_set(*sm.scylla_tables());
24732473
if (!table_rs.empty()) {
24742474
prepare_builder_from_scylla_tables_row(ctxt, builder, table_rs.row(0));
24752475
}

query-result-set.hh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ public:
5252
: _schema{schema}
5353
, _cells{std::move(cells)}
5454
{ }
55+
result_set_row(result_set_row&&) = default;
56+
result_set_row(const result_set_row&) = delete;
57+
result_set_row& operator=(const result_set_row&) = delete;
58+
result_set_row copy() const {
59+
return {_schema, std::unordered_map{_cells}};
60+
}
5561
// Look up a deserialized row cell value by column name
5662
const data_value*
5763
get_data_value(const sstring& column_name) const {

test/boost/multishard_mutation_query_test.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ class data_result_builder {
484484
return false;
485485
}
486486
for (const auto& row : res.rows()) {
487-
_rows.push_back(row);
487+
_rows.emplace_back(row.copy());
488488
_last_ckey = extract_ckey(row);
489489
auto last_pkey = extract_pkey(row);
490490
if (_last_pkey && last_pkey.equal(*_s, *_last_pkey)) {
@@ -799,7 +799,7 @@ SEASTAR_THREAD_TEST_CASE(test_read_reversed) {
799799
std::vector<query::result_set_row> expected_rows;
800800
for (const auto& mut : expected_results) {
801801
auto rs = query::result_set(mut);
802-
std::copy(rs.rows().begin(), rs.rows().end(), std::back_inserter(expected_rows));
802+
std::ranges::copy(rs.rows() | std::views::transform([](const auto& row) { return row.copy(); }), std::back_inserter(expected_rows));
803803
}
804804
auto expected_data_results = query::result_set(s, std::move(expected_rows));
805805

0 commit comments

Comments
 (0)