Files
scylladb/service/topology_guard.hh
Avi Kivity 0ae22a09d4 LICENSE: Update to version 1.1
Updated terms of non-commercial use (must be a never-customer).
2026-04-12 19:46:33 +03:00

74 lines
2.7 KiB
C++

/*
* Copyright (C) 2023-present ScyllaDB
*/
/*
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.1
*/
#pragma once
#include "service/session.hh"
namespace service {
/// Represents topology_guard in transit.
/// Can be passed across nodes and copied across shards.
/// Guard in transit doesn't block barriers, but can be materialized into topology_guard
/// which does. If the guard was invalidated while in transit, materialization will fail.
/// Has an null state which represents no guard.
/// topology_guard created out of null frozen_topology_guard is valid and never aborted.
using frozen_topology_guard = session_id;
/// Represents a guard which is always valid and never aborted.
constexpr frozen_topology_guard null_topology_guard = default_session_id;
session_manager& get_topology_session_manager();
/// A guard used by operations started by the topology change coordinator whose scope
/// of operation is supposed to be limited to a single transition stage.
/// The coordinator invalidates guards, typically when it advances to the next stage.
/// Invalidated guards are still alive and block barriers, but their check() will throw, which
/// gives the holder a chance to interrupt the operation and release the guard early.
/// The token metadata barrier executed by the coordinator waits for guards to die, even the
/// invalidated ones.
///
/// Guards allow coordinators to make sure there are no side-effects from operations started
/// in earlier stages of topology change operation. If all side-effects are performed under
/// the guard's scope, then executing a token metadata barrier after invalidating the guard
/// guarantees that there can be no side-effects from earlier stages.
/// The token metadata barrier must contact all nodes which may have alive guards.
template <typename T> concept TopologyGuard = requires(T guard, frozen_topology_guard frozen_guard) {
// Acquiring the guard.
{ T(frozen_guard) } -> std::same_as<T>;
// Moving the guard.
{ T(std::move(guard)) } -> std::same_as<T>;
// Checking if the guard was invalidated.
{ guard.check() } -> std::same_as<void>;
};
/// TopologyGuard implementation where the scope of the guard's validity
/// is limited to the scope of a session validity.
/// The topology change coordinator invalidates the guards by closing the session.
class session_topology_guard {
session::guard _guard;
public:
using frozen = session_id;
session_topology_guard(frozen_topology_guard g)
: _guard(get_topology_session_manager().enter_session(g))
{ }
void check() {
return _guard.check();
}
};
static_assert(TopologyGuard<session_topology_guard>);
using topology_guard = session_topology_guard;
} // namespace service