foundationdb/fdbserver/workloads/GetRangeStream.cpp

132 lines
4.0 KiB
C++

/*
* GetRangeStream.cpp
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2026 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fdbclient/NativeAPI.actor.h"
#include "fdbserver/core/TesterInterface.h"
#include "fdbserver/tester/workloads.h"
#include "BulkSetup.h"
struct GetRangeStream : TestWorkload {
static constexpr auto NAME = "GetRangeStream";
PerfIntCounter bytesRead;
bool useGetRange;
Key begin;
Key end;
bool printKVPairs;
explicit GetRangeStream(WorkloadContext const& wcx) : TestWorkload(wcx), bytesRead("BytesRead") {
useGetRange = getOption(options, "useGetRange"_sr, false);
begin = getOption(options, "begin"_sr, normalKeys.begin);
end = getOption(options, "end"_sr, normalKeys.end);
printKVPairs = getOption(options, "printKVPairs"_sr, false);
}
Future<Void> setup(Database const& cx) override { return Void(); }
Future<Void> start(Database const& cx) override {
return clientId != 0 ? Void() : useGetRange ? fdbClientGetRange(cx) : fdbClientStream(cx);
}
Future<bool> check(Database const& cx) override { return true; }
void getMetrics(std::vector<PerfMetric>& m) override { m.push_back(bytesRead.getMetric()); }
Future<Void> logThroughput(Key* next) {
while (true) {
int64_t last = bytesRead.getValue();
double before = g_network->now();
co_await delay(1);
double after = g_network->now();
if (after > before) {
printf("throughput: %g bytes/s, next: %s\n",
(bytesRead.getValue() - last) / (after - before),
printable(*next).c_str());
}
}
}
Future<Void> fdbClientGetRange(Database db) {
Transaction tx(db);
Key next = begin;
Future<Void> logFuture = logThroughput(&next);
while (true) {
Error err;
try {
Standalone<RangeResultRef> range = co_await tx.getRange(
KeySelector(firstGreaterOrEqual(next), next.arena()),
KeySelector(firstGreaterOrEqual(end)),
GetRangeLimits(GetRangeLimits::ROW_LIMIT_UNLIMITED, CLIENT_KNOBS->REPLY_BYTE_LIMIT));
for (const auto& [k, v] : range) {
if (printKVPairs) {
printf("%s -> %s\n", printable(k).c_str(), printable(v).c_str());
}
bytesRead += k.size() + v.size();
}
if (!range.more) {
break;
}
next = keyAfter(range.back().key);
} catch (Error& e) {
err = e;
}
co_await tx.onError(err);
}
}
Future<Void> fdbClientStream(Database db) {
Transaction tx(db);
Key next = begin;
Future<Void> logFuture = logThroughput(&next);
while (true) {
PromiseStream<Standalone<RangeResultRef>> results;
Error err;
try {
Future<Void> stream = tx.getRangeStream(results,
KeySelector(firstGreaterOrEqual(next), next.arena()),
KeySelector(firstGreaterOrEqual(end)),
GetRangeLimits());
while (true) {
Standalone<RangeResultRef> range = co_await results.getFuture();
for (const auto& [k, v] : range) {
if (printKVPairs) {
printf("%s -> %s\n", printable(k).c_str(), printable(v).c_str());
}
bytesRead += k.size() + v.size();
}
if (!range.empty()) {
next = keyAfter(range.back().key);
}
}
} catch (Error& e) {
err = e;
}
if (!err.isValid()) {
continue;
}
if (err.code() == error_code_end_of_stream) {
break;
}
co_await tx.onError(err);
}
}
};
WorkloadFactory<GetRangeStream> GetRangeStreamWorkloadFactory;