group0_state_machine: use correct comparison for timeuuids in merger

In d2a4079bbe, `merger` was modified so
that when we merge a command, `last_group0_state_id` is taken to be the
maximum of the merged command's state_id and the current
`last_group0_state_id`. This is necessary for achieving the same
behavior as if the commands were applied individually instead of being
merged -- where we take the maximum state ID from `group0_history` table
which was applied until now (because the table is sorted using the state
IDs and we take the greatest row).

However, a subtle bug was introduced -- the `std::max` function uses the
`utils::UUID` standard comparison operator which is unfortunately not
the same as timeuuid comparison that Scylla performs when sorting the
`group0_history` table. So in rare cases it could return the *smaller*
of the two timeuuids w.r.t. the correct timeuuid ordering. This would
then lead to commands being applied which should have been turned to
no-ops due to the `prev_state_id` check -- and then, for example,
permanent schema desync or worse.

Fix it by using the correct comparison method.

Fixes: #14600
This commit is contained in:
Kamil Braun
2023-07-10 22:55:08 +02:00
parent 5ce802676f
commit 5779230d28

View File

@@ -121,7 +121,12 @@ future<> group0_state_machine::apply(std::vector<raft::command_cref> command) {
void add(group0_command&& cmd, size_t added_size) {
slogger.trace("add to merging set new_state_id: {}", cmd.new_state_id);
auto m = convert_history_mutation(std::move(cmd.history_append), sm._sp.data_dictionary());
last_group0_state_id = std::max(last_group0_state_id, cmd.new_state_id);
// Set `last_group0_state_id` to the maximum of the current value and `cmd.new_state_id`,
// but make sure we compare them the same way timeuuids are compared in clustering keys
// (i.e. in the same order that the history table is sorted).
if (utils::timeuuid_tri_compare(last_group0_state_id, cmd.new_state_id) < 0) {
last_group0_state_id = cmd.new_state_id;
}
cmd_to_merge.push_back(std::move(cmd));
size += added_size;
if (merged_history_mutation) {