| // 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 |