Skip to content

Commit 51dd6d1

Browse files
authored
feat: allow non-ascii values in dfly_bench (#4751)
binary strings are supported by RESP protocol so we now generate commands using this protocol, so that we could pass binary strings. In addition, fixed "done" metric which did not account for number of shards cluster mode. Signed-off-by: Roman Gershman <[email protected]>
1 parent 59a8c36 commit 51dd6d1

File tree

1 file changed

+65
-49
lines changed

1 file changed

+65
-49
lines changed

src/server/dfly_bench.cc

Lines changed: 65 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ ABSL_FLAG(bool, noreply, false, "If true, does not wait for replies. Relevant on
6161
ABSL_FLAG(bool, greet, true,
6262
"If true, sends a greeting command on each connection, "
6363
"to make sure the connection succeeded");
64+
ABSL_FLAG(bool, ascii, true, "If true, use ascii characters for values");
6465

6566
using namespace std;
6667
using namespace util;
@@ -82,9 +83,7 @@ enum Protocol { RESP, MC_TEXT } protocol;
8283
enum DistType { UNIFORM, NORMAL, ZIPFIAN, SEQUENTIAL } dist_type{UNIFORM};
8384
constexpr uint16_t kNumSlots = 16384;
8485

85-
string_view kTmplPatterns[] = {"__key__"sv, "__data__"sv, "__score__"sv};
86-
87-
static string GetRandomHex(size_t len) {
86+
static string GetRandomHex(size_t len, bool ascii) {
8887
std::string res(len, '\0');
8988
size_t indx = 0;
9089

@@ -103,6 +102,11 @@ static string GetRandomHex(size_t len) {
103102
}
104103
}
105104

105+
if (!ascii) {
106+
for (size_t i = 0; i < len; i++) {
107+
res[i] += 80;
108+
}
109+
}
106110
return res;
107111
}
108112

@@ -154,21 +158,24 @@ class CommandGenerator {
154158

155159
string FillSet(string_view key);
156160
string FillGet(string_view key);
157-
void AddTemplateIndices(string_view pattern, TemplateType t);
158161

159162
KeyGenerator* keygen_;
160163
uint32_t ratio_set_ = 0, ratio_get_ = 0;
161164
string command_;
162165

163-
vector<pair<size_t, TemplateType>> key_indices_;
166+
using CmdPart = variant<string_view, TemplateType>;
167+
vector<CmdPart> cmd_parts_;
168+
164169
string value_;
165170
bool might_hit_ = false;
166171
bool noreply_ = false;
172+
bool is_ascii_ = true;
167173
};
168174

169175
CommandGenerator::CommandGenerator(KeyGenerator* keygen) : keygen_(keygen) {
170176
command_ = GetFlag(FLAGS_command);
171-
value_ = string(GetFlag(FLAGS_d), 'a');
177+
is_ascii_ = GetFlag(FLAGS_ascii);
178+
value_ = string(GetFlag(FLAGS_d), is_ascii_ ? 'a' : char(130));
172179

173180
if (command_.empty()) {
174181
pair<string, string> ratio_str = absl::StrSplit(GetFlag(FLAGS_ratio), ':');
@@ -177,12 +184,24 @@ CommandGenerator::CommandGenerator(KeyGenerator* keygen) : keygen_(keygen) {
177184
return;
178185
}
179186

180-
AddTemplateIndices(kTmplPatterns[KEY], KEY);
181-
AddTemplateIndices(kTmplPatterns[VALUE], VALUE);
182-
AddTemplateIndices(kTmplPatterns[SCORE], SCORE);
183-
sort(key_indices_.begin(), key_indices_.end());
184-
if (absl::StartsWithIgnoreCase(command_, "get") || absl::StartsWithIgnoreCase(command_, "mget")) {
185-
might_hit_ = true;
187+
vector<string_view> parts = absl::StrSplit(command_, ' ', absl::SkipEmpty());
188+
for (string_view p : parts) {
189+
if (p == "__key__"sv) {
190+
cmd_parts_.emplace_back(KEY);
191+
} else if (p == "__data__"sv) {
192+
cmd_parts_.emplace_back(VALUE);
193+
} else if (p == "__score__"sv) {
194+
cmd_parts_.emplace_back(SCORE);
195+
} else {
196+
cmd_parts_.emplace_back(p);
197+
}
198+
}
199+
200+
if (!cmd_parts_.empty()) {
201+
const string_view* cmd = get_if<string_view>(&cmd_parts_.front());
202+
if (cmd) {
203+
might_hit_ = absl::EqualsIgnoreCase(*cmd, "get") || absl::StartsWithIgnoreCase(*cmd, "mget");
204+
}
186205
}
187206
}
188207

@@ -204,58 +223,54 @@ string CommandGenerator::Next(SlotRange range) {
204223
return FillGet(key);
205224
}
206225

207-
size_t last_pos = 0;
208-
const size_t kPatLen[] = {kTmplPatterns[KEY].size(), kTmplPatterns[VALUE].size(),
209-
kTmplPatterns[SCORE].size()};
210226
string str, gen_cmd;
211-
for (auto [pos, type] : key_indices_) {
212-
switch (type) {
213-
case KEY:
214-
str = (*keygen_)(slot_id);
215-
break;
216-
case VALUE:
217-
str = GetRandomHex(value_.size());
218-
break;
219-
case SCORE: {
220-
uniform_real_distribution<double> uniform(0, 1);
221-
str = absl::StrCat(uniform(bit_gen));
227+
absl::StrAppend(&gen_cmd, "*", cmd_parts_.size(), "\r\n");
228+
for (const CmdPart& part : cmd_parts_) {
229+
if (auto p = get_if<string_view>(&part)) {
230+
absl::StrAppend(&gen_cmd, "$", p->size(), "\r\n", *p, "\r\n");
231+
} else {
232+
switch (get<TemplateType>(part)) {
233+
case KEY:
234+
str = (*keygen_)(slot_id);
235+
break;
236+
case VALUE:
237+
str = GetRandomHex(value_.size(), is_ascii_);
238+
break;
239+
case SCORE: {
240+
uniform_real_distribution<double> uniform(0, 1);
241+
str = absl::StrCat(uniform(bit_gen));
242+
}
222243
}
244+
absl::StrAppend(&gen_cmd, "$", str.size(), "\r\n", str, "\r\n");
223245
}
224-
absl::StrAppend(&gen_cmd, command_.substr(last_pos, pos - last_pos), str);
225-
last_pos = pos + kPatLen[type];
226246
}
227-
absl::StrAppend(&gen_cmd, command_.substr(last_pos), "\r\n");
228247

229248
return gen_cmd;
230249
}
231250

232251
string CommandGenerator::FillSet(string_view key) {
252+
string res;
253+
233254
if (protocol == RESP) {
234-
return absl::StrCat("set ", key, " ", value_, "\r\n");
235-
}
255+
absl::StrAppend(&res, "*3\r\n$3\r\nset\r\n$", key.size(), "\r\n", key);
256+
absl::StrAppend(&res, "\r\n$", value_.size(), "\r\n", value_, "\r\n");
257+
} else {
258+
DCHECK_EQ(protocol, MC_TEXT);
259+
absl::StrAppend(&res, "set ", key, " 0 0 ", value_.size());
260+
if (GetFlag(FLAGS_noreply)) {
261+
absl::StrAppend(&res, " noreply");
262+
noreply_ = true;
263+
}
236264

237-
DCHECK_EQ(protocol, MC_TEXT);
238-
string res;
239-
absl::StrAppend(&res, "set ", key, " 0 0 ", value_.size());
240-
if (GetFlag(FLAGS_noreply)) {
241-
absl::StrAppend(&res, " noreply");
242-
noreply_ = true;
265+
absl::StrAppend(&res, "\r\n", value_, "\r\n");
243266
}
244-
245-
absl::StrAppend(&res, "\r\n", value_, "\r\n");
246267
return res;
247268
}
248269

249270
string CommandGenerator::FillGet(string_view key) {
250271
return absl::StrCat("get ", key, "\r\n");
251272
}
252273

253-
void CommandGenerator::AddTemplateIndices(string_view pattern, TemplateType t) {
254-
for (size_t pos = 0; (pos = command_.find(pattern, pos)) != string::npos; pos += pattern.size()) {
255-
key_indices_.emplace_back(pos, t);
256-
}
257-
}
258-
259274
struct ClientStats {
260275
base::Histogram hist;
261276

@@ -766,16 +781,16 @@ void TLocalClient::AdjustCycle() {
766781

767782
thread_local unique_ptr<TLocalClient> client;
768783

769-
void WatchFiber(atomic_bool* finish_signal, ProactorPool* pp) {
784+
void WatchFiber(size_t num_shards, atomic_bool* finish_signal, ProactorPool* pp) {
770785
fb2::Mutex mutex;
771786

772787
int64_t start_time = absl::GetCurrentTimeNanos();
773788
LOG(INFO) << "Started watching";
774789

775790
int64_t last_print = start_time;
776791
uint64_t num_last_resp_cnt = 0;
777-
778-
uint64_t resp_goal = GetFlag(FLAGS_c) * pp->size() * GetFlag(FLAGS_n);
792+
num_shards = max<size_t>(num_shards, 1u);
793+
uint64_t resp_goal = GetFlag(FLAGS_c) * pp->size() * GetFlag(FLAGS_n) * num_shards;
779794
uint32_t time_limit = GetFlag(FLAGS_test_time);
780795

781796
while (*finish_signal == false) {
@@ -1007,7 +1022,8 @@ int main(int argc, char* argv[]) {
10071022
client->Start(key_minimum + index * thread_key_step, key_max, interval);
10081023
});
10091024

1010-
auto watch_fb = pp->GetNextProactor()->LaunchFiber([&] { WatchFiber(&finish, pp.get()); });
1025+
auto watch_fb =
1026+
pp->GetNextProactor()->LaunchFiber([&] { WatchFiber(shards.size(), &finish, pp.get()); });
10111027
const absl::Time start_time = absl::Now();
10121028

10131029
// The actual run.

0 commit comments

Comments
 (0)