utils: add tagged_integer

A generic template for defining strongly typed
integer types.

Use it here to replace raft::internal::tagged_uint64.
Will be used for defining gms generation and version
as strong and distinguishable types in following patches.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
This commit is contained in:
Benny Halevy
2023-02-24 14:10:52 +02:00
parent c5d819ce60
commit f5f566bdd8
10 changed files with 127 additions and 70 deletions

View File

@@ -1155,6 +1155,7 @@ idls = ['idl/gossip_digest.idl.hh',
'idl/position_in_partition.idl.hh',
'idl/experimental/broadcast_tables_lang.idl.hh',
'idl/storage_service.idl.hh',
'idl/utils.idl.hh',
]
headers = find_headers('.', excluded_dirs=['idl', 'build', 'seastar', '.git'])

View File

@@ -59,7 +59,9 @@ set(idl_headers
replica_exception.idl.hh
per_partition_rate_limit_info.idl.hh
position_in_partition.idl.hh
experimental/broadcast_tables_lang.idl.hh)
experimental/broadcast_tables_lang.idl.hh
utils.idl.hh
)
foreach(idl_header ${idl_headers})
compile_idl(${idl_header}

View File

@@ -6,6 +6,10 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include "raft/raft.hh"
#include "idl/utils.idl.hh"
namespace raft {
struct snapshot_descriptor {

View File

@@ -9,6 +9,7 @@
#include "raft/raft.hh"
#include "idl/uuid.idl.hh"
#include "idl/utils.idl.hh"
namespace raft {
@@ -19,11 +20,6 @@ struct tagged_id {
utils::UUID id;
};
template<typename Tag>
struct tagged_uint64 {
uint64_t get_value();
};
} // namespace internal
struct server_address {

18
idl/utils.idl.hh Normal file
View File

@@ -0,0 +1,18 @@
/*
* Copyright 2023-present ScyllaDB
*/
/*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include "utils/tagged_integer.hh"
namespace utils {
template<typename Tag, typename ValueType>
struct tagged_integer final {
ValueType value();
};
} // namespace utils

View File

@@ -98,7 +98,7 @@ const log_entry& fsm::add_entry(T command) {
tmp.enter_joint(command.current);
command = std::move(tmp);
logger.trace("[{}] appending joint config entry at {}: {}", _my_id, _log.next_idx().get_value(), command);
logger.trace("[{}] appending joint config entry at {}: {}", _my_id, _log.next_idx(), command);
}
utils::get_local_injector().inject("fsm::add_entry/test-failure",
@@ -462,7 +462,7 @@ void fsm::maybe_commit() {
// system then transitions to the new configuration.
configuration cfg(_log.get_configuration());
cfg.leave_joint();
logger.trace("[{}] appending non-joint config entry at {}: {}", _my_id, _log.next_idx().get_value(), cfg);
logger.trace("[{}] appending non-joint config entry at {}: {}", _my_id, _log.next_idx(), cfg);
_log.emplace_back(seastar::make_lw_shared<log_entry>({_current_term, _log.next_idx(), std::move(cfg)}));
leader_state().tracker.set_configuration(_log.get_configuration(), _log.last_idx());
// Leaving joint configuration may commit more entries

View File

@@ -14,66 +14,8 @@
namespace raft {
namespace internal {
template<typename Tag>
class tagged_uint64 {
uint64_t _val;
public:
tagged_uint64() : _val(0) {}
explicit tagged_uint64(uint64_t v) : _val(v) {}
tagged_uint64(const tagged_uint64&) = default;
tagged_uint64(tagged_uint64&&) = default;
tagged_uint64& operator=(const tagged_uint64&) = default;
auto operator<=>(const tagged_uint64&) const = default;
explicit operator bool() const { return _val != 0; }
uint64_t get_value() const {
return _val;
}
operator uint64_t() const {
return get_value();
}
tagged_uint64& operator++() { // pre increment
++_val;
return *this;
}
tagged_uint64 operator++(int) { // post increment
uint64_t v = _val++;
return tagged_uint64(v);
}
tagged_uint64& operator--() { // pre decrement
--_val;
return *this;
}
tagged_uint64 operator--(int) { // post decrement
uint64_t v = _val--;
return tagged_uint64(v);
}
tagged_uint64 operator+(const tagged_uint64& o) const {
return tagged_uint64(_val + o._val);
}
tagged_uint64 operator-(const tagged_uint64& o) const {
return tagged_uint64(_val - o._val);
}
friend std::ostream& operator<<(std::ostream& os, const tagged_uint64<Tag>& u) {
os << u._val;
return os;
}
};
template<typename Tag>
using tagged_id = utils::tagged_uuid<Tag>;
} // end of namespace internal
} // end of namespace raft
namespace std {
template<typename Tag>
struct hash<raft::internal::tagged_uint64<Tag>> {
size_t operator()(const raft::internal::tagged_uint64<Tag>& val) const {
return hash<uint64_t>()(val);
}
};
} // end of namespace std

View File

@@ -19,6 +19,7 @@
#include <seastar/core/abort_source.hh>
#include "bytes_ostream.hh"
#include "utils/UUID.hh"
#include "utils/tagged_integer.hh"
#include "internal.hh"
#include "logical_clock.hh"
@@ -39,11 +40,11 @@ using server_id = internal::tagged_id<struct server_id_tag>;
using group_id = raft::internal::tagged_id<struct group_id_tag>;
// This type represents the raft term
using term_t = internal::tagged_uint64<struct term_tag>;
using term_t = utils::tagged_integer<struct term_tag, int64_t>;
// This type represensts the index into the raft log
using index_t = internal::tagged_uint64<struct index_tag>;
using index_t = utils::tagged_integer<struct index_tag, uint64_t>;
// Identifier for a read barrier request
using read_id = internal::tagged_uint64<struct read_id_tag>;
using read_id = utils::tagged_integer<struct read_id_tag, uint64_t>;
// Opaque connection properties. May contain ip:port pair for instance.
// This value is disseminated between cluster member

View File

@@ -893,7 +893,7 @@ class persistence {
if (b == _stored_entries.end() || (*b)->idx >= idx) {
return b;
}
return b + std::min((idx - (*b)->idx).get_value(), _stored_entries.size());
return b + std::min(size_t(idx - (*b)->idx), _stored_entries.size());
}
public:

93
utils/tagged_integer.hh Normal file
View File

@@ -0,0 +1,93 @@
/*
* Copyright 2020-present ScyllaDB
*/
/*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include <cstdint>
#include <compare>
#include <iostream>
#include <type_traits>
namespace utils {
template <typename Tag, std::integral ValueType>
class tagged_integer {
public:
using value_type = ValueType;
private:
value_type _value;
public:
tagged_integer() noexcept : _value(0) {}
explicit tagged_integer(value_type v) noexcept : _value(v) {}
tagged_integer& operator=(value_type v) noexcept {
_value = v;
return *this;
}
value_type value() const noexcept { return _value; }
operator value_type() const noexcept { return _value; }
explicit operator bool() const { return _value != 0; }
auto operator<=>(const tagged_integer& o) const = default;
tagged_integer& operator++() noexcept {
++_value;
return *this;
}
tagged_integer& operator--() noexcept {
--_value;
return *this;
}
tagged_integer operator++(int) noexcept {
auto ret = *this;
++_value;
return ret;
}
tagged_integer operator--(int) noexcept {
auto ret = *this;
--_value;
return ret;
}
tagged_integer operator+(const tagged_integer& o) const {
return tagged_integer(_value + o._value);
}
tagged_integer operator-(const tagged_integer& o) const {
return tagged_integer(_value - o._value);
}
tagged_integer& operator+=(const tagged_integer& o) const {
_value += o._value;
return *this;
}
tagged_integer& operator-=(const tagged_integer& o) const {
_value -= o._value;
return *this;
}
};
} // namespace utils
namespace std {
template <typename Tag, std::integral ValueType>
struct hash<utils::tagged_integer<Tag, ValueType>> {
size_t operator()(const utils::tagged_integer<Tag, ValueType>& x) const noexcept {
return hash<ValueType>{}(x.value());
}
};
template <typename Tag, std::integral ValueType>
[[maybe_unused]] ostream& operator<<(ostream& s, const utils::tagged_integer<Tag, ValueType>& x) {
return s << x.value();
}
} // namespace std