From 8a0b8d3b0fcde046810eba5373649616c88d44da Mon Sep 17 00:00:00 2001 From: Maksim Denisov Date: Mon, 11 Mar 2024 14:32:20 +0100 Subject: LargeObjectUtils: Randomize large files and directories for testing purposes --- test/utils/large_objects/large_object_utils.cpp | 152 ++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 test/utils/large_objects/large_object_utils.cpp (limited to 'test/utils/large_objects/large_object_utils.cpp') diff --git a/test/utils/large_objects/large_object_utils.cpp b/test/utils/large_objects/large_object_utils.cpp new file mode 100644 index 00000000..b7bcebdc --- /dev/null +++ b/test/utils/large_objects/large_object_utils.cpp @@ -0,0 +1,152 @@ +// Copyright 2024 Huawei Cloud Computing Technology Co., Ltd. +// +// 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 "test/utils/large_objects/large_object_utils.hpp" + +#include +#include +#include +#include +#include + +#include "src/buildtool/file_system/file_system_manager.hpp" +#include "src/utils/cpp/gsl.hpp" + +namespace { +class Randomizer final { + public: + Randomizer(std::uint64_t min, std::uint64_t max) noexcept + : range_(std::random_device{}()), distribution_(min, max) {} + + [[nodiscard]] inline auto Get() noexcept -> uint64_t { + return distribution_(range_); + } + + private: + std::mt19937_64 range_; + std::uniform_int_distribution distribution_; +}; + +/// \brief Create a number of chunks of the predefined size. +/// \tparam UChunkLength Length of each chunk. +/// \tparam USize Number of chunks. +template +class ChunkPool final { + public: + [[nodiscard]] static auto Instance() noexcept + -> ChunkPool const& { + static ChunkPool pool; + return pool; + } + + [[nodiscard]] auto operator[](size_t index) const noexcept + -> std::string const& { + return gsl::at(pool_, static_cast(index)); + } + + private: + std::array pool_; + + explicit ChunkPool() noexcept { + // Starts from 1 to exclude '\0' from randomization + Randomizer randomizer{1, std::numeric_limits::max()}; + + for (size_t i = 0; i < pool_.size(); ++i) { + auto& chunk = gsl::at(pool_, static_cast(i)); + chunk.resize(kChunkLength); + for (size_t j = 0; j < kChunkLength; ++j) { + chunk[j] = randomizer.Get(); + } + } + } +}; +} // namespace + +auto LargeObjectUtils::GenerateFile(std::filesystem::path const& path, + std::uintmax_t size) noexcept -> bool { + // Remove the file, if exists: + if (not FileSystemManager::RemoveFile(path)) { + return false; + } + + static constexpr size_t kChunkLength = 128; + static constexpr size_t kPoolSize = 64; + using Pool = ChunkPool; + + // To create a random file, the initial chunk position and the shift are + // randomized: + Randomizer randomizer{std::numeric_limits::min(), + std::numeric_limits::max()}; + const size_t pool_index = randomizer.Get() % kPoolSize; + const size_t pool_shift = randomizer.Get() % 10; + const size_t step_count = size / kChunkLength + 1; + + try { + std::ofstream stream(path); + for (size_t i = 0; i < step_count && stream.good(); ++i) { + const size_t index = (pool_index + i * pool_shift) % kPoolSize; + if (i != step_count - 1) { + stream << Pool::Instance()[index]; + } + else { + auto count = std::min(size - kChunkLength * i, kChunkLength); + stream << Pool::Instance()[index].substr(0, count); + } + } + if (not stream.good()) { + return false; + } + stream.close(); + } catch (...) { + return false; + } + return true; +} + +auto LargeObjectUtils::GenerateDirectory(std::filesystem::path const& path, + std::uintmax_t entries_count) noexcept + -> bool { + // Recreate the directory: + if (not FileSystemManager::RemoveDirectory(path) or + not FileSystemManager::CreateDirectory(path)) { + return false; + } + + Randomizer randomizer{std::numeric_limits::min(), + std::numeric_limits::max()}; + + std::uintmax_t entries = 0; + while (entries < entries_count) { + // Randomize the number for a file: + auto const random_number = randomizer.Get(); + auto const file_name = + std::string(kTreeEntryPrefix) + std::to_string(random_number); + std::filesystem::path const file_path = path / file_name; + + // Check file uniqueness: + if (FileSystemManager::IsFile(file_path)) { + continue; + } + + try { + std::ofstream stream(file_path); + stream << random_number; + stream.close(); + } catch (...) { + return false; + } + ++entries; + } + return true; +} -- cgit v1.2.3