blob: 4a294cbac4c04bdcfcd8679a662c9931897ea9dc [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ledger/bin/testing/page_data_generator.h"
#include <lib/callback/waiter.h>
#include <lib/fit/function.h>
#include <lib/fsl/vmo/strings.h>
#include <memory>
#include "peridot/lib/convert/convert.h"
#include "src/lib/fxl/logging.h"
#include "src/lib/fxl/memory/ref_ptr.h"
namespace ledger {
namespace {
constexpr size_t kMaxInlineDataSize = ZX_CHANNEL_MAX_MSG_BYTES * 9 / 10;
bool LogOnError(Status status, fxl::StringView description) {
if (status != Status::OK) {
FXL_LOG(ERROR) << description << " failed with status "
<< fidl::ToUnderlying(status) << ".";
return true;
}
return false;
}
} // namespace
PageDataGenerator::PageDataGenerator(rng::Random* random)
: generator_(random) {}
void PageDataGenerator::PutEntry(PagePtr* page, std::vector<uint8_t> key,
std::vector<uint8_t> value,
ReferenceStrategy ref_strategy,
Priority priority,
fit::function<void(Status)> callback) {
if (ref_strategy == ReferenceStrategy::INLINE) {
if (value.size() >= kMaxInlineDataSize) {
FXL_LOG(ERROR)
<< "Value too large (" << value.size()
<< ") to be put inline. Consider putting as reference instead.";
callback(Status::IO_ERROR);
return;
}
(*page)->PutWithPriority(std::move(key), std::move(value), priority);
callback(Status::OK);
return;
}
fsl::SizedVmo vmo;
if (!fsl::VmoFromString(convert::ToStringView(value), &vmo)) {
LogOnError(Status::IO_ERROR, "fsl::VmoFromString");
callback(Status::IO_ERROR);
return;
}
(*page)->CreateReferenceFromBuffer(
std::move(vmo).ToTransport(),
[page, key = std::move(key), priority, callback = std::move(callback)](
CreateReferenceStatus status, ReferencePtr reference) mutable {
if (status != CreateReferenceStatus::OK) {
LogOnError(Status::IO_ERROR, "Page::CreateReferenceFromBuffer");
callback(Status::IO_ERROR);
return;
}
(*page)->PutReference(std::move(key), std::move(*reference), priority);
callback(Status::OK);
});
}
void PageDataGenerator::Populate(PagePtr* page,
std::vector<std::vector<uint8_t>> keys,
size_t value_size, size_t transaction_size,
ReferenceStrategy ref_strategy,
Priority priority,
fit::function<void(Status)> callback) {
if (transaction_size == 0) {
PutMultipleEntries(page, std::move(keys), value_size, ref_strategy,
priority, std::move(callback));
return;
}
PutInTransaction(page, std::move(keys), 0, value_size, transaction_size,
ref_strategy, priority, std::move(callback));
}
void PageDataGenerator::PutInTransaction(
PagePtr* page, std::vector<std::vector<uint8_t>> keys,
size_t current_key_index, size_t value_size, size_t transaction_size,
ReferenceStrategy ref_strategy, Priority priority,
fit::function<void(Status)> callback) {
if (current_key_index >= keys.size()) {
(*page)->Sync([callback = std::move(callback)] { callback(Status::OK); });
return;
}
size_t this_transaction_size =
std::min(transaction_size, keys.size() - current_key_index);
std::vector<std::vector<uint8_t>> partial_keys;
std::move(keys.begin() + current_key_index,
keys.begin() + current_key_index + this_transaction_size,
std::back_inserter(partial_keys));
(*page)->StartTransaction();
PutMultipleEntries(
page, std::move(partial_keys), value_size, ref_strategy, priority,
[this, page, keys = std::move(keys), current_key_index, value_size,
ref_strategy, priority, transaction_size,
callback = std::move(callback)](Status status) mutable {
if (LogOnError(status, "PutMultipleEntries")) {
callback(status);
return;
}
(*page)->Commit();
PutInTransaction(page, std::move(keys),
current_key_index + transaction_size, value_size,
transaction_size, ref_strategy, priority,
std::move(callback));
});
}
void PageDataGenerator::PutMultipleEntries(
PagePtr* page, std::vector<std::vector<uint8_t>> keys, size_t value_size,
ReferenceStrategy ref_strategy, Priority priority,
fit::function<void(Status)> callback) {
auto waiter = fxl::MakeRefCounted<callback::StatusWaiter<Status>>(Status::OK);
for (auto& key : keys) {
std::vector<uint8_t> value = generator_.MakeValue(value_size);
PutEntry(page, std::move(key), std::move(value), ref_strategy, priority,
waiter->NewCallback());
}
waiter->Finalize(std::move(callback));
}
} // namespace ledger