mirror of
https://github.com/scylladb/scylladb.git
synced 2026-05-22 15:52:13 +00:00
With the new `min_alive_uuid` saved in the group0 table, we need to make sure that all new tasks are created with time uuid greater than the value saved in `min_alive_uuid`. This patch introduces the `task_uuid_generator` which ensures that when we are generating multiple tasks in one group0 command, each task will have an unique time uuid and each time uuid will be greater than `min_alive_uuid`.
155 lines
6.3 KiB
C++
155 lines
6.3 KiB
C++
/*
|
|
* Copyright (C) 2025-present ScyllaDB
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.1
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <ranges>
|
|
#include <seastar/core/condition-variable.hh>
|
|
#include "db/view/view_build_status.hh"
|
|
#include "locator/host_id.hh"
|
|
#include "locator/tablets.hh"
|
|
#include "mutation/timestamp.hh"
|
|
#include "utils/UUID.hh"
|
|
#include <fmt/base.h>
|
|
#include "schema/schema_fwd.hh"
|
|
|
|
namespace db {
|
|
|
|
namespace view {
|
|
|
|
// Holds information about view building task for a tablet_replica.
|
|
//
|
|
// There are two types of tasks - `build_range` and `process_staging`, chosen by the `type` member.
|
|
// The meaning of these two task types are:
|
|
// build_range -> Build a token_range owned by tablet_id, from base_id to view_id.
|
|
// Multiple `build_range` tasks are executed together
|
|
// if their `base_id` and `tid` are the same.
|
|
// process_staging -> Register all staging sstables owned by the tablet_replica
|
|
// to the view_update_generator and wait until all of the staging sstables
|
|
// are processed (view updates are generated and
|
|
// the sstables are moved to normal directory).
|
|
struct view_building_task {
|
|
enum class task_type {
|
|
build_range,
|
|
process_staging,
|
|
};
|
|
|
|
|
|
utils::UUID id;
|
|
task_type type;
|
|
bool aborted;
|
|
|
|
table_id base_id;
|
|
std::optional<table_id> view_id; // nullopt when task_type is `process_staging`
|
|
locator::tablet_replica replica;
|
|
dht::token last_token;
|
|
|
|
view_building_task(utils::UUID id, task_type type, bool aborted,
|
|
table_id base_id, std::optional<table_id> view_id,
|
|
locator::tablet_replica replica, dht::token last_token);
|
|
};
|
|
|
|
using task_map = std::map<utils::UUID, view_building_task>;
|
|
|
|
struct replica_tasks {
|
|
std::map<table_id, task_map> view_tasks; // owned by a particular view
|
|
task_map staging_tasks; // owned by whole base table
|
|
};
|
|
|
|
using base_table_tasks = std::map<locator::tablet_replica, replica_tasks>;
|
|
using building_tasks = std::map<table_id, base_table_tasks>;
|
|
|
|
// Generates unique timeuuids with strictly increasing microsecond timestamps.
|
|
// Each call to operator() returns a new timeuuid whose timestamp is one
|
|
// microsecond greater than the previous one.
|
|
class task_uuid_generator {
|
|
api::timestamp_type _next_ts;
|
|
public:
|
|
explicit task_uuid_generator(api::timestamp_type base_ts);
|
|
utils::UUID operator()();
|
|
};
|
|
|
|
// Represents cluster-wide view building state (only for tablet-based views).
|
|
// The state stores all unfinished view building tasks for all tablet-based views
|
|
// and table_id of currently processed base table by view building coordinator.
|
|
//
|
|
// The state is stored in group0 tables and the in-memory structure is reloaded
|
|
// when mutations are applied to relevant tables.
|
|
struct view_building_state {
|
|
building_tasks tasks_state;
|
|
std::optional<table_id> currently_processed_base_table;
|
|
std::optional<utils::UUID> min_alive_uuid;
|
|
|
|
view_building_state(building_tasks tasks_state, std::optional<table_id> processed_base_table, std::optional<utils::UUID> min_alive_uuid);
|
|
view_building_state() = default;
|
|
|
|
std::optional<std::reference_wrapper<const view_building_task>> get_task(table_id base_id, locator::tablet_replica replica, utils::UUID id) const;
|
|
std::vector<std::reference_wrapper<const view_building_task>> get_tasks_for_host(table_id base_id, locator::host_id host) const;
|
|
std::map<dht::token, std::vector<view_building_task>> collect_tasks_by_last_token(table_id base_table_id) const;
|
|
std::map<dht::token, std::vector<view_building_task>> collect_tasks_by_last_token(table_id base_table_id, const locator::tablet_replica& replica) const;
|
|
|
|
// Creates a generator that produces unique timeuuids suitable for view
|
|
// building task IDs. The generated uuids have strictly increasing
|
|
// microsecond timestamps starting from write_timestamp. If min_alive_uuid
|
|
// is set, all generated uuids are guaranteed to be greater than
|
|
// *min_alive_uuid in timeuuid order.
|
|
task_uuid_generator make_task_uuid_generator(api::timestamp_type write_timestamp) const;
|
|
};
|
|
|
|
// Represents global state of tablet-based views.
|
|
// Contains information about existing views and their build statuses.
|
|
struct views_state {
|
|
using view_build_status_map = std::map<table_id, std::map<locator::host_id, db::view::build_status>>;
|
|
|
|
std::map<table_id, std::vector<table_id>> views_per_base;
|
|
view_build_status_map status_map;
|
|
|
|
views_state(std::map<table_id, std::vector<table_id>> views_per_base, view_build_status_map status_map);
|
|
views_state() = default;
|
|
};
|
|
|
|
struct view_building_state_machine {
|
|
view_building_state building_state;
|
|
views_state views_state;
|
|
condition_variable event;
|
|
};
|
|
|
|
view_building_task::task_type task_type_from_string(std::string_view str);
|
|
seastar::sstring task_type_to_sstring(view_building_task::task_type type);
|
|
|
|
} // namespace view_building
|
|
|
|
} // namespace service
|
|
|
|
template <> struct fmt::formatter<db::view::view_building_task::task_type> : fmt::formatter<string_view> {
|
|
auto format(db::view::view_building_task::task_type type, fmt::format_context& ctx) const {
|
|
return fmt::format_to(ctx.out(), "{}", db::view::task_type_to_sstring(type));
|
|
}
|
|
};
|
|
|
|
template <> struct fmt::formatter<db::view::view_building_task> : fmt::formatter<string_view> {
|
|
auto format(db::view::view_building_task task, fmt::format_context& ctx) const {
|
|
auto view_id = task.view_id ? fmt::to_string(*task.view_id) : "nullopt";
|
|
return fmt::format_to(ctx.out(), "view_building_task{{type: {}, aborted: {}, base_id: {}, view_id: {}, last_token: {}}}",
|
|
task.type, task.aborted, task.base_id, view_id, task.last_token);
|
|
}
|
|
};
|
|
|
|
template <> struct fmt::formatter<db::view::task_map> : fmt::formatter<string_view> {
|
|
auto format(db::view::task_map task_map, fmt::format_context& ctx) const {
|
|
return fmt::format_to(ctx.out(), "{}", task_map | std::views::keys);
|
|
}
|
|
};
|
|
|
|
template <> struct fmt::formatter<db::view::replica_tasks> : fmt::formatter<string_view> {
|
|
auto format(db::view::replica_tasks replica_tasks, fmt::format_context& ctx) const {
|
|
return fmt::format_to(ctx.out(), "{{view_tasks: {}, staging_tasks: {}}}", replica_tasks.view_tasks, replica_tasks.staging_tasks);
|
|
}
|
|
};
|