Introduces `replica::rate_limit_exception` - an exceptions that is supposed to be thrown/returned on the replica side when the request is rejected due to the exceeding the per-partition rate limit. Additionally, introduces the `exception_variant` type which allows to transport the new exception over RPC while preserving the type information. This will be useful in later commits, as the coordinator will have to know whether a replica has failed due to rate limit being exceeded or another kind of error. The `exception_variant` currently can only either hold "other exception" (std::monostate) or the aforementioned `rate_limit_exception`, but can be extended in a backwards-compatible way in the future to be able to hold more exceptions that need to be handled in a different way.
74 lines
1.7 KiB
C++
74 lines
1.7 KiB
C++
/*
|
|
* Copyright 2022-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <exception>
|
|
#include <optional>
|
|
#include <variant>
|
|
|
|
#include "seastar/core/sstring.hh"
|
|
#include "seastar/core/timed_out_error.hh"
|
|
|
|
#include "utils/exception_container.hh"
|
|
#include "utils/result.hh"
|
|
|
|
namespace replica {
|
|
|
|
// A marker indicating that the exception_variant holds an unknown exception.
|
|
// For example, replica sends a new type of error and coordinator does not
|
|
// understand it because it wasn't upgraded to a newer version yet.
|
|
struct unknown_exception {};
|
|
|
|
// A marker indicating that the exception variant doesn't hold any exception.
|
|
struct no_exception {};
|
|
|
|
class replica_exception : public std::exception {
|
|
public:
|
|
replica_exception() noexcept {};
|
|
};
|
|
|
|
class rate_limit_exception final : public replica_exception {
|
|
public:
|
|
rate_limit_exception() noexcept
|
|
: replica_exception()
|
|
{ }
|
|
|
|
virtual const char* what() const noexcept override { return "rate limit exceeded"; }
|
|
};
|
|
|
|
struct exception_variant {
|
|
std::variant<unknown_exception,
|
|
no_exception,
|
|
rate_limit_exception
|
|
> reason;
|
|
|
|
exception_variant()
|
|
: reason(no_exception{})
|
|
{ }
|
|
|
|
template<typename Ex>
|
|
exception_variant(Ex&& ex)
|
|
: reason(std::move(ex))
|
|
{ }
|
|
|
|
std::exception_ptr into_exception_ptr() noexcept;
|
|
|
|
inline operator bool() const noexcept {
|
|
return !std::holds_alternative<no_exception>(reason);
|
|
}
|
|
};
|
|
|
|
// Tries to encode the exception into an exception_variant.
|
|
// If given exception cannot be encoded into one of the replica exception types,
|
|
// returns no_exception.
|
|
exception_variant try_encode_replica_exception(std::exception_ptr eptr);
|
|
|
|
}
|