Simplify string generation
This commit is contained in:
parent
d202d482d9
commit
b7e493f030
|
@ -40,8 +40,8 @@ void ResumableStateForPopulate::postNextTick() {
|
|||
void ResumableStateForPopulate::runOneTick() {
|
||||
const auto num_commit_every = args.txnspec.ops[OP_INSERT][OP_COUNT];
|
||||
for (auto i = key_checkpoint; i <= key_end; i++) {
|
||||
genKey(keystr, KEY_PREFIX, args, i);
|
||||
randomString(valstr, args.value_length);
|
||||
genKey(keystr.data(), KEY_PREFIX, args, i);
|
||||
randomString(valstr.data(), args.value_length);
|
||||
tx.set(keystr, valstr);
|
||||
stats.incrOpCount(OP_INSERT);
|
||||
if (i == key_end || (i - key_begin + 1) % num_commit_every == 0) {
|
||||
|
|
|
@ -62,8 +62,8 @@ struct ResumableStateForPopulate : std::enable_shared_from_this<ResumableStateFo
|
|||
int key_end)
|
||||
: logr(logr), db(db), tx(tx), io_context(io_context), args(args), stats(stats), stopcount(stopcount),
|
||||
key_begin(key_begin), key_end(key_end), key_checkpoint(key_begin) {
|
||||
keystr.reserve(args.key_length);
|
||||
valstr.reserve(args.value_length);
|
||||
keystr.resize(args.key_length);
|
||||
valstr.resize(args.value_length);
|
||||
}
|
||||
void runOneTick();
|
||||
void postNextTick();
|
||||
|
@ -105,9 +105,9 @@ struct ResumableStateForRunWorkload : std::enable_shared_from_this<ResumableStat
|
|||
OpIterator iter)
|
||||
: logr(logr), db(db), tx(tx), io_context(io_context), args(args), stats(stats), stopcount(stopcount),
|
||||
signal(signal), max_iters(max_iters), iter(iter), needs_commit(false) {
|
||||
key1.reserve(args.key_length);
|
||||
key2.reserve(args.key_length);
|
||||
val.reserve(args.value_length);
|
||||
key1.resize(args.key_length);
|
||||
key2.resize(args.key_length);
|
||||
val.resize(args.value_length);
|
||||
}
|
||||
void signalEnd() noexcept { stopcount.fetch_add(1); }
|
||||
bool ended() noexcept {
|
||||
|
|
|
@ -88,15 +88,21 @@ thread_local Logger logr = Logger(MainProcess{}, VERBOSE_DEFAULT);
|
|||
|
||||
/* cleanup database */
|
||||
int cleanup(Transaction tx, Arguments const& args) {
|
||||
auto beginstr = ByteString{};
|
||||
beginstr.reserve(args.key_length);
|
||||
genKeyPrefix(beginstr, KEY_PREFIX, args);
|
||||
beginstr.push_back(0);
|
||||
|
||||
auto endstr = ByteString{};
|
||||
endstr.reserve(args.key_length);
|
||||
genKeyPrefix(endstr, KEY_PREFIX, args);
|
||||
endstr.push_back(0xff);
|
||||
const auto prefix_len = args.prefixpadding ? args.key_length - args.row_digits : intSize(KEY_PREFIX);
|
||||
auto genprefix = [&args](ByteString& s) {
|
||||
const auto padding_len = args.key_length - intSize(KEY_PREFIX) - args.row_digits;
|
||||
auto pos = 0;
|
||||
if (args.prefixpadding) {
|
||||
memset(s.data(), 'x', padding_len);
|
||||
pos += padding_len;
|
||||
}
|
||||
const auto key_prefix_len = intSize(KEY_PREFIX);
|
||||
memcpy(&s[pos], KEY_PREFIX.data(), key_prefix_len);
|
||||
};
|
||||
auto beginstr = ByteString(prefix_len + 1, '\0');
|
||||
genprefix(beginstr);
|
||||
auto endstr = ByteString(prefix_len + 1, '\xff');
|
||||
genprefix(endstr);
|
||||
|
||||
auto watch = Stopwatch(StartAtCtor{});
|
||||
|
||||
|
@ -133,8 +139,8 @@ int populate(Transaction tx,
|
|||
|
||||
auto keystr = ByteString{};
|
||||
auto valstr = ByteString{};
|
||||
keystr.reserve(args.key_length);
|
||||
valstr.reserve(args.value_length);
|
||||
keystr.resize(args.key_length);
|
||||
valstr.resize(args.value_length);
|
||||
const auto num_commit_every = args.txnspec.ops[OP_INSERT][OP_COUNT];
|
||||
const auto num_seconds_trace_every = args.txntrace;
|
||||
auto watch_total = Stopwatch(StartAtCtor{});
|
||||
|
@ -145,9 +151,9 @@ int populate(Transaction tx,
|
|||
|
||||
for (auto i = key_begin; i <= key_end; i++) {
|
||||
/* sequential keys */
|
||||
genKey(keystr, KEY_PREFIX, args, i);
|
||||
genKey(keystr.data(), KEY_PREFIX, args, i);
|
||||
/* random values */
|
||||
randomString(valstr, args.value_length);
|
||||
randomString(valstr.data(), args.value_length);
|
||||
|
||||
while (thread_tps > 0 && xacts >= thread_tps /* throttle */) {
|
||||
if (toIntegerSeconds(watch_throttle.stop().diff()) >= 1) {
|
||||
|
@ -369,11 +375,11 @@ int runWorkload(Transaction tx,
|
|||
|
||||
// reuse memory for keys to avoid realloc overhead
|
||||
auto key1 = ByteString{};
|
||||
key1.reserve(args.key_length);
|
||||
key1.resize(args.key_length);
|
||||
auto key2 = ByteString{};
|
||||
key2.reserve(args.key_length);
|
||||
key2.resize(args.key_length);
|
||||
auto val = ByteString{};
|
||||
val.reserve(args.value_length);
|
||||
val.resize(args.value_length);
|
||||
|
||||
/* main transaction loop */
|
||||
while (1) {
|
||||
|
|
|
@ -124,7 +124,7 @@ const std::array<Operation, MAX_OP> opTable{
|
|||
} },
|
||||
{ StepKind::IMM,
|
||||
[](Transaction& tx, Arguments const& args, ByteString& key, ByteString&, ByteString& value) {
|
||||
randomString(value, args.value_length);
|
||||
randomString(value.data(), args.value_length);
|
||||
tx.set(key, value);
|
||||
return Future();
|
||||
} } },
|
||||
|
@ -133,10 +133,9 @@ const std::array<Operation, MAX_OP> opTable{
|
|||
{ "INSERT",
|
||||
{ { StepKind::IMM,
|
||||
[](Transaction& tx, Arguments const& args, ByteString& key, ByteString&, ByteString& value) {
|
||||
genKeyPrefix(key, KEY_PREFIX, args);
|
||||
// concat([padding], key_prefix, random_string): reasonably unique
|
||||
randomString<false /*clear-before-append*/>(key, args.key_length - static_cast<int>(key.size()));
|
||||
randomString(value, args.value_length);
|
||||
// key[0..args.key_length] := concat(key_prefix, random_string)
|
||||
randomString(key.data() + intSize(KEY_PREFIX), args.key_length - intSize(KEY_PREFIX));
|
||||
randomString(value.data(), args.value_length);
|
||||
tx.set(key, value);
|
||||
return Future();
|
||||
} } },
|
||||
|
@ -145,20 +144,17 @@ const std::array<Operation, MAX_OP> opTable{
|
|||
{ "INSERTRANGE",
|
||||
{ { StepKind::IMM,
|
||||
[](Transaction& tx, Arguments const& args, ByteString& key, ByteString&, ByteString& value) {
|
||||
genKeyPrefix(key, KEY_PREFIX, args);
|
||||
const auto prefix_len = static_cast<int>(key.size());
|
||||
randomString(value.data(), args.value_length);
|
||||
|
||||
// key[0..args.key_length] := concat(prefix, random_string, num[0..range_digits])
|
||||
const auto range = args.txnspec.ops[OP_INSERTRANGE][OP_RANGE];
|
||||
assert(range > 0);
|
||||
const auto range_digits = digits(range);
|
||||
assert(args.key_length - prefix_len >= range_digits);
|
||||
const auto rand_len = args.key_length - prefix_len - range_digits;
|
||||
// concat([padding], prefix, random_string, range_digits)
|
||||
randomString<false /*clear-before-append*/>(key, rand_len);
|
||||
randomString(value, args.value_length);
|
||||
const auto random_len = args.key_length - intSize(KEY_PREFIX) - range_digits;
|
||||
randomString(&key[intSize(KEY_PREFIX)], random_len);
|
||||
for (auto i = 0; i < range; i++) {
|
||||
fmt::format_to(std::back_inserter(key), "{0:0{1}d}", i, range_digits);
|
||||
numericWithFill(&key[args.key_length - range_digits], range_digits, i);
|
||||
tx.set(key, value);
|
||||
key.resize(key.size() - static_cast<size_t>(range_digits));
|
||||
}
|
||||
return Future();
|
||||
} } },
|
||||
|
@ -167,7 +163,7 @@ const std::array<Operation, MAX_OP> opTable{
|
|||
{ "OVERWRITE",
|
||||
{ { StepKind::IMM,
|
||||
[](Transaction& tx, Arguments const& args, ByteString& key, ByteString&, ByteString& value) {
|
||||
randomString(value, args.value_length);
|
||||
randomString(value.data(), args.value_length);
|
||||
tx.set(key, value);
|
||||
return Future();
|
||||
} } },
|
||||
|
@ -184,10 +180,8 @@ const std::array<Operation, MAX_OP> opTable{
|
|||
{ "SETCLEAR",
|
||||
{ { StepKind::COMMIT,
|
||||
[](Transaction& tx, Arguments const& args, ByteString& key, ByteString&, ByteString& value) {
|
||||
genKeyPrefix(key, KEY_PREFIX, args);
|
||||
const auto prefix_len = static_cast<int>(key.size());
|
||||
randomString<false /*clear-before-append*/>(key, args.key_length - prefix_len);
|
||||
randomString(value, args.value_length);
|
||||
randomString(&key[KEY_PREFIX.size()], args.key_length - intSize(KEY_PREFIX));
|
||||
randomString(value.data(), args.value_length);
|
||||
tx.set(key, value);
|
||||
return tx.commit().eraseType();
|
||||
} },
|
||||
|
@ -210,26 +204,19 @@ const std::array<Operation, MAX_OP> opTable{
|
|||
{ "SETCLEARRANGE",
|
||||
{ { StepKind::COMMIT,
|
||||
[](Transaction& tx, Arguments const& args, ByteString& key_begin, ByteString& key, ByteString& value) {
|
||||
genKeyPrefix(key, KEY_PREFIX, args);
|
||||
const auto prefix_len = static_cast<int>(key.size());
|
||||
const auto range = args.txnspec.ops[OP_SETCLEARRANGE][OP_RANGE];
|
||||
randomString(value.data(), args.value_length);
|
||||
|
||||
// key[0..args.key_length] := concat(prefix, random_string, num[0..range_digits])
|
||||
const auto range = args.txnspec.ops[OP_INSERTRANGE][OP_RANGE];
|
||||
assert(range > 0);
|
||||
const auto range_digits = digits(range);
|
||||
assert(args.key_length - prefix_len >= range_digits);
|
||||
const auto rand_len = args.key_length - prefix_len - range_digits;
|
||||
// concat([padding], prefix, random_string, range_digits)
|
||||
randomString<false /*clear-before-append*/>(key, rand_len);
|
||||
randomString(value, args.value_length);
|
||||
for (auto i = 0; i <= range; i++) {
|
||||
fmt::format_to(std::back_inserter(key), "{0:0{1}d}", i, range_digits);
|
||||
if (i == range)
|
||||
break; // preserve "exclusive last"
|
||||
// preserve first key for step 1
|
||||
if (i == 0)
|
||||
key_begin = key;
|
||||
const auto random_len = args.key_length - intSize(KEY_PREFIX) - range_digits;
|
||||
randomString(&key[KEY_PREFIX.size()], random_len);
|
||||
for (auto i = 0; i < range; i++) {
|
||||
numericWithFill(&key[args.key_length - range_digits], range_digits, i);
|
||||
tx.set(key, value);
|
||||
// preserve last key for step 1
|
||||
key.resize(key.size() - static_cast<size_t>(range_digits));
|
||||
if (i == 0)
|
||||
key_begin.assign(key);
|
||||
}
|
||||
return tx.commit().eraseType();
|
||||
} },
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
@ -48,15 +49,16 @@ force_inline int nextKey(Arguments const& args) {
|
|||
return urand(0, args.rows - 1);
|
||||
}
|
||||
|
||||
force_inline int intSize(std::string_view sv) {
|
||||
return static_cast<int>(sv.size());
|
||||
}
|
||||
|
||||
/* random string */
|
||||
template <bool Clear = true, typename Char>
|
||||
void randomString(std::basic_string<Char>& str, int len) {
|
||||
if constexpr (Clear)
|
||||
str.clear();
|
||||
template <typename Char>
|
||||
void randomString(Char* str, int len) {
|
||||
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' */
|
||||
str[i] = ('!' + urand(0, 'z' - '!')); /* generate a char from '!' to 'z' */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,47 +107,37 @@ int computeThreadPortion(int val, int p_idx, int t_idx, int total_p, int total_t
|
|||
/* get the number of digits */
|
||||
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, Arguments 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());
|
||||
for (auto i = 0; i < padding_len; i++)
|
||||
str.push_back('x');
|
||||
str.append(reinterpret_cast<Char const*>(prefix.data()), prefix.size());
|
||||
/* fill memory slice [str, str + len) as stringified, zero-padded num */
|
||||
template <typename Char>
|
||||
void numericWithFill(Char* str, int len, int num) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
assert(num >= 0);
|
||||
for (auto i = len - 1; i >= 0; i--) {
|
||||
str[i] = (num % 10) + '0';
|
||||
num /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 <typename Char>
|
||||
void genKey(std::basic_string<Char>& str, std::string_view prefix, Arguments const& args, int num) {
|
||||
void genKey(Char* str, std::string_view prefix, Arguments const& args, int num) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
str.clear();
|
||||
str.resize(args.key_length, 'x');
|
||||
memset(str, 'x', args.key_length);
|
||||
const auto prefix_len = static_cast<int>(prefix.size());
|
||||
auto pos = args.prefixpadding ? (args.key_length - prefix_len - args.row_digits) : 0;
|
||||
memcpy(&str[pos], prefix.data(), prefix.size());
|
||||
memcpy(&str[pos], prefix.data(), prefix_len);
|
||||
pos += prefix_len;
|
||||
for (auto i = 0; i < args.row_digits; i++) {
|
||||
str[pos + (args.row_digits - i - 1)] = (num % 10) + '0';
|
||||
num /= 10;
|
||||
}
|
||||
numericWithFill(&str[pos], args.row_digits, num);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void prepareKeys(int op, std::basic_string<Char>& key1, std::basic_string<Char>& key2, Arguments const& args) {
|
||||
const auto key1_num = nextKey(args);
|
||||
genKey(key1, KEY_PREFIX, args, key1_num);
|
||||
genKey(key1.data(), KEY_PREFIX, args, key1_num);
|
||||
if (args.txnspec.ops[op][OP_RANGE] > 0) {
|
||||
const auto key2_num = std::min(key1_num + args.txnspec.ops[op][OP_RANGE] - 1, args.rows - 1);
|
||||
genKey(key2, KEY_PREFIX, args, key2_num);
|
||||
genKey(key2.data(), KEY_PREFIX, args, key2_num);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue