storage_proxy: handler responses, use pointers to default constructed values instead of nulls
The current Seastar RPC infrastructure lacks support
for null values in tuples in handler responses.
In this commit we add the make_default_rpc_tuple function,
which solves the problem by returning pointers to
default-constructed values for smart pointer types
rather than nulls.
The problem was introduced in this commit
2d791a5ed4. The
function `encode_replica_exception_for_rpc` used
`default_tuple_maker` callback to create tuples
containing exceptions. Callers returned pointers
to default-constructed values in this callback,
e.g. `foreign_ptr(make_lw_shared<reconcilable_result>())`.
The commit changed this to just `SourceTuple{}`,
which means nullptr for pointer types.
Fixes: #14282
Closes #14352
This commit is contained in:
@@ -94,6 +94,7 @@
|
||||
#include "utils/error_injection.hh"
|
||||
#include "utils/exceptions.hh"
|
||||
#include "utils/tuple_utils.hh"
|
||||
#include "utils/rpc_utils.hh"
|
||||
#include "replica/exceptions.hh"
|
||||
#include "db/operation_type.hh"
|
||||
#include "locator/util.hh"
|
||||
@@ -134,7 +135,7 @@ static future<ResultTuple> encode_replica_exception_for_rpc(gms::feature_service
|
||||
std::exception_ptr eptr = f.get_exception();
|
||||
if (features.typed_errors_in_read_rpc) {
|
||||
if (auto ex = replica::try_encode_replica_exception(eptr); ex) {
|
||||
return make_ready_future<ResultTuple>(utils::tuple_insert<ResultTuple>(SourceTuple{}, std::move(ex)));
|
||||
return make_ready_future<ResultTuple>(utils::tuple_insert<ResultTuple>(utils::make_default_rpc_tuple<SourceTuple>(), std::move(ex)));
|
||||
}
|
||||
}
|
||||
return make_exception_future<ResultTuple>(std::move(eptr));
|
||||
|
||||
62
utils/rpc_utils.hh
Normal file
62
utils/rpc_utils.hh
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2023-present ScyllaDB
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils/tuple_utils.hh"
|
||||
#include <seastar/core/shared_ptr.hh>
|
||||
#include <seastar/core/sharded.hh>
|
||||
|
||||
namespace utils {
|
||||
namespace internal {
|
||||
class rpc_default_value {
|
||||
template <typename T>
|
||||
struct marker {};
|
||||
template <typename T>
|
||||
static auto create(marker<std::unique_ptr<T>>) {
|
||||
return std::make_unique<T>();
|
||||
}
|
||||
template <typename T>
|
||||
static auto create(marker<std::shared_ptr<T>>) {
|
||||
return std::make_shared<T>();
|
||||
}
|
||||
template <typename T>
|
||||
static auto create(marker<seastar::lw_shared_ptr<T>>) {
|
||||
return make_lw_shared<T>();
|
||||
}
|
||||
template <typename T>
|
||||
static auto create(marker<seastar::shared_ptr<T>>) {
|
||||
return make_shared<T>();
|
||||
}
|
||||
template <typename T>
|
||||
static auto create(marker<seastar::foreign_ptr<T>>) {
|
||||
return make_foreign(create<T>());
|
||||
}
|
||||
template <typename T>
|
||||
static auto create(marker<T>) {
|
||||
return T{};
|
||||
}
|
||||
public:
|
||||
template <typename T>
|
||||
static T create() {
|
||||
return create(marker<T>{});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// The Seastar RPC infrastructure does not support null values in tuples in handler responses.
|
||||
// This function generates a tuple by default constructing all of its elements, except for
|
||||
// smart pointer types. For those, it returns a pointer to the default constructed value.
|
||||
template <Tuple T>
|
||||
T make_default_rpc_tuple() {
|
||||
return std::invoke([&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return T { internal::rpc_default_value::create<std::tuple_element_t<Is, T>>()... };
|
||||
}, std::make_index_sequence<tuple_ex_size_v<T>>());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user