Clang-format mako-cpp

This commit is contained in:
Junhyun Shim 2022-03-03 13:33:58 +01:00
parent 0c6578a1e5
commit 2247a35361
4 changed files with 2712 additions and 2828 deletions

View File

@ -28,178 +28,168 @@ using KeyRef = BytesRef;
using ValueRef = BytesRef;
inline uint8_t const* to_byte_ptr(char const* ptr) noexcept {
return reinterpret_cast<uint8_t const*>(ptr);
return reinterpret_cast<uint8_t const*>(ptr);
}
// get bytestring view from charstring: e.g. std::basic_string{_view}<char>
template <template <class...> class StringLike, class Char>
BytesRef to_bytes_ref(const StringLike<Char>& s) noexcept {
static_assert(sizeof(Char) == 1);
return BytesRef(reinterpret_cast<uint8_t const*>(s.data()),
s.size());
static_assert(sizeof(Char) == 1);
return BytesRef(reinterpret_cast<uint8_t const*>(s.data()), s.size());
}
// get charstring view from bytestring: e.g. std::basic_string{_view}<uint8_t>
template <template <class...> class StringLike, class Char>
CharsRef to_chars_ref(const StringLike<Char>& s) noexcept {
static_assert(sizeof(Char) == 1);
return CharsRef(reinterpret_cast<char const*>(s.data()),
s.size());
static_assert(sizeof(Char) == 1);
return CharsRef(reinterpret_cast<char const*>(s.data()), s.size());
}
[[maybe_unused]] constexpr const bool overflow_check = false;
inline int intsize(BytesRef b) {
if constexpr (overflow_check) {
if (b.size() > static_cast<size_t>(std::numeric_limits<int>::max()))
throw std::overflow_error("byte strlen goes beyond int bounds");
}
return static_cast<int>(b.size());
if constexpr (overflow_check) {
if (b.size() > static_cast<size_t>(std::numeric_limits<int>::max()))
throw std::overflow_error("byte strlen goes beyond int bounds");
}
return static_cast<int>(b.size());
}
class Error {
public:
using code_type = native::fdb_error_t;
using code_type = native::fdb_error_t;
Error() noexcept : err(0) {}
Error() noexcept : err(0) {}
explicit Error(code_type err) noexcept : err(err) {}
explicit Error(code_type err) noexcept : err(err) {}
char const* what() noexcept { return native::fdb_get_error(err); }
char const* what() noexcept { return native::fdb_get_error(err); }
explicit operator bool() const noexcept { return err != 0; }
explicit operator bool() const noexcept { return err != 0; }
bool is(code_type other) const noexcept { return err != other; }
bool is(code_type other) const noexcept { return err != other; }
code_type code() const noexcept { return err; }
code_type code() const noexcept { return err; }
bool retryable() const noexcept { return native::fdb_error_predicate(FDB_ERROR_PREDICATE_RETRYABLE, err) != 0; }
bool retryable() const noexcept {
return native::fdb_error_predicate(FDB_ERROR_PREDICATE_RETRYABLE, err) != 0;
}
private:
code_type err;
code_type err;
};
/* Traits of value types held by ready futures.
Holds type and value extraction function. */
namespace future_var {
struct None {
struct type {};
static Error extract(native::FDBFuture*, type&) noexcept {
return Error(0);
}
};
struct Int64 {
using type = int64_t;
static Error extract(native::FDBFuture* f, type& out) noexcept {
return Error(native::fdb_future_get_int64(f, &out));
}
};
struct Key {
using type = std::pair<uint8_t const*, int>;
static Error extract(native::FDBFuture* f, type& out) noexcept {
auto& [out_key, out_key_length] = out;
return Error(native::fdb_future_get_key(f, &out_key, &out_key_length));
}
};
struct Value {
using type = std::tuple<bool, uint8_t const*, int>;
static Error extract(native::FDBFuture* f, type& out) noexcept {
auto& [out_present, out_value, out_value_length] = out;
auto out_present_native = native::fdb_bool_t{};
auto err = native::fdb_future_get_value(f, &out_present_native,
&out_value, &out_value_length);
out_present = (out_present_native != 0);
return Error(err);
}
};
struct StringArray {
using type = std::pair<const char**, int>;
static Error extract(native::FDBFuture* f, type& out) noexcept {
auto& [out_strings, out_count] = out;
return Error(native::fdb_future_get_string_array(f, &out_strings, &out_count));
}
};
struct KeyValueArray {
using type = std::tuple<native::FDBKeyValue const *, int, bool>;
static Error extract(native::FDBFuture* f, type& out) noexcept {
auto& [out_kv, out_count, out_more] = out;
auto out_more_native = native::fdb_bool_t{};
auto err = native::fdb_future_get_keyvalue_array(f, &out_kv, &out_count, &out_more_native);
out_more = (out_more_native != 0);
return Error(err);
}
};
struct None {
struct type {};
static Error extract(native::FDBFuture*, type&) noexcept { return Error(0); }
};
struct Int64 {
using type = int64_t;
static Error extract(native::FDBFuture* f, type& out) noexcept {
return Error(native::fdb_future_get_int64(f, &out));
}
};
struct Key {
using type = std::pair<uint8_t const*, int>;
static Error extract(native::FDBFuture* f, type& out) noexcept {
auto& [out_key, out_key_length] = out;
return Error(native::fdb_future_get_key(f, &out_key, &out_key_length));
}
};
struct Value {
using type = std::tuple<bool, uint8_t const*, int>;
static Error extract(native::FDBFuture* f, type& out) noexcept {
auto& [out_present, out_value, out_value_length] = out;
auto out_present_native = native::fdb_bool_t{};
auto err = native::fdb_future_get_value(f, &out_present_native, &out_value, &out_value_length);
out_present = (out_present_native != 0);
return Error(err);
}
};
struct StringArray {
using type = std::pair<const char**, int>;
static Error extract(native::FDBFuture* f, type& out) noexcept {
auto& [out_strings, out_count] = out;
return Error(native::fdb_future_get_string_array(f, &out_strings, &out_count));
}
};
struct KeyValueArray {
using type = std::tuple<native::FDBKeyValue const*, int, bool>;
static Error extract(native::FDBFuture* f, type& out) noexcept {
auto& [out_kv, out_count, out_more] = out;
auto out_more_native = native::fdb_bool_t{};
auto err = native::fdb_future_get_keyvalue_array(f, &out_kv, &out_count, &out_more_native);
out_more = (out_more_native != 0);
return Error(err);
}
};
} // namespace future_var
[[noreturn]] inline void throw_error(std::string_view preamble, Error err) {
auto msg = std::string(preamble);
msg.append(err.what());
throw std::runtime_error(msg);
auto msg = std::string(preamble);
msg.append(err.what());
throw std::runtime_error(msg);
}
inline int max_api_version() {
return native::fdb_get_max_api_version();
return native::fdb_get_max_api_version();
}
inline Error select_api_version_nothrow(int version) {
return Error(native::fdb_select_api_version(version));
return Error(native::fdb_select_api_version(version));
}
inline void select_api_version(int version) {
if (auto err = select_api_version_nothrow(version)) {
throw_error(fmt::format("ERROR: fdb_select_api_version({}): ", version), err);
}
if (auto err = select_api_version_nothrow(version)) {
throw_error(fmt::format("ERROR: fdb_select_api_version({}): ", version), err);
}
}
namespace network {
inline Error set_option_nothrow(FDBNetworkOption option, BytesRef str) noexcept {
return Error(native::fdb_network_set_option(option, str.data(), intsize(str)));
}
inline Error set_option_nothrow(FDBNetworkOption option, BytesRef str) noexcept {
return Error(native::fdb_network_set_option(option, str.data(), intsize(str)));
}
inline Error set_option_nothrow(FDBNetworkOption option, int64_t value) noexcept {
return Error(native::fdb_network_set_option(
option,
reinterpret_cast<const uint8_t*>(&value),
static_cast<int>(sizeof(value))));
}
inline Error set_option_nothrow(FDBNetworkOption option, int64_t value) noexcept {
return Error(native::fdb_network_set_option(
option, reinterpret_cast<const uint8_t*>(&value), static_cast<int>(sizeof(value))));
}
inline void set_option(FDBNetworkOption option, BytesRef str) {
if (auto err = set_option_nothrow(option, str)) {
throw_error(
fmt::format("ERROR: fdb_network_set_option({}): ",
static_cast<std::underlying_type_t<FDBNetworkOption>>(option)),
err);
}
}
inline void set_option(FDBNetworkOption option, BytesRef str) {
if (auto err = set_option_nothrow(option, str)) {
throw_error(fmt::format("ERROR: fdb_network_set_option({}): ",
static_cast<std::underlying_type_t<FDBNetworkOption>>(option)),
err);
}
}
inline void set_option(FDBNetworkOption option, int64_t value) {
if (auto err = set_option_nothrow(option, value)) {
throw_error(
fmt::format("ERROR: fdb_network_set_option({}, {}): ",
static_cast<std::underlying_type_t<FDBNetworkOption>>(option),
value),
err);
}
}
inline void set_option(FDBNetworkOption option, int64_t value) {
if (auto err = set_option_nothrow(option, value)) {
throw_error(fmt::format("ERROR: fdb_network_set_option({}, {}): ",
static_cast<std::underlying_type_t<FDBNetworkOption>>(option),
value),
err);
}
}
inline Error setup_nothrow() noexcept {
return Error(native::fdb_setup_network());
}
inline Error setup_nothrow() noexcept {
return Error(native::fdb_setup_network());
}
inline void setup() {
if (auto err = setup_nothrow())
throw_error("ERROR: fdb_network_setup(): ", err);
}
inline void setup() {
if (auto err = setup_nothrow())
throw_error("ERROR: fdb_network_setup(): ", err);
}
inline Error run() {
return Error(native::fdb_run_network());
}
inline Error run() {
return Error(native::fdb_run_network());
}
inline Error stop() {
return Error(native::fdb_stop_network());
}
inline Error stop() {
return Error(native::fdb_stop_network());
}
} // namespace network
@ -207,346 +197,347 @@ class TX;
class Database;
class Result {
friend class TX;
std::shared_ptr<native::FDBResult> r;
friend class TX;
std::shared_ptr<native::FDBResult> r;
Result(native::FDBResult* result) {
if (result)
r = std::shared_ptr<native::FDBResult>(result, &native::fdb_result_destroy);
}
Result(native::FDBResult* result) {
if (result) r = std::shared_ptr<native::FDBResult>(result, &native::fdb_result_destroy);
}
public:
using KeyValueArray = future_var::KeyValueArray::type;
using KeyValueArray = future_var::KeyValueArray::type;
Error get_keyvalue_array_nothrow(KeyValueArray& out) const noexcept {
auto out_more_native = native::fdb_bool_t{};
auto& [out_kv, out_count, out_more] = out;
auto err_raw = native::fdb_result_get_keyvalue_array(r.get(), &out_kv,
&out_count, &out_more_native);
out_more = out_more_native != 0;
return Error(err_raw);
}
KeyValueArray get_keyvalue_array() const {
auto ret = KeyValueArray{};
if (auto err = get_keyvalue_array_nothrow(ret))
throw_error("ERROR: result_get_keyvalue_array(): ", err);
return ret;
}
Error get_keyvalue_array_nothrow(KeyValueArray& out) const noexcept {
auto out_more_native = native::fdb_bool_t{};
auto& [out_kv, out_count, out_more] = out;
auto err_raw = native::fdb_result_get_keyvalue_array(r.get(), &out_kv, &out_count, &out_more_native);
out_more = out_more_native != 0;
return Error(err_raw);
}
KeyValueArray get_keyvalue_array() const {
auto ret = KeyValueArray{};
if (auto err = get_keyvalue_array_nothrow(ret))
throw_error("ERROR: result_get_keyvalue_array(): ", err);
return ret;
}
};
class Future {
protected:
friend class TX;
std::shared_ptr<native::FDBFuture> f;
friend class TX;
std::shared_ptr<native::FDBFuture> f;
Future(native::FDBFuture* future)
{
if (future) f = std::shared_ptr<native::FDBFuture>(future, &native::fdb_future_destroy);
}
Future(native::FDBFuture* future) {
if (future)
f = std::shared_ptr<native::FDBFuture>(future, &native::fdb_future_destroy);
}
// wrap any capturing lambda as callback passable to fdb_future_set_callback().
// destroy after invocation.
template <class Fn>
static void callback(native::FDBFuture*, void* param) {
auto fp = static_cast<Fn*>(param);
try {
(*fp)();
} catch (const std::exception& e) {
fmt::print(stderr, "ERROR: Exception thrown in user callback: {}", e.what());
}
delete fp;
}
// wrap any capturing lambda as callback passable to fdb_future_set_callback().
// destroy after invocation.
template <class Fn>
static void callback(native::FDBFuture*, void* param) {
auto fp = static_cast<Fn*>(param);
try {
(*fp)();
} catch (const std::exception& e) {
fmt::print(stderr, "ERROR: Exception thrown in user callback: {}", e.what());
}
delete fp;
}
// set as callback user-defined completion handler of signature void(Future)
template <class FutureType, class UserFunc>
void then(UserFunc&& fn) {
auto cb = [fut=FutureType(*this), fn=std::forward<UserFunc>(fn)]() {
fn(fut);
};
using cb_type = std::decay_t<decltype(cb)>;
auto fp = new cb_type(std::move(cb));
native::fdb_future_set_callback(f.get(), &callback<cb_type>, fp);
}
// set as callback user-defined completion handler of signature void(Future)
template <class FutureType, class UserFunc>
void then(UserFunc&& fn) {
auto cb = [fut = FutureType(*this), fn = std::forward<UserFunc>(fn)]() { fn(fut); };
using cb_type = std::decay_t<decltype(cb)>;
auto fp = new cb_type(std::move(cb));
native::fdb_future_set_callback(f.get(), &callback<cb_type>, fp);
}
public:
Future() noexcept : Future(nullptr) {}
Future(const Future&) noexcept = default;
Future& operator=(const Future&) noexcept = default;
Future() noexcept : Future(nullptr) {}
Future(const Future&) noexcept = default;
Future& operator=(const Future&) noexcept = default;
bool valid() const noexcept { return f != nullptr; }
bool valid() const noexcept { return f != nullptr; }
explicit operator bool() const noexcept { return valid(); }
explicit operator bool() const noexcept { return valid(); }
bool ready() const noexcept {
assert(valid());
return native::fdb_future_is_ready(f.get()) != 0;
}
bool ready() const noexcept {
assert(valid());
return native::fdb_future_is_ready(f.get()) != 0;
}
Error block_until_ready() const noexcept {
assert(valid());
return Error(native::fdb_future_block_until_ready(f.get()));
}
Error block_until_ready() const noexcept {
assert(valid());
return Error(native::fdb_future_block_until_ready(f.get()));
}
Error error() const noexcept {
assert(valid());
return Error(native::fdb_future_get_error(f.get()));
}
Error error() const noexcept {
assert(valid());
return Error(native::fdb_future_get_error(f.get()));
}
void cancel() noexcept {
native::fdb_future_cancel(f.get());
}
void cancel() noexcept { native::fdb_future_cancel(f.get()); }
template <class VarTraits>
typename VarTraits::type get() const {
assert(valid());
assert(!error());
auto out = typename VarTraits::Type{};
if (auto err = VarTraits::extract(f.get(), out)) {
throw_error("future_get: ", err);
}
return out;
}
template <class VarTraits>
typename VarTraits::type get() const {
assert(valid());
assert(!error());
auto out = typename VarTraits::Type{};
if (auto err = VarTraits::extract(f.get(), out)) {
throw_error("future_get: ", err);
}
return out;
}
template <class VarTraits>
Error get_nothrow(typename VarTraits::type& var) const noexcept {
assert(valid());
assert(!error());
auto out = typename VarTraits::Type{};
return VarTraits::extract(f.get(), out);
}
template <class VarTraits>
Error get_nothrow(typename VarTraits::type& var) const noexcept {
assert(valid());
assert(!error());
auto out = typename VarTraits::Type{};
return VarTraits::extract(f.get(), out);
}
template <class UserFunc>
void then(UserFunc&& fn) {
then<Future>(std::forward<UserFunc>(fn));
}
template <class UserFunc>
void then(UserFunc&& fn) {
then<Future>(std::forward<UserFunc>(fn));
}
};
template <typename VarTraits>
class TypedFuture : public Future {
friend class TX;
using self_type = TypedFuture<VarTraits>;
using Future::Future;
// hide type-unsafe inherited functions
using Future::get;
using Future::get_nothrow;
using Future::then;
TypedFuture(const Future& f) noexcept : Future(f) {}
friend class TX;
using self_type = TypedFuture<VarTraits>;
using Future::Future;
// hide type-unsafe inherited functions
using Future::get;
using Future::get_nothrow;
using Future::then;
TypedFuture(const Future& f) noexcept : Future(f) {}
public:
using contained_type = typename VarTraits::type;
using contained_type = typename VarTraits::type;
Future erase_type() const noexcept {
return static_cast<Future const&>(*this);
}
Future erase_type() const noexcept { return static_cast<Future const&>(*this); }
contained_type get() const {
return get<VarTraits>();
}
contained_type get() const { return get<VarTraits>(); }
Error get_nothrow(contained_type& out) const noexcept {
return get_nothrow<VarTraits>(out);
}
Error get_nothrow(contained_type& out) const noexcept { return get_nothrow<VarTraits>(out); }
template <class UserFunc>
void then(UserFunc&& fn) {
Future::then<self_type>(std::forward<UserFunc>(fn));
}
template <class UserFunc>
void then(UserFunc&& fn) {
Future::then<self_type>(std::forward<UserFunc>(fn));
}
};
namespace key_select {
struct inclusive { static constexpr const bool value = true; };
struct inclusive {
static constexpr const bool value = true;
};
struct exclusive { static constexpr const bool value = false; };
}
struct exclusive {
static constexpr const bool value = false;
};
} // namespace key_select
class TX {
friend class Database;
std::shared_ptr<native::FDBTransaction> tr;
friend class Database;
std::shared_ptr<native::FDBTransaction> tr;
explicit TX(native::FDBTransaction* tr_raw) {
if (tr_raw)
tr = std::shared_ptr<native::FDBTransaction>(tr_raw, &native::fdb_transaction_destroy);
}
explicit TX(native::FDBTransaction* tr_raw) {
if (tr_raw) tr = std::shared_ptr<native::FDBTransaction>(tr_raw, &native::fdb_transaction_destroy);
}
public:
TX() noexcept : TX(nullptr) {}
TX(const TX&) noexcept = default;
TX& operator=(const TX&) noexcept = default;
TX() noexcept : TX(nullptr) {}
TX(const TX&) noexcept = default;
TX& operator=(const TX&) noexcept = default;
bool valid() const noexcept { return tr != nullptr; }
bool valid() const noexcept { return tr != nullptr; }
explicit operator bool() const noexcept { return valid(); }
explicit operator bool() const noexcept { return valid(); }
Error set_option_nothrow(FDBTransactionOption option, int64_t value) noexcept {
return Error(native::fdb_transaction_set_option(
tr.get(), option,
reinterpret_cast<const uint8_t*>(&value),
static_cast<int>(sizeof(value))));
}
Error set_option_nothrow(FDBTransactionOption option, int64_t value) noexcept {
return Error(native::fdb_transaction_set_option(
tr.get(), option, reinterpret_cast<const uint8_t*>(&value), static_cast<int>(sizeof(value))));
}
Error set_option_nothrow(FDBTransactionOption option, BytesRef str) noexcept {
return Error(native::fdb_transaction_set_option(
tr.get(), option, str.data(), intsize(str)));
}
Error set_option_nothrow(FDBTransactionOption option, BytesRef str) noexcept {
return Error(native::fdb_transaction_set_option(tr.get(), option, str.data(), intsize(str)));
}
void set_option(FDBTransactionOption option, int64_t value) {
if (auto err = set_option_nothrow(option, value)) {
throw_error(fmt::format("transaction_set_option({}, {}) returned error: ",
static_cast<std::underlying_type_t<FDBTransactionOption>>(option),
value),
err);
}
}
void set_option(FDBTransactionOption option, int64_t value) {
if (auto err = set_option_nothrow(option, value)) {
throw_error(fmt::format("transaction_set_option({}, {}) returned error: ",
static_cast<std::underlying_type_t<FDBTransactionOption>>(option),
value),
err);
}
}
void set_option(FDBTransactionOption option, BytesRef str) {
if (auto err = set_option_nothrow(option, str)) {
throw_error(
fmt::format("transaction_set_option({}) returned error: ",
static_cast<std::underlying_type_t<FDBTransactionOption>>(option)),
err);
}
}
void set_option(FDBTransactionOption option, BytesRef str) {
if (auto err = set_option_nothrow(option, str)) {
throw_error(fmt::format("transaction_set_option({}) returned error: ",
static_cast<std::underlying_type_t<FDBTransactionOption>>(option)),
err);
}
}
TypedFuture<future_var::Int64> get_read_version() {
return native::fdb_transaction_get_read_version(tr.get());
}
TypedFuture<future_var::Int64> get_read_version() { return native::fdb_transaction_get_read_version(tr.get()); }
Error get_committed_version_nothrow(int64_t& out) {
return Error(native::fdb_transaction_get_committed_version(tr.get(), &out));
}
Error get_committed_version_nothrow(int64_t& out) {
return Error(native::fdb_transaction_get_committed_version(tr.get(), &out));
}
int64_t get_committed_version() {
auto out = int64_t{};
if (auto err = get_committed_version_nothrow(out)) {
throw_error("get_committed_version: ", err);
}
return out;
}
int64_t get_committed_version() {
auto out = int64_t{};
if (auto err = get_committed_version_nothrow(out)) {
throw_error("get_committed_version: ", err);
}
return out;
}
// Func should have signature void(Future f, bool need_retry)
// Func should first check that retry == false and f.error() == 0
// before attempting to extract value from f
TypedFuture<future_var::Value> get(KeyRef key, bool snapshot) {
return native::fdb_transaction_get(tr.get(), key.data(), intsize(key), snapshot);
}
// Func should have signature void(Future f, bool need_retry)
// Func should first check that retry == false and f.error() == 0
// before attempting to extract value from f
TypedFuture<future_var::Value> get(KeyRef key, bool snapshot) {
return native::fdb_transaction_get(tr.get(), key.data(), intsize(key), snapshot);
}
// Usage: tx.get_range<key_select::inclusive, key_select::exclusive>(begin, end, ...);
// gets key-value pairs in key range [begin, end)
template <class FirstInclusive, class LastInclusive>
TypedFuture<future_var::KeyValueArray> get_range(KeyRef begin, KeyRef end,
int limit, int target_bytes, FDBStreamingMode mode,
int iteration, bool snapshot, bool reverse) {
if constexpr (FirstInclusive::value && LastInclusive::value) {
return native::fdb_transaction_get_range(tr.get(),
FDB_KEYSEL_FIRST_GREATER_OR_EQUAL(begin.data(), intsize(begin)),
FDB_KEYSEL_LAST_LESS_OR_EQUAL(end.data(), intsize(end)),
limit, target_bytes, mode, iteration, snapshot, reverse);
} else if constexpr (FirstInclusive::value && !LastInclusive::value) {
return native::fdb_transaction_get_range(tr.get(),
FDB_KEYSEL_FIRST_GREATER_OR_EQUAL(begin.data(), intsize(begin)),
FDB_KEYSEL_LAST_LESS_THAN(end.data(), intsize(end)),
limit, target_bytes, mode, iteration, snapshot, reverse);
} else if constexpr (!FirstInclusive::value && LastInclusive::value) {
return native::fdb_transaction_get_range(tr.get(),
FDB_KEYSEL_FIRST_GREATER_THAN(begin.data(), intsize(begin)),
FDB_KEYSEL_LAST_LESS_OR_EQUAL(end.data(), intsize(end)),
limit, target_bytes, mode, iteration, snapshot, reverse);
} else {
return native::fdb_transaction_get_range(tr.get(),
FDB_KEYSEL_FIRST_GREATER_THAN(begin.data(), intsize(begin)),
FDB_KEYSEL_LAST_LESS_THAN(end.data(), intsize(end)),
limit, target_bytes, mode, iteration, snapshot, reverse);
}
}
// Usage: tx.get_range<key_select::inclusive, key_select::exclusive>(begin, end, ...);
// gets key-value pairs in key range [begin, end)
template <class FirstInclusive, class LastInclusive>
TypedFuture<future_var::KeyValueArray> get_range(KeyRef begin,
KeyRef end,
int limit,
int target_bytes,
FDBStreamingMode mode,
int iteration,
bool snapshot,
bool reverse) {
if constexpr (FirstInclusive::value && LastInclusive::value) {
return native::fdb_transaction_get_range(tr.get(),
FDB_KEYSEL_FIRST_GREATER_OR_EQUAL(begin.data(), intsize(begin)),
FDB_KEYSEL_LAST_LESS_OR_EQUAL(end.data(), intsize(end)),
limit,
target_bytes,
mode,
iteration,
snapshot,
reverse);
} else if constexpr (FirstInclusive::value && !LastInclusive::value) {
return native::fdb_transaction_get_range(tr.get(),
FDB_KEYSEL_FIRST_GREATER_OR_EQUAL(begin.data(), intsize(begin)),
FDB_KEYSEL_LAST_LESS_THAN(end.data(), intsize(end)),
limit,
target_bytes,
mode,
iteration,
snapshot,
reverse);
} else if constexpr (!FirstInclusive::value && LastInclusive::value) {
return native::fdb_transaction_get_range(tr.get(),
FDB_KEYSEL_FIRST_GREATER_THAN(begin.data(), intsize(begin)),
FDB_KEYSEL_LAST_LESS_OR_EQUAL(end.data(), intsize(end)),
limit,
target_bytes,
mode,
iteration,
snapshot,
reverse);
} else {
return native::fdb_transaction_get_range(tr.get(),
FDB_KEYSEL_FIRST_GREATER_THAN(begin.data(), intsize(begin)),
FDB_KEYSEL_LAST_LESS_THAN(end.data(), intsize(end)),
limit,
target_bytes,
mode,
iteration,
snapshot,
reverse);
}
}
Result read_blob_granules(KeyRef begin, KeyRef end,
int64_t begin_version, int64_t read_version,
native::FDBReadBlobGranuleContext context) {
return Result(native::fdb_transaction_read_blob_granules(tr.get(),
begin.data(), intsize(begin),
end.data(), intsize(end),
begin_version, read_version, context));
}
Result read_blob_granules(KeyRef begin,
KeyRef end,
int64_t begin_version,
int64_t read_version,
native::FDBReadBlobGranuleContext context) {
return Result(native::fdb_transaction_read_blob_granules(
tr.get(), begin.data(), intsize(begin), end.data(), intsize(end), begin_version, read_version, context));
}
TypedFuture<future_var::None> commit() {
return native::fdb_transaction_commit(tr.get());
}
TypedFuture<future_var::None> commit() { return native::fdb_transaction_commit(tr.get()); }
TypedFuture<future_var::None> on_error(Error err) {
return native::fdb_transaction_on_error(tr.get(), err.code());
}
TypedFuture<future_var::None> on_error(Error err) { return native::fdb_transaction_on_error(tr.get(), err.code()); }
void reset() {
return native::fdb_transaction_reset(tr.get());
}
void reset() { return native::fdb_transaction_reset(tr.get()); }
void set(KeyRef key, ValueRef value) {
native::fdb_transaction_set(tr.get(), key.data(), intsize(key), value.data(), intsize(value));
}
void set(KeyRef key, ValueRef value) {
native::fdb_transaction_set(tr.get(), key.data(), intsize(key), value.data(), intsize(value));
}
void clear(KeyRef key) {
native::fdb_transaction_clear(tr.get(), key.data(), intsize(key));
}
void clear_range(KeyRef begin, KeyRef end) {
native::fdb_transaction_clear_range(tr.get(), begin.data(), intsize(begin),
end.data(), intsize(end));
}
void clear(KeyRef key) { native::fdb_transaction_clear(tr.get(), key.data(), intsize(key)); }
void clear_range(KeyRef begin, KeyRef end) {
native::fdb_transaction_clear_range(tr.get(), begin.data(), intsize(begin), end.data(), intsize(end));
}
};
class Database {
std::shared_ptr<native::FDBDatabase> db;
std::shared_ptr<native::FDBDatabase> db;
public:
Database(const Database&) noexcept = default;
Database& operator=(const Database&) noexcept = default;
Database(const std::string& cluster_file_path) : db(nullptr) {
auto db_raw = static_cast<native::FDBDatabase*>(nullptr);
if (auto err = Error(native::fdb_create_database(cluster_file_path.c_str(), &db_raw)))
throw_error(
fmt::format("Failed to create database with '{}': ", cluster_file_path),
err);
db = std::shared_ptr<native::FDBDatabase>(db_raw, &native::fdb_database_destroy);
}
Database() noexcept : db(nullptr) {}
Database(const Database&) noexcept = default;
Database& operator=(const Database&) noexcept = default;
Database(const std::string& cluster_file_path) : db(nullptr) {
auto db_raw = static_cast<native::FDBDatabase*>(nullptr);
if (auto err = Error(native::fdb_create_database(cluster_file_path.c_str(), &db_raw)))
throw_error(fmt::format("Failed to create database with '{}': ", cluster_file_path), err);
db = std::shared_ptr<native::FDBDatabase>(db_raw, &native::fdb_database_destroy);
}
Database() noexcept : db(nullptr) {}
Error set_option_nothrow(FDBDatabaseOption option, int64_t value) noexcept {
return Error(native::fdb_database_set_option(
db.get(), option,
reinterpret_cast<const uint8_t*>(&value),
static_cast<int>(sizeof(value))));
}
Error set_option_nothrow(FDBDatabaseOption option, int64_t value) noexcept {
return Error(native::fdb_database_set_option(
db.get(), option, reinterpret_cast<const uint8_t*>(&value), static_cast<int>(sizeof(value))));
}
Error set_option_nothrow(FDBDatabaseOption option, BytesRef str) noexcept {
return Error(native::fdb_database_set_option(
db.get(), option, str.data(), intsize(str)));
}
Error set_option_nothrow(FDBDatabaseOption option, BytesRef str) noexcept {
return Error(native::fdb_database_set_option(db.get(), option, str.data(), intsize(str)));
}
void set_option(FDBDatabaseOption option, int64_t value) {
if (auto err = set_option_nothrow(option, value)) {
throw_error(
fmt::format("database_set_option({}, {}) returned error: ",
static_cast<std::underlying_type_t<FDBDatabaseOption>>(option),
value),
err);
}
}
void set_option(FDBDatabaseOption option, int64_t value) {
if (auto err = set_option_nothrow(option, value)) {
throw_error(fmt::format("database_set_option({}, {}) returned error: ",
static_cast<std::underlying_type_t<FDBDatabaseOption>>(option),
value),
err);
}
}
void set_option(FDBDatabaseOption option, BytesRef str) {
if (auto err = set_option_nothrow(option, str)) {
throw_error(
fmt::format("database_set_option({}) returned error: ",
static_cast<std::underlying_type_t<FDBDatabaseOption>>(option)),
err);
}
}
void set_option(FDBDatabaseOption option, BytesRef str) {
if (auto err = set_option_nothrow(option, str)) {
throw_error(fmt::format("database_set_option({}) returned error: ",
static_cast<std::underlying_type_t<FDBDatabaseOption>>(option)),
err);
}
}
TX create_tx() {
if (!db) throw std::runtime_error("create_transaction from null database");
auto tx_native = static_cast<native::FDBTransaction*>(nullptr);
auto err = Error(native::fdb_database_create_transaction(db.get(), &tx_native));
if (err) throw_error("Failed to create transaction: ", err);
return TX(tx_native);
}
TX create_tx() {
if (!db)
throw std::runtime_error("create_transaction from null database");
auto tx_native = static_cast<native::FDBTransaction*>(nullptr);
auto err = Error(native::fdb_database_create_transaction(db.get(), &tx_native));
if (err)
throw_error("Failed to create transaction: ", err);
return TX(tx_native);
}
};
} // namespace fdb

File diff suppressed because it is too large Load Diff

View File

@ -23,71 +23,71 @@
#include <limits.h>
#endif
constexpr const int VERBOSE_NONE = 0;
constexpr const int VERBOSE_DEFAULT = 1;
constexpr const int VERBOSE_NONE = 0;
constexpr const int VERBOSE_DEFAULT = 1;
constexpr const int VERBOSE_ANNOYING = 2;
constexpr const int VERBOSE_DEBUG = 3;
constexpr const int VERBOSE_DEBUG = 3;
constexpr const int MODE_INVALID = -1;
constexpr const int MODE_CLEAN = 0;
constexpr const int MODE_BUILD = 1;
constexpr const int MODE_RUN = 2;
constexpr const int MODE_CLEAN = 0;
constexpr const int MODE_BUILD = 1;
constexpr const int MODE_RUN = 2;
/* size of each block to get detailed latency for each operation */
constexpr const size_t LAT_BLOCK_SIZE = 511;
/* transaction specification */
enum Operations {
OP_GETREADVERSION,
OP_GET,
OP_GETRANGE,
OP_SGET,
OP_SGETRANGE,
OP_UPDATE,
OP_INSERT,
OP_INSERTRANGE,
OP_OVERWRITE,
OP_CLEAR,
OP_SETCLEAR,
OP_CLEARRANGE,
OP_SETCLEARRANGE,
OP_COMMIT,
OP_TRANSACTION, /* pseudo-operation - cumulative time for the operation + commit */
OP_READ_BG,
MAX_OP /* must be the last item */
OP_GETREADVERSION,
OP_GET,
OP_GETRANGE,
OP_SGET,
OP_SGETRANGE,
OP_UPDATE,
OP_INSERT,
OP_INSERTRANGE,
OP_OVERWRITE,
OP_CLEAR,
OP_SETCLEAR,
OP_CLEARRANGE,
OP_SETCLEARRANGE,
OP_COMMIT,
OP_TRANSACTION, /* pseudo-operation - cumulative time for the operation + commit */
OP_READ_BG,
MAX_OP /* must be the last item */
};
constexpr const int OP_COUNT = 0;
constexpr const int OP_RANGE = 1;
constexpr const int OP_COUNT = 0;
constexpr const int OP_RANGE = 1;
constexpr const int OP_REVERSE = 2;
/* for long arguments */
enum Arguments {
ARG_KEYLEN,
ARG_VALLEN,
ARG_TPS,
ARG_COMMITGET,
ARG_SAMPLING,
ARG_VERSION,
ARG_KNOBS,
ARG_FLATBUFFERS,
ARG_LOGGROUP,
ARG_PREFIXPADDING,
ARG_TRACE,
ARG_TRACEPATH,
ARG_TRACEFORMAT,
ARG_TPSMAX,
ARG_TPSMIN,
ARG_TPSINTERVAL,
ARG_TPSCHANGE,
ARG_TXNTRACE,
ARG_TXNTAGGING,
ARG_TXNTAGGINGPREFIX,
ARG_STREAMING_MODE,
ARG_DISABLE_RYW,
ARG_CLIENT_THREADS_PER_VERSION,
ARG_JSON_REPORT,
ARG_BG_FILE_PATH // if blob granule files are stored locally, mako will read and materialize them if this is set
ARG_KEYLEN,
ARG_VALLEN,
ARG_TPS,
ARG_COMMITGET,
ARG_SAMPLING,
ARG_VERSION,
ARG_KNOBS,
ARG_FLATBUFFERS,
ARG_LOGGROUP,
ARG_PREFIXPADDING,
ARG_TRACE,
ARG_TRACEPATH,
ARG_TRACEFORMAT,
ARG_TPSMAX,
ARG_TPSMIN,
ARG_TPSINTERVAL,
ARG_TPSCHANGE,
ARG_TXNTRACE,
ARG_TXNTAGGING,
ARG_TXNTAGGINGPREFIX,
ARG_STREAMING_MODE,
ARG_DISABLE_RYW,
ARG_CLIENT_THREADS_PER_VERSION,
ARG_JSON_REPORT,
ARG_BG_FILE_PATH // if blob granule files are stored locally, mako will read and materialize them if this is set
};
enum TPSChangeTypes { TPS_SIN, TPS_SQUARE, TPS_PULSE };
@ -97,58 +97,58 @@ enum TPSChangeTypes { TPS_SIN, TPS_SQUARE, TPS_PULSE };
*/
typedef struct {
/* for each operation, it stores "count", "range" and "reverse" */
int ops[MAX_OP][3];
/* for each operation, it stores "count", "range" and "reverse" */
int ops[MAX_OP][3];
} mako_txnspec_t;
constexpr const int LOGGROUP_MAX = 256;
constexpr const int KNOB_MAX = 256;
constexpr const int LOGGROUP_MAX = 256;
constexpr const int KNOB_MAX = 256;
constexpr const int TAGPREFIXLENGTH_MAX = 8;
constexpr const int NUM_CLUSTERS_MAX = 3;
constexpr const int NUM_DATABASES_MAX = 10;
constexpr const int MAX_BG_IDS = 1000;
constexpr const int NUM_CLUSTERS_MAX = 3;
constexpr const int NUM_DATABASES_MAX = 10;
constexpr const int MAX_BG_IDS = 1000;
/* benchmark parameters */
struct mako_args_t {
int api_version;
int json;
int num_processes;
int num_threads;
int mode;
int rows; /* is 2 billion enough? */
int row_digits;
int seconds;
int iteration;
int tpsmax;
int tpsmin;
int tpsinterval;
int tpschange;
int sampling;
int key_length;
int value_length;
int zipf;
int commit_get;
int verbose;
mako_txnspec_t txnspec;
char cluster_files[NUM_CLUSTERS_MAX][PATH_MAX];
int num_fdb_clusters;
int num_databases;
char log_group[LOGGROUP_MAX];
int prefixpadding;
int trace;
char tracepath[PATH_MAX];
int traceformat; /* 0 - XML, 1 - JSON */
char knobs[KNOB_MAX];
uint8_t flatbuffers;
int txntrace;
int txntagging;
char txntagging_prefix[TAGPREFIXLENGTH_MAX];
FDBStreamingMode streaming_mode;
int64_t client_threads_per_version;
int disable_ryw;
char json_output_path[PATH_MAX];
bool bg_materialize_files;
char bg_file_path[PATH_MAX];
int api_version;
int json;
int num_processes;
int num_threads;
int mode;
int rows; /* is 2 billion enough? */
int row_digits;
int seconds;
int iteration;
int tpsmax;
int tpsmin;
int tpsinterval;
int tpschange;
int sampling;
int key_length;
int value_length;
int zipf;
int commit_get;
int verbose;
mako_txnspec_t txnspec;
char cluster_files[NUM_CLUSTERS_MAX][PATH_MAX];
int num_fdb_clusters;
int num_databases;
char log_group[LOGGROUP_MAX];
int prefixpadding;
int trace;
char tracepath[PATH_MAX];
int traceformat; /* 0 - XML, 1 - JSON */
char knobs[KNOB_MAX];
uint8_t flatbuffers;
int txntrace;
int txntagging;
char txntagging_prefix[TAGPREFIXLENGTH_MAX];
FDBStreamingMode streaming_mode;
int64_t client_threads_per_version;
int disable_ryw;
char json_output_path[PATH_MAX];
bool bg_materialize_files;
char bg_file_path[PATH_MAX];
};
/* shared memory */
@ -157,155 +157,140 @@ constexpr const int SIGNAL_GREEN = 1;
constexpr const int SIGNAL_OFF = 2;
struct mako_shmhdr_t {
std::atomic<int> signal;
std::atomic<int> readycount;
std::atomic<double> throttle_factor;
std::atomic<int> stopcount;
std::atomic<int> signal;
std::atomic<int> readycount;
std::atomic<double> throttle_factor;
std::atomic<int> stopcount;
};
class alignas(64) mako_stats_t {
uint64_t xacts;
uint64_t conflicts;
uint64_t total_errors;
uint64_t ops[MAX_OP];
uint64_t errors[MAX_OP];
uint64_t latency_samples[MAX_OP];
uint64_t latency_us_total[MAX_OP];
uint64_t latency_us_min[MAX_OP];
uint64_t latency_us_max[MAX_OP];
uint64_t xacts;
uint64_t conflicts;
uint64_t total_errors;
uint64_t ops[MAX_OP];
uint64_t errors[MAX_OP];
uint64_t latency_samples[MAX_OP];
uint64_t latency_us_total[MAX_OP];
uint64_t latency_us_min[MAX_OP];
uint64_t latency_us_max[MAX_OP];
public:
mako_stats_t() noexcept {
memset(this, 0, sizeof(mako_stats_t));
memset(latency_us_max, 0xff, sizeof(latency_us_max));
}
mako_stats_t() noexcept {
memset(this, 0, sizeof(mako_stats_t));
memset(latency_us_max, 0xff, sizeof(latency_us_max));
}
mako_stats_t(const mako_stats_t& other) noexcept = default;
mako_stats_t& operator=(const mako_stats_t& other) noexcept = default;
mako_stats_t(const mako_stats_t& other) noexcept = default;
mako_stats_t& operator=(const mako_stats_t& other) noexcept = default;
uint64_t get_tx_count() const noexcept {
return xacts;
}
uint64_t get_tx_count() const noexcept { return xacts; }
uint64_t get_conflict_count() const noexcept {
return conflicts;
}
uint64_t get_conflict_count() const noexcept { return conflicts; }
uint64_t get_op_count(int op) const noexcept {
return ops[op];
}
uint64_t get_op_count(int op) const noexcept { return ops[op]; }
uint64_t get_error_count(int op) const noexcept {
return errors[op];
}
uint64_t get_error_count(int op) const noexcept { return errors[op]; }
uint64_t get_total_error_count() const noexcept {
return total_errors;
}
uint64_t get_total_error_count() const noexcept { return total_errors; }
uint64_t get_latency_sample_count(int op) const noexcept {
return latency_samples[op];
}
uint64_t get_latency_sample_count(int op) const noexcept { return latency_samples[op]; }
uint64_t get_latency_us_total(int op) const noexcept {
return latency_us_total[op];
}
uint64_t get_latency_us_total(int op) const noexcept { return latency_us_total[op]; }
uint64_t get_latency_us_min(int op) const noexcept {
return latency_us_min[op];
}
uint64_t get_latency_us_min(int op) const noexcept { return latency_us_min[op]; }
uint64_t get_latency_us_max(int op) const noexcept {
return latency_us_max[op];
}
uint64_t get_latency_us_max(int op) const noexcept { return latency_us_max[op]; }
// with 'this' as final aggregation, factor in 'other'
void combine(const mako_stats_t& other) {
xacts += other.xacts;
conflicts += other.conflicts;
for (auto op = 0; op < MAX_OP; op++) {
ops[op] += other.ops[op];
errors[op] += other.errors[op];
total_errors += other.errors[op];
latency_samples[op] += other.latency_samples[op];
latency_us_total[op] += other.latency_us_total[op];
if (latency_us_min[op] > other.latency_us_min[op])
latency_us_min[op] = other.latency_us_min[op];
if (latency_us_min[op] < other.latency_us_min[op])
latency_us_max[op] = other.latency_us_max[op];
}
}
// with 'this' as final aggregation, factor in 'other'
void combine(const mako_stats_t& other) {
xacts += other.xacts;
conflicts += other.conflicts;
for (auto op = 0; op < MAX_OP; op++) {
ops[op] += other.ops[op];
errors[op] += other.errors[op];
total_errors += other.errors[op];
latency_samples[op] += other.latency_samples[op];
latency_us_total[op] += other.latency_us_total[op];
if (latency_us_min[op] > other.latency_us_min[op])
latency_us_min[op] = other.latency_us_min[op];
if (latency_us_min[op] < other.latency_us_min[op])
latency_us_max[op] = other.latency_us_max[op];
}
}
void incr_tx_count() noexcept { xacts++; }
void incr_conflict_count() noexcept { conflicts++; }
void incr_tx_count() noexcept { xacts++; }
void incr_conflict_count() noexcept { conflicts++; }
// non-commit write operations aren't measured for time.
void incr_count_immediate(int op) noexcept { ops[op]++; }
// non-commit write operations aren't measured for time.
void incr_count_immediate(int op) noexcept { ops[op]++; }
void incr_error_count(int op) noexcept {
total_errors++;
errors[op]++;
}
void incr_error_count(int op) noexcept {
total_errors++;
errors[op]++;
}
void add_latency(int op, uint64_t latency_us) noexcept {
latency_samples[op]++;
latency_us_total[op] += latency_us;
if (latency_us_min[op] > latency_us)
latency_us_min[op] = latency_us;
if (latency_us_max[op] < latency_us)
latency_us_max[op] = latency_us;
ops[op]++;
}
void add_latency(int op, uint64_t latency_us) noexcept {
latency_samples[op]++;
latency_us_total[op] += latency_us;
if (latency_us_min[op] > latency_us)
latency_us_min[op] = latency_us;
if (latency_us_max[op] < latency_us)
latency_us_max[op] = latency_us;
ops[op]++;
}
};
/* per-process information */
typedef struct {
int worker_id;
pid_t parent_id;
mako_args_t* args;
mako_shmhdr_t* shm;
std::vector<fdb::Database> databases;
int worker_id;
pid_t parent_id;
mako_args_t* args;
mako_shmhdr_t* shm;
std::vector<fdb::Database> databases;
} process_info_t;
/* memory block allocated to each operation when collecting detailed latency */
class lat_block_t {
uint64_t samples[LAT_BLOCK_SIZE]{0, };
uint32_t index{0};
uint64_t samples[LAT_BLOCK_SIZE]{
0,
};
uint32_t index{ 0 };
public:
lat_block_t() noexcept = default;
bool full() const noexcept { return index >= LAT_BLOCK_SIZE; }
void put(uint64_t point) {
assert(!full());
samples[index++] = point;
}
// return {data block, number of samples}
std::pair<uint64_t const*, size_t> data() const noexcept {
return {samples, index};
}
lat_block_t() noexcept = default;
bool full() const noexcept { return index >= LAT_BLOCK_SIZE; }
void put(uint64_t point) {
assert(!full());
samples[index++] = point;
}
// return {data block, number of samples}
std::pair<uint64_t const*, size_t> data() const noexcept { return { samples, index }; }
};
/* collect sampled latencies */
class sample_bin {
std::list<lat_block_t> blocks;
std::list<lat_block_t> blocks;
public:
void reserve_one() {
if (blocks.empty())
blocks.emplace_back();
}
void reserve_one() {
if (blocks.empty())
blocks.emplace_back();
}
void put(uint64_t latency_us) {
if (blocks.empty() || blocks.back().full())
blocks.emplace_back();
blocks.back().put(latency_us);
}
void put(uint64_t latency_us) {
if (blocks.empty() || blocks.back().full())
blocks.emplace_back();
blocks.back().put(latency_us);
}
// iterate & apply for each block user function void(uint64_t const*, size_t)
template <typename Func>
void for_each_block(Func&& fn) const {
for (const auto& block : blocks) {
auto [ptr, cnt] = block.data();
fn(ptr, cnt);
}
}
// iterate & apply for each block user function void(uint64_t const*, size_t)
template <typename Func>
void for_each_block(Func&& fn) const {
for (const auto& block : blocks) {
auto [ptr, cnt] = block.data();
fn(ptr, cnt);
}
}
};
using sample_bin_array_t = std::array<sample_bin, MAX_OP>;
@ -313,7 +298,7 @@ using sample_bin_array_t = std::array<sample_bin, MAX_OP>;
struct alignas(64) thread_args_t {
int thread_id;
int database_index; // index of the database to do work to
sample_bin_array_t sample_bins;
sample_bin_array_t sample_bins;
process_info_t* process;
};
@ -322,38 +307,32 @@ typedef enum { proc_master = 0, proc_worker, proc_stats } proc_type_t;
// determines how resultant future will be handled
enum class StepKind {
NONE, ///< not part of the table: OP_TRANSACTION, OP_COMMIT
IMM, ///< non-future ops that return immediately: e.g. set, clear_range
READ, ///< blockable reads: get(), get_range(), get_read_version, ...
COMMIT, ///< self-explanatory
ON_ERROR ///< future is a result of tx.on_error()
NONE, ///< not part of the table: OP_TRANSACTION, OP_COMMIT
IMM, ///< non-future ops that return immediately: e.g. set, clear_range
READ, ///< blockable reads: get(), get_range(), get_read_version, ...
COMMIT, ///< self-explanatory
ON_ERROR ///< future is a result of tx.on_error()
};
class OpDesc {
std::string_view name_;
std::vector<StepKind> steps_;
bool needs_commit_;
public:
OpDesc(std::string_view name, std::vector<StepKind>&& steps, bool needs_commit) :
name_(name), steps_(std::move(steps)), needs_commit_(needs_commit)
{}
std::string_view name_;
std::vector<StepKind> steps_;
bool needs_commit_;
std::string_view name() const noexcept {
return name_;
}
// what
StepKind step_kind(int step) const noexcept {
assert(step < steps());
return steps_[step];
}
// how many steps in this op?
int steps() const noexcept {
return static_cast<int>(steps_.size());
}
// does the op needs to commit some time after its final step?
bool needs_commit() const noexcept {
return needs_commit_;
}
public:
OpDesc(std::string_view name, std::vector<StepKind>&& steps, bool needs_commit)
: name_(name), steps_(std::move(steps)), needs_commit_(needs_commit) {}
std::string_view name() const noexcept { return name_; }
// what
StepKind step_kind(int step) const noexcept {
assert(step < steps());
return steps_[step];
}
// how many steps in this op?
int steps() const noexcept { return static_cast<int>(steps_.size()); }
// does the op needs to commit some time after its final step?
bool needs_commit() const noexcept { return needs_commit_; }
};
#endif /* MAKO_HPP */

View File

@ -13,24 +13,24 @@
int urand(int low, int high);
/* random string */
template <bool Clear=true, typename Char>
template <bool Clear = true, typename Char>
void randstr(std::basic_string<Char>& str, int len) {
if constexpr (Clear)
str.clear();
assert(len >= 0);
str.reserve(str.size() + static_cast<size_t>(len));
if constexpr (Clear)
str.clear();
assert(len >= 0);
str.reserve(str.size() + static_cast<size_t>(len));
for (auto i = 0; i < len; i++) {
str.push_back('!' + urand(0, 'z' - '!')); /* generage a char from '!' to 'z' */
}
}
/* random numeric string */
template <bool Clear=true, typename Char>
template <bool Clear = true, typename Char>
void randnumstr(std::basic_string<Char>& str, int len) {
if constexpr (Clear)
str.clear();
assert(len >= 0);
str.reserve(str.size() + static_cast<size_t>(len));
if constexpr (Clear)
str.clear();
assert(len >= 0);
str.reserve(str.size() + static_cast<size_t>(len));
for (auto i = 0; i < len; i++) {
str.push_back('0' + urand(0, 9)); /* generage a char from '0' to '9' */
}
@ -67,66 +67,63 @@ int digits(int num);
/* fill (str) with configured key prefix: i.e. non-numeric part
* (str) is appended with concat([padding], PREFIX)
*/
template <bool Clear=true, typename Char>
void genkeyprefix(std::basic_string<Char>& str,
std::string_view prefix,
mako_args_t const& args) {
// concat('x' * padding_len, key_prefix)
if constexpr (Clear)
str.clear();
const auto padding_len = args.prefixpadding ?
(args.key_length - args.row_digits - static_cast<int>(prefix.size())) : 0;
assert(padding_len >= 0);
str.reserve(str.size() + padding_len + prefix.size());
fmt::format_to(std::back_inserter(str),
"{0:x>{1}}{2}", "", padding_len, prefix);
template <bool Clear = true, typename Char>
void genkeyprefix(std::basic_string<Char>& str, std::string_view prefix, mako_args_t const& args) {
// concat('x' * padding_len, key_prefix)
if constexpr (Clear)
str.clear();
const auto padding_len =
args.prefixpadding ? (args.key_length - args.row_digits - static_cast<int>(prefix.size())) : 0;
assert(padding_len >= 0);
str.reserve(str.size() + padding_len + prefix.size());
fmt::format_to(std::back_inserter(str), "{0:x>{1}}{2}", "", padding_len, prefix);
}
/* generate a key for a given key number */
/* prefix is "mako" by default, prefixpadding = 1 means 'x' will be in front rather than trailing the keyname */
template <bool Clear=true, typename Char>
void genkey(std::basic_string<Char>& str,
std::string_view prefix,
mako_args_t const& args, int num) {
static_assert(sizeof(Char) == 1);
const auto pad_len = args.prefixpadding ?
args.key_length - (static_cast<int>(prefix.size()) + args.row_digits) : 0;
assert(pad_len >= 0);
if constexpr (Clear)
str.clear();
str.reserve(str.size() + static_cast<size_t>(args.key_length));
fmt::format_to(std::back_inserter(str),
"{0:x>{1}}{2}{3:0{4}d}{5:x>{6}}",
"", pad_len,
prefix,
num, args.row_digits,
"", args.key_length - pad_len - static_cast<int>(prefix.size()) - args.row_digits);
template <bool Clear = true, typename Char>
void genkey(std::basic_string<Char>& str, std::string_view prefix, mako_args_t const& args, int num) {
static_assert(sizeof(Char) == 1);
const auto pad_len = args.prefixpadding ? args.key_length - (static_cast<int>(prefix.size()) + args.row_digits) : 0;
assert(pad_len >= 0);
if constexpr (Clear)
str.clear();
str.reserve(str.size() + static_cast<size_t>(args.key_length));
fmt::format_to(std::back_inserter(str),
"{0:x>{1}}{2}{3:0{4}d}{5:x>{6}}",
"",
pad_len,
prefix,
num,
args.row_digits,
"",
args.key_length - pad_len - static_cast<int>(prefix.size()) - args.row_digits);
}
// invoke user-provided callable when object goes out of scope.
template <typename Func>
class exit_guard {
std::decay_t<Func> fn;
public:
exit_guard(Func&& fn) : fn(std::forward<Func>(fn)) {}
std::decay_t<Func> fn;
~exit_guard() {
fn();
}
public:
exit_guard(Func&& fn) : fn(std::forward<Func>(fn)) {}
~exit_guard() { fn(); }
};
// invoke user-provided callable when stack unwinds by exception.
template <typename Func>
class fail_guard {
std::decay_t<Func> fn;
public:
fail_guard(Func&& fn) : fn(std::forward<Func>(fn)) {}
std::decay_t<Func> fn;
~fail_guard() {
if (std::uncaught_exceptions()) {
fn();
}
}
public:
fail_guard(Func&& fn) : fn(std::forward<Func>(fn)) {}
~fail_guard() {
if (std::uncaught_exceptions()) {
fn();
}
}
};
// timing helpers
@ -135,17 +132,17 @@ using timepoint_t = decltype(steady_clock::now());
template <typename Duration>
double to_double_seconds(Duration duration) {
return std::chrono::duration_cast<std::chrono::duration<double>>(duration).count();
return std::chrono::duration_cast<std::chrono::duration<double>>(duration).count();
}
template <typename Duration>
uint64_t to_integer_seconds(Duration duration) {
return std::chrono::duration_cast<std::chrono::duration<uint64_t>>(duration).count();
return std::chrono::duration_cast<std::chrono::duration<uint64_t>>(duration).count();
}
template <typename Duration>
uint64_t to_integer_microseconds(Duration duration) {
return std::chrono::duration_cast<std::chrono::duration<uint64_t, std::micro>>(duration).count();
return std::chrono::duration_cast<std::chrono::duration<uint64_t, std::micro>>(duration).count();
}
// trace helpers
@ -154,31 +151,30 @@ constexpr const int STATS_FIELD_WIDTH = 12;
template <typename Value>
void put_title(Value&& value) {
fmt::print("{0: <{1}} ", std::forward<Value>(value), STATS_TITLE_WIDTH);
fmt::print("{0: <{1}} ", std::forward<Value>(value), STATS_TITLE_WIDTH);
}
template <typename Value>
void put_title_r(Value&& value) {
fmt::print("{0: >{1}} ", std::forward<Value>(value), STATS_TITLE_WIDTH);
fmt::print("{0: >{1}} ", std::forward<Value>(value), STATS_TITLE_WIDTH);
}
inline void put_title_bar() {
fmt::print("{0:=<{1}} ", "", STATS_TITLE_WIDTH);
fmt::print("{0:=<{1}} ", "", STATS_TITLE_WIDTH);
}
template <typename Value>
void put_field(Value&& value) {
fmt::print("{0: >{1}} ", std::forward<Value>(value), STATS_FIELD_WIDTH);
fmt::print("{0: >{1}} ", std::forward<Value>(value), STATS_FIELD_WIDTH);
}
inline void put_field_bar() {
fmt::print("{0:=>{1}} ", "", STATS_FIELD_WIDTH);
fmt::print("{0:=>{1}} ", "", STATS_FIELD_WIDTH);
}
template <typename Value>
void put_field_f(Value&& value, int precision) {
fmt::print("{0: >{1}.{2}f} ",
std::forward<Value>(value), STATS_FIELD_WIDTH, precision);
fmt::print("{0: >{1}.{2}f} ", std::forward<Value>(value), STATS_FIELD_WIDTH, precision);
}
#endif /* UTILS_HPP */