From 2b18954cb9e11bc9a0d4b32d3861bfa5a98b0b52 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Sun, 21 Oct 2018 21:22:41 -0700 Subject: [PATCH] `mmap` tarfiles directly when mmapping is enabled --- .../datafacade/mmap_memory_allocator.hpp | 8 +- include/engine/datafacade_provider.hpp | 11 +- include/storage/block.hpp | 11 +- include/storage/serialization.hpp | 17 +- include/storage/shared_data_index.hpp | 20 +-- include/storage/shared_datatype.hpp | 156 +++++++++++++---- include/storage/storage.hpp | 10 +- include/util/mmap_file.hpp | 33 ++-- .../datafacade/mmap_memory_allocator.cpp | 70 ++++---- .../datafacade/process_memory_allocator.cpp | 18 +- .../datafacade/shared_memory_allocator.cpp | 2 +- src/storage/storage.cpp | 163 ++++++++++-------- src/tools/store.cpp | 6 +- unit_tests/storage/data_layout.cpp | 65 +++---- 14 files changed, 359 insertions(+), 231 deletions(-) diff --git a/include/engine/datafacade/mmap_memory_allocator.hpp b/include/engine/datafacade/mmap_memory_allocator.hpp index 4a9742a44..60df71e90 100644 --- a/include/engine/datafacade/mmap_memory_allocator.hpp +++ b/include/engine/datafacade/mmap_memory_allocator.hpp @@ -10,6 +10,7 @@ #include #include +#include namespace osrm { @@ -24,8 +25,7 @@ namespace datafacade class MMapMemoryAllocator : public ContiguousBlockAllocator { public: - explicit MMapMemoryAllocator(const storage::StorageConfig &config, - const boost::filesystem::path &memory_file); + explicit MMapMemoryAllocator(const storage::StorageConfig &config); ~MMapMemoryAllocator() override final; // interface to give access to the datafacades @@ -33,8 +33,8 @@ class MMapMemoryAllocator : public ContiguousBlockAllocator private: storage::SharedDataIndex index; - util::vector_view mapped_memory; - boost::iostreams::mapped_file mapped_memory_file; + std::vector mapped_memory_files; + std::string rtree_filename; }; } // namespace datafacade diff --git a/include/engine/datafacade_provider.hpp b/include/engine/datafacade_provider.hpp index a624ee009..0ad6370f0 100644 --- a/include/engine/datafacade_provider.hpp +++ b/include/engine/datafacade_provider.hpp @@ -32,9 +32,8 @@ class ExternalProvider final : public DataFacadeProvider public: using Facade = typename DataFacadeProvider::Facade; - ExternalProvider(const storage::StorageConfig &config, - const boost::filesystem::path &memory_file) - : facade_factory(std::make_shared(config, memory_file)) + ExternalProvider(const storage::StorageConfig &config) + : facade_factory(std::make_shared(config)) { } @@ -94,7 +93,7 @@ class WatchingProvider : public DataFacadeProvider return watchdog.Get(params); } }; -} +} // namespace detail template using DataFacadeProvider = detail::DataFacadeProvider; @@ -104,7 +103,7 @@ template using ImmutableProvider = detail::ImmutableProvider; template using ExternalProvider = detail::ExternalProvider; -} -} +} // namespace engine +} // namespace osrm #endif diff --git a/include/storage/block.hpp b/include/storage/block.hpp index 47478e5eb..60271f4ea 100644 --- a/include/storage/block.hpp +++ b/include/storage/block.hpp @@ -16,10 +16,15 @@ struct Block { std::uint64_t num_entries; std::uint64_t byte_size; + std::uint64_t offset; - Block() : num_entries(0), byte_size(0) {} + Block() : num_entries(0), byte_size(0), offset(0) {} + Block(std::uint64_t num_entries, std::uint64_t byte_size, std::uint64_t offset) + : num_entries(num_entries), byte_size(byte_size), offset(offset) + { + } Block(std::uint64_t num_entries, std::uint64_t byte_size) - : num_entries(num_entries), byte_size(byte_size) + : num_entries(num_entries), byte_size(byte_size), offset(0) { } }; @@ -29,7 +34,7 @@ using NamedBlock = std::tuple; template Block make_block(uint64_t num_entries) { static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer"); - return Block{num_entries, sizeof(T) * num_entries}; + return Block{num_entries, sizeof(T) * num_entries, 0}; } } } diff --git a/include/storage/serialization.hpp b/include/storage/serialization.hpp index a2554f9be..ccf8e564e 100644 --- a/include/storage/serialization.hpp +++ b/include/storage/serialization.hpp @@ -97,7 +97,7 @@ void writeBoolVector(tar::FileWriter &writer, const std::string &name, const Vec boost::make_function_input_iterator(encode_function, boost::infinite()), number_of_blocks); } -} +} // namespace detail /* All vector formats here use the same on-disk format. * This is important because we want to be able to write from a vector @@ -273,14 +273,17 @@ template void write(io::BufferWriter &writer, const std } } -inline void read(io::BufferReader &reader, DataLayout &layout) { read(reader, layout.blocks); } - -inline void write(io::BufferWriter &writer, const DataLayout &layout) +inline void read(io::BufferReader &reader, std::unique_ptr &layout) { - write(writer, layout.blocks); -} -} + read(reader, layout->blocks); } + +inline void write(io::BufferWriter &writer, const std::unique_ptr &layout) +{ + write(writer, layout->blocks); } +} // namespace serialization +} // namespace storage +} // namespace osrm #endif diff --git a/include/storage/shared_data_index.hpp b/include/storage/shared_data_index.hpp index 94f78182a..baa61c8a8 100644 --- a/include/storage/shared_data_index.hpp +++ b/include/storage/shared_data_index.hpp @@ -20,7 +20,7 @@ class SharedDataIndex struct AllocatedRegion { char *memory_ptr; - DataLayout layout; + std::unique_ptr layout; }; SharedDataIndex() = default; @@ -29,10 +29,10 @@ class SharedDataIndex // Build mapping from block name to region for (auto index : util::irange(0, regions.size())) { - regions[index].layout.List("", - boost::make_function_output_iterator([&](const auto &name) { - block_to_region[name] = index; - })); + regions[index].layout->List("", + boost::make_function_output_iterator([&](const auto &name) { + block_to_region[name] = index; + })); } } @@ -40,32 +40,32 @@ class SharedDataIndex { for (const auto ®ion : regions) { - region.layout.List(name_prefix, out); + region.layout->List(name_prefix, out); } } template auto GetBlockPtr(const std::string &name) const { const auto ®ion = GetBlockRegion(name); - return region.layout.GetBlockPtr(region.memory_ptr, name); + return reinterpret_cast(region.layout->GetBlockPtr(region.memory_ptr, name)); } template auto GetBlockPtr(const std::string &name) { const auto ®ion = GetBlockRegion(name); - return region.layout.GetBlockPtr(region.memory_ptr, name); + return reinterpret_cast(region.layout->GetBlockPtr(region.memory_ptr, name)); } std::size_t GetBlockEntries(const std::string &name) const { const auto ®ion = GetBlockRegion(name); - return region.layout.GetBlockEntries(name); + return region.layout->GetBlockEntries(name); } std::size_t GetBlockSize(const std::string &name) const { const auto ®ion = GetBlockRegion(name); - return region.layout.GetBlockSize(name); + return region.layout->GetBlockSize(name); } private: diff --git a/include/storage/shared_datatype.hpp b/include/storage/shared_datatype.hpp index 926ca1ded..3f8ba449a 100644 --- a/include/storage/shared_datatype.hpp +++ b/include/storage/shared_datatype.hpp @@ -20,12 +20,12 @@ namespace osrm namespace storage { -class DataLayout; +class BaseDataLayout; namespace serialization { -inline void read(io::BufferReader &reader, DataLayout &layout); +inline void read(io::BufferReader &reader, std::unique_ptr &layout); -inline void write(io::BufferWriter &writer, const DataLayout &layout); +inline void write(io::BufferWriter &writer, const std::unique_ptr &layout); } // namespace serialization namespace detail @@ -54,43 +54,20 @@ inline std::string trimName(const std::string &name_prefix, const std::string &n } } // namespace detail -class DataLayout +class BaseDataLayout { public: - DataLayout() : blocks{} {} + virtual ~BaseDataLayout() = default; - inline void SetBlock(const std::string &name, Block block) { blocks[name] = std::move(block); } + virtual inline void SetBlock(const std::string &name, Block block) = 0; - inline uint64_t GetBlockEntries(const std::string &name) const - { - return GetBlock(name).num_entries; - } + virtual inline uint64_t GetBlockEntries(const std::string &name) const = 0; - inline uint64_t GetBlockSize(const std::string &name) const { return GetBlock(name).byte_size; } + virtual inline uint64_t GetBlockSize(const std::string &name) const = 0; - inline bool HasBlock(const std::string &name) const - { - return blocks.find(name) != blocks.end(); - } + virtual inline bool HasBlock(const std::string &name) const = 0; - inline uint64_t GetSizeOfLayout() const - { - uint64_t result = 0; - for (const auto &name_and_block : blocks) - { - result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT; - } - return result; - } - - template inline T *GetBlockPtr(char *shared_memory, const std::string &name) const - { - static_assert(BLOCK_ALIGNMENT % std::alignment_of::value == 0, - "Datatype does not fit alignment constraints."); - - char *ptr = (char *)GetAlignedBlockPtr(shared_memory, name); - return (T *)ptr; - } + virtual inline uint64_t GetSizeOfLayout() const = 0; // Depending on the name prefix this function either lists all blocks with the same prefix // or all entries in the sub-directory. @@ -115,9 +92,59 @@ class DataLayout } } + virtual inline void *GetBlockPtr(char *shared_memory, const std::string &name) const = 0; + + std::map blocks; +}; + +class DataLayout final : public BaseDataLayout +{ + public: + inline void SetBlock(const std::string &name, Block block) override final + { + blocks[name] = std::move(block); + } + + inline uint64_t GetBlockEntries(const std::string &name) const override final + { + return GetBlock(name).num_entries; + } + + inline uint64_t GetBlockSize(const std::string &name) const override final + { + return GetBlock(name).byte_size; + } + + inline bool HasBlock(const std::string &name) const override final + { + return blocks.find(name) != blocks.end(); + } + + inline uint64_t GetSizeOfLayout() const override final + { + uint64_t result = 0; + for (const auto &name_and_block : blocks) + { + result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT; + } + return result; + } + + inline void *GetBlockPtr(char *shared_memory, const std::string &name) const override final + { + // TODO: re-enable this alignment checking somehow + // static_assert(BLOCK_ALIGNMENT % std::alignment_of::value == 0, + // "Datatype does not fit alignment constraints."); + + char *ptr = (char *)GetAlignedBlockPtr(shared_memory, name); + return ptr; + } + private: - friend void serialization::read(io::BufferReader &reader, DataLayout &layout); - friend void serialization::write(io::BufferWriter &writer, const DataLayout &layout); + friend void serialization::read(io::BufferReader &reader, + std::unique_ptr &layout); + friend void serialization::write(io::BufferWriter &writer, + const std::unique_ptr &layout); const Block &GetBlock(const std::string &name) const { @@ -157,7 +184,64 @@ class DataLayout } static constexpr std::size_t BLOCK_ALIGNMENT = 64; - std::map blocks; +}; + +class TarDataLayout final : public BaseDataLayout +{ + public: + inline void SetBlock(const std::string &name, Block block) override final + { + blocks[name] = std::move(block); + } + + inline uint64_t GetBlockEntries(const std::string &name) const override final + { + return GetBlock(name).num_entries; + } + + inline uint64_t GetBlockSize(const std::string &name) const override final + { + return GetBlock(name).byte_size; + } + + inline bool HasBlock(const std::string &name) const override final + { + return blocks.find(name) != blocks.end(); + } + + inline uint64_t GetSizeOfLayout() const override final + { + uint64_t result = 0; + for (const auto &name_and_block : blocks) + { + result += GetBlockSize(name_and_block.first); + } + return result; + } + + inline void *GetBlockPtr(char *memory_ptr, const std::string &name) const override final + { + auto offset = GetBlock(name).offset; + const auto offset_memory = memory_ptr + offset; + return offset_memory; + } + + private: + friend void serialization::read(io::BufferReader &reader, + std::unique_ptr &layout); + friend void serialization::write(io::BufferWriter &writer, + const std::unique_ptr &layout); + + const Block &GetBlock(const std::string &name) const + { + auto iter = blocks.find(name); + if (iter == blocks.end()) + { + throw util::exception("Could not find block " + name); + } + + return iter->second; + } }; struct SharedRegion diff --git a/include/storage/storage.hpp b/include/storage/storage.hpp index 2c8ae02bc..4ad193b5d 100644 --- a/include/storage/storage.hpp +++ b/include/storage/storage.hpp @@ -46,11 +46,15 @@ class Storage Storage(StorageConfig config); int Run(int max_wait, const std::string &name, bool only_metric); - - void PopulateStaticLayout(DataLayout &layout); - void PopulateUpdatableLayout(DataLayout &layout); void PopulateStaticData(const SharedDataIndex &index); void PopulateUpdatableData(const SharedDataIndex &index); + void PopulateLayout(std::unique_ptr &layout, + std::vector> files); + std::string PopulateLayoutWithRTree(std::unique_ptr &layout); + void readBlocks(const boost::filesystem::path &path, + std::unique_ptr &layout); + std::vector> GetUpdatableFiles(); + std::vector> GetStaticFiles(); private: StorageConfig config; diff --git a/include/util/mmap_file.hpp b/include/util/mmap_file.hpp index 46984d948..d55203d72 100644 --- a/include/util/mmap_file.hpp +++ b/include/util/mmap_file.hpp @@ -15,14 +15,14 @@ namespace util namespace detail { -template -util::vector_view mmapFile(const boost::filesystem::path &file, RegionT ®ion) +template +util::vector_view mmapFile(const boost::filesystem::path &file, MmapContainerT &mmap_container) { try { - region.open(file); - std::size_t num_objects = region.size() / sizeof(T); - auto data_ptr = region.data(); + mmap_container.open(file); + std::size_t num_objects = mmap_container.size() / sizeof(T); + auto data_ptr = mmap_container.data(); BOOST_ASSERT(reinterpret_cast(data_ptr) % alignof(T) == 0); return util::vector_view(reinterpret_cast(data_ptr), num_objects); } @@ -34,9 +34,10 @@ util::vector_view mmapFile(const boost::filesystem::path &file, RegionT ®i } } -template -util::vector_view -mmapFile(const boost::filesystem::path &file, RegionT ®ion, const std::size_t size) +template +util::vector_view mmapFile(const boost::filesystem::path &file, + MmapContainerT &mmap_container, + const std::size_t size) { try { @@ -45,10 +46,10 @@ mmapFile(const boost::filesystem::path &file, RegionT ®ion, const std::size_t params.path = file.string(); params.flags = boost::iostreams::mapped_file::readwrite; params.new_file_size = size; - region.open(params); + mmap_container.open(params); std::size_t num_objects = size / sizeof(T); - auto data_ptr = region.data(); + auto data_ptr = mmap_container.data(); BOOST_ASSERT(reinterpret_cast(data_ptr) % alignof(T) == 0); return util::vector_view(reinterpret_cast(data_ptr), num_objects); } @@ -63,24 +64,24 @@ mmapFile(const boost::filesystem::path &file, RegionT ®ion, const std::size_t template util::vector_view mmapFile(const boost::filesystem::path &file, - boost::iostreams::mapped_file_source ®ion) + boost::iostreams::mapped_file_source &mmap_container) { - return detail::mmapFile(file, region); + return detail::mmapFile(file, mmap_container); } template util::vector_view mmapFile(const boost::filesystem::path &file, - boost::iostreams::mapped_file ®ion) + boost::iostreams::mapped_file &mmap_container) { - return detail::mmapFile(file, region); + return detail::mmapFile(file, mmap_container); } template util::vector_view mmapFile(const boost::filesystem::path &file, - boost::iostreams::mapped_file ®ion, + boost::iostreams::mapped_file &mmap_container, std::size_t size) { - return detail::mmapFile(file, region, size); + return detail::mmapFile(file, mmap_container, size); } } } diff --git a/src/engine/datafacade/mmap_memory_allocator.cpp b/src/engine/datafacade/mmap_memory_allocator.cpp index 9b0902fd3..9be59e862 100644 --- a/src/engine/datafacade/mmap_memory_allocator.cpp +++ b/src/engine/datafacade/mmap_memory_allocator.cpp @@ -1,5 +1,6 @@ #include "engine/datafacade/mmap_memory_allocator.hpp" +#include "storage/block.hpp" #include "storage/io.hpp" #include "storage/serialization.hpp" #include "storage/storage.hpp" @@ -16,47 +17,52 @@ namespace engine namespace datafacade { -MMapMemoryAllocator::MMapMemoryAllocator(const storage::StorageConfig &config, - const boost::filesystem::path &memory_file) +MMapMemoryAllocator::MMapMemoryAllocator(const storage::StorageConfig &config) { storage::Storage storage(config); + std::vector allocated_regions; - if (!boost::filesystem::exists(memory_file)) { - storage::DataLayout initial_layout; - storage.PopulateStaticLayout(initial_layout); - storage.PopulateUpdatableLayout(initial_layout); + std::unique_ptr fake_layout = + std::make_unique(); - auto data_size = initial_layout.GetSizeOfLayout(); + // Convert the boost::filesystem::path object into a plain string + // that's stored as a member of this allocator object + rtree_filename = storage.PopulateLayoutWithRTree(fake_layout); - storage::io::BufferWriter writer; - storage::serialization::write(writer, initial_layout); - auto encoded_layout = writer.GetBuffer(); - - auto total_size = data_size + encoded_layout.size(); - - mapped_memory = util::mmapFile(memory_file, mapped_memory_file, total_size); - - std::copy(encoded_layout.begin(), encoded_layout.end(), mapped_memory.data()); - - index = storage::SharedDataIndex( - {{mapped_memory.data() + encoded_layout.size(), std::move(initial_layout)}}); - - storage.PopulateStaticData(index); - storage.PopulateUpdatableData(index); + // Now, we add one more AllocatedRegion, with it's start address as the start + // of the rtree_filename string we've saved. In the fake_layout, we've + // stated that the data is at offset 0, which is where the string starts + // at it's own memory address. + // The syntax &(rtree_filename[0]) gets the memory address of the first char. + // We can't use the convenient `.data()` or `.c_str()` methods, because + // prior to C++17 (which we're not using), those return a `const char *`, + // which isn't compatible with the `char *` that AllocatedRegion expects + // for it's memory_ptr + allocated_regions.push_back({&(rtree_filename[0]), std::move(fake_layout)}); } - else + + std::vector> files = storage.GetStaticFiles(); + std::vector> updatable_files = + storage.GetUpdatableFiles(); + files.insert(files.end(), updatable_files.begin(), updatable_files.end()); + + for (const auto &file : files) { - mapped_memory = util::mmapFile(memory_file, mapped_memory_file); - - storage::DataLayout layout; - storage::io::BufferReader reader(mapped_memory.data(), mapped_memory.size()); - storage::serialization::read(reader, layout); - auto layout_size = reader.GetPosition(); - - index = storage::SharedDataIndex({{mapped_memory.data() + layout_size, std::move(layout)}}); + if (boost::filesystem::exists(file.second)) + { + std::unique_ptr layout = + std::make_unique(); + boost::iostreams::mapped_file mapped_memory_file; + util::mmapFile(file.second, mapped_memory_file); + mapped_memory_files.push_back(std::move(mapped_memory_file)); + storage.readBlocks(file.second, layout); + allocated_regions.push_back({mapped_memory_file.data(), std::move(layout)}); + } } -} + + index = storage::SharedDataIndex{std::move(allocated_regions)}; +} // namespace datafacade MMapMemoryAllocator::~MMapMemoryAllocator() {} diff --git a/src/engine/datafacade/process_memory_allocator.cpp b/src/engine/datafacade/process_memory_allocator.cpp index 4e20ee8b6..8a9b8a846 100644 --- a/src/engine/datafacade/process_memory_allocator.cpp +++ b/src/engine/datafacade/process_memory_allocator.cpp @@ -15,20 +15,26 @@ ProcessMemoryAllocator::ProcessMemoryAllocator(const storage::StorageConfig &con storage::Storage storage(config); // Calculate the layout/size of the memory block - storage::DataLayout layout; - storage.PopulateStaticLayout(layout); - storage.PopulateUpdatableLayout(layout); + std::vector> static_files = storage.GetStaticFiles(); + std::vector> updatable_files = + storage.GetUpdatableFiles(); + std::unique_ptr layout = std::make_unique(); + storage.PopulateLayoutWithRTree(layout); + storage.PopulateLayout(layout, static_files); + storage.PopulateLayout(layout, updatable_files); // Allocate the memory block, then load data from files into it - internal_memory = std::make_unique(layout.GetSizeOfLayout()); + internal_memory = std::make_unique(layout->GetSizeOfLayout()); - index = storage::SharedDataIndex({{internal_memory.get(), std::move(layout)}}); + std::vector regions; + regions.push_back({internal_memory.get(), std::move(layout)}); + index = {std::move(regions)}; storage.PopulateStaticData(index); storage.PopulateUpdatableData(index); } -ProcessMemoryAllocator::~ProcessMemoryAllocator() {} +ProcessMemoryAllocator::~ProcessMemoryAllocator() { /* free(internal_memory) */} const storage::SharedDataIndex &ProcessMemoryAllocator::GetIndex() { return index; } diff --git a/src/engine/datafacade/shared_memory_allocator.cpp b/src/engine/datafacade/shared_memory_allocator.cpp index 610503498..04967f3b1 100644 --- a/src/engine/datafacade/shared_memory_allocator.cpp +++ b/src/engine/datafacade/shared_memory_allocator.cpp @@ -25,7 +25,7 @@ SharedMemoryAllocator::SharedMemoryAllocator( auto mem = storage::makeSharedMemory(shm_key); storage::io::BufferReader reader(reinterpret_cast(mem->Ptr()), mem->Size()); - storage::DataLayout layout; + std::unique_ptr layout = std::make_unique(); storage::serialization::read(reader, layout); auto layout_size = reader.GetPosition(); diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp index 213217425..c1d1908e0 100644 --- a/src/storage/storage.cpp +++ b/src/storage/storage.cpp @@ -44,24 +44,6 @@ namespace { using Monitor = SharedMonitor; -void readBlocks(const boost::filesystem::path &path, DataLayout &layout) -{ - tar::FileReader reader(path, tar::FileReader::VerifyFingerprint); - - std::vector entries; - reader.List(std::back_inserter(entries)); - - for (const auto &entry : entries) - { - const auto name_end = entry.name.rfind(".meta"); - if (name_end == std::string::npos) - { - auto number_of_elements = reader.ReadElementCount64(entry.name); - layout.SetBlock(entry.name, Block{number_of_elements, entry.size}); - } - } -} - struct RegionHandle { std::unique_ptr memory; @@ -69,7 +51,8 @@ struct RegionHandle std::uint16_t shm_key; }; -auto setupRegion(SharedRegionRegister &shared_register, const DataLayout &layout) +auto setupRegion(SharedRegionRegister &shared_register, + const std::unique_ptr &layout) { // This is safe because we have an exclusive lock for all osrm-datastore processes. auto shm_key = shared_register.ReserveKey(); @@ -90,7 +73,7 @@ auto setupRegion(SharedRegionRegister &shared_register, const DataLayout &layout auto encoded_static_layout = writer.GetBuffer(); // Allocate shared memory block - auto regions_size = encoded_static_layout.size() + layout.GetSizeOfLayout(); + auto regions_size = encoded_static_layout.size() + layout->GetSizeOfLayout(); util::Log() << "Data layout has a size of " << encoded_static_layout.size() << " bytes"; util::Log() << "Allocating shared memory of " << regions_size << " bytes"; auto memory = makeSharedMemory(shm_key, regions_size); @@ -182,10 +165,29 @@ bool swapData(Monitor &monitor, return true; } -} +} // namespace Storage::Storage(StorageConfig config_) : config(std::move(config_)) {} +void Storage::readBlocks(const boost::filesystem::path &path, + std::unique_ptr &layout) +{ + tar::FileReader reader(path, tar::FileReader::VerifyFingerprint); + + std::vector entries; + reader.List(std::back_inserter(entries)); + + for (const auto &entry : entries) + { + const auto name_end = entry.name.rfind(".meta"); + if (name_end == std::string::npos) + { + auto number_of_elements = reader.ReadElementCount64(entry.name); + layout->SetBlock(entry.name, Block{number_of_elements, entry.size, entry.offset}); + } + } +} + int Storage::Run(int max_wait, const std::string &dataset_name, bool only_metric) { BOOST_ASSERT_MSG(config.IsValid(), "Invalid storage config"); @@ -243,29 +245,35 @@ int Storage::Run(int max_wait, const std::string &dataset_name, bool only_metric auto static_region = shared_register.GetRegion(region_id); auto static_memory = makeSharedMemory(static_region.shm_key); - DataLayout static_layout; + std::unique_ptr static_layout = + std::make_unique(); io::BufferReader reader(reinterpret_cast(static_memory->Ptr()), static_memory->Size()); serialization::read(reader, static_layout); auto layout_size = reader.GetPosition(); auto *data_ptr = reinterpret_cast(static_memory->Ptr()) + layout_size; - regions.push_back({data_ptr, static_layout}); + regions.push_back({data_ptr, std::move(static_layout)}); readonly_handles.push_back({std::move(static_memory), data_ptr, static_region.shm_key}); } else { - DataLayout static_layout; - PopulateStaticLayout(static_layout); + std::unique_ptr static_layout = + std::make_unique(); + Storage::PopulateLayoutWithRTree(static_layout); + std::vector> files = Storage::GetStaticFiles(); + Storage::PopulateLayout(static_layout, files); auto static_handle = setupRegion(shared_register, static_layout); - regions.push_back({static_handle.data_ptr, static_layout}); + regions.push_back({static_handle.data_ptr, std::move(static_layout)}); handles[dataset_name + "/static"] = std::move(static_handle); } - DataLayout updatable_layout; - PopulateUpdatableLayout(updatable_layout); + std::unique_ptr updatable_layout = + std::make_unique(); + std::vector> files = Storage::GetUpdatableFiles(); + Storage::PopulateLayout(updatable_layout, files); auto updatable_handle = setupRegion(shared_register, updatable_layout); - regions.push_back({updatable_handle.data_ptr, updatable_layout}); + regions.push_back({updatable_handle.data_ptr, std::move(updatable_layout)}); handles[dataset_name + "/updatable"] = std::move(updatable_handle); SharedDataIndex index{std::move(regions)}; @@ -281,24 +289,12 @@ int Storage::Run(int max_wait, const std::string &dataset_name, bool only_metric return EXIT_SUCCESS; } -/** - * This function examines all our data files and figures out how much - * memory needs to be allocated, and the position of each data structure - * in that big block. It updates the fields in the DataLayout parameter. - */ -void Storage::PopulateStaticLayout(DataLayout &static_layout) +std::vector> Storage::GetStaticFiles() { - { - auto absolute_file_index_path = - boost::filesystem::absolute(config.GetPath(".osrm.fileIndex")); - - static_layout.SetBlock("/common/rtree/file_index_path", - make_block(absolute_file_index_path.string().length() + 1)); - } - constexpr bool REQUIRED = true; constexpr bool OPTIONAL = false; - std::vector> tar_files = { + + std::vector> files = { {OPTIONAL, config.GetPath(".osrm.cells")}, {OPTIONAL, config.GetPath(".osrm.partition")}, {REQUIRED, config.GetPath(".osrm.icd")}, @@ -310,53 +306,74 @@ void Storage::PopulateStaticLayout(DataLayout &static_layout) {REQUIRED, config.GetPath(".osrm.maneuver_overrides")}, {REQUIRED, config.GetPath(".osrm.edges")}, {REQUIRED, config.GetPath(".osrm.names")}, - {REQUIRED, config.GetPath(".osrm.ramIndex")}, - }; + {REQUIRED, config.GetPath(".osrm.ramIndex")}}; - for (const auto &file : tar_files) + for (const auto &file : files) { - if (boost::filesystem::exists(file.second)) + if (file.first == REQUIRED && !boost::filesystem::exists(file.second)) { - readBlocks(file.second, static_layout); - } - else - { - if (file.first == REQUIRED) - { - throw util::exception("Could not find required filed: " + - std::get<1>(file).string()); - } + throw util::exception("Could not find required filed: " + std::get<1>(file).string()); } } + + return files; } -void Storage::PopulateUpdatableLayout(DataLayout &updatable_layout) +std::vector> Storage::GetUpdatableFiles() { constexpr bool REQUIRED = true; constexpr bool OPTIONAL = false; - std::vector> tar_files = { + + std::vector> files = { {OPTIONAL, config.GetPath(".osrm.mldgr")}, {OPTIONAL, config.GetPath(".osrm.cell_metrics")}, {OPTIONAL, config.GetPath(".osrm.hsgr")}, {REQUIRED, config.GetPath(".osrm.datasource_names")}, {REQUIRED, config.GetPath(".osrm.geometry")}, {REQUIRED, config.GetPath(".osrm.turn_weight_penalties")}, - {REQUIRED, config.GetPath(".osrm.turn_duration_penalties")}, - }; + {REQUIRED, config.GetPath(".osrm.turn_duration_penalties")}}; - for (const auto &file : tar_files) + for (const auto &file : files) + { + if (file.first == REQUIRED && !boost::filesystem::exists(file.second)) + { + throw util::exception("Could not find required filed: " + std::get<1>(file).string()); + } + } + + return files; +} + +std::string Storage::PopulateLayoutWithRTree(std::unique_ptr &layout) +{ + // Figure out the path to the rtree file (it's not a tar file) + auto absolute_file_index_path = boost::filesystem::absolute(config.GetPath(".osrm.fileIndex")); + + // Convert the boost::filesystem::path object into a plain string + // that can then be stored as a member of an allocator object + std::string rtree_filename = absolute_file_index_path.string(); + + // Here, we hardcode the special file_index_path block name. + // The important bit here is that the "offset" is set to zero + layout->SetBlock("/common/rtree/file_index_path", + make_block(rtree_filename.length() + 1)); + + return rtree_filename; +} + +/** + * This function examines all our data files and figures out how much + * memory needs to be allocated, and the position of each data structure + * in that big block. It updates the fields in the std::unique_ptr parameter. + */ +void Storage::PopulateLayout(std::unique_ptr &layout, + std::vector> files) +{ + for (const auto &file : files) { if (boost::filesystem::exists(file.second)) { - readBlocks(file.second, updatable_layout); - } - else - { - if (file.first == REQUIRED) - { - throw util::exception("Could not find required filed: " + - std::get<1>(file).string()); - } + readBlocks(file.second, layout); } } } @@ -569,5 +586,5 @@ void Storage::PopulateUpdatableData(const SharedDataIndex &index) } } } -} -} +} // namespace storage +} // namespace osrm diff --git a/src/tools/store.cpp b/src/tools/store.cpp index bd21c9b4b..18aa2d298 100644 --- a/src/tools/store.cpp +++ b/src/tools/store.cpp @@ -52,14 +52,14 @@ void listRegions(bool show_blocks) auto memory = makeSharedMemory(region.shm_key); io::BufferReader reader(reinterpret_cast(memory->Ptr()), memory->Size()); - DataLayout layout; + std::unique_ptr layout = std::make_unique(); serialization::read(reader, layout); std::vector block_names; - layout.List("", std::back_inserter(block_names)); + layout->List("", std::back_inserter(block_names)); for (auto &name : block_names) { - osrm::util::Log() << " " << name << " " << layout.GetBlockSize(name); + osrm::util::Log() << " " << name << " " << layout->GetBlockSize(name); } } } diff --git a/unit_tests/storage/data_layout.cpp b/unit_tests/storage/data_layout.cpp index 2aa0b40ee..f8db5d351 100644 --- a/unit_tests/storage/data_layout.cpp +++ b/unit_tests/storage/data_layout.cpp @@ -15,86 +15,89 @@ using namespace osrm::storage; BOOST_AUTO_TEST_CASE(layout_write_test) { - DataLayout layout; + std::unique_ptr layout = std::make_unique(); Block block_1{20, 8 * 20}; Block block_2{1, 4 * 1}; Block block_3{100, static_cast(std::ceil(100 / 64.))}; - layout.SetBlock("block1", block_1); - layout.SetBlock("block2", block_2); - layout.SetBlock("block3", block_3); + layout->SetBlock("block1", block_1); + layout->SetBlock("block2", block_2); + layout->SetBlock("block3", block_3); // Canary and alignment change layout size - BOOST_CHECK_GT(layout.GetSizeOfLayout(), + BOOST_CHECK_GT(layout->GetSizeOfLayout(), block_1.byte_size + block_2.byte_size + block_3.byte_size); - BOOST_CHECK_EQUAL(layout.GetBlockSize("block1"), block_1.byte_size); - BOOST_CHECK_EQUAL(layout.GetBlockSize("block2"), block_2.byte_size); - BOOST_CHECK_EQUAL(layout.GetBlockSize("block3"), block_3.byte_size); + BOOST_CHECK_EQUAL(layout->GetBlockSize("block1"), block_1.byte_size); + BOOST_CHECK_EQUAL(layout->GetBlockSize("block2"), block_2.byte_size); + BOOST_CHECK_EQUAL(layout->GetBlockSize("block3"), block_3.byte_size); - std::vector buffer(layout.GetSizeOfLayout()); + std::vector buffer(layout->GetSizeOfLayout()); auto smallest_addr = buffer.data(); auto biggest_addr = buffer.data() + buffer.size(); { - auto block_1_ptr = layout.GetBlockPtr(buffer.data(), "block1"); - auto block_2_ptr = layout.GetBlockPtr(buffer.data(), "block2"); - auto block_3_ptr = layout.GetBlockPtr(buffer.data(), "block3"); + auto block_1_ptr = + reinterpret_cast(layout->GetBlockPtr(buffer.data(), "block1")); + auto block_2_ptr = + reinterpret_cast(layout->GetBlockPtr(buffer.data(), "block2")); + auto block_3_ptr = + reinterpret_cast(layout->GetBlockPtr(buffer.data(), "block3")); - BOOST_CHECK_LT(reinterpret_cast(smallest_addr), + BOOST_CHECK_LE(reinterpret_cast(smallest_addr), reinterpret_cast(block_1_ptr)); BOOST_CHECK_GT( reinterpret_cast(biggest_addr), - reinterpret_cast(block_1_ptr + layout.GetBlockEntries("block1"))); + reinterpret_cast(block_1_ptr + layout->GetBlockEntries("block1"))); BOOST_CHECK_LT(reinterpret_cast(smallest_addr), reinterpret_cast(block_2_ptr)); BOOST_CHECK_GT( reinterpret_cast(biggest_addr), - reinterpret_cast(block_2_ptr + layout.GetBlockEntries("block2"))); + reinterpret_cast(block_2_ptr + layout->GetBlockEntries("block2"))); BOOST_CHECK_LT(reinterpret_cast(smallest_addr), reinterpret_cast(block_3_ptr)); BOOST_CHECK_GT(reinterpret_cast(biggest_addr), reinterpret_cast( block_3_ptr + static_cast( - std::ceil(layout.GetBlockEntries("block3") / 64)))); + std::ceil(layout->GetBlockEntries("block3") / 64)))); } } BOOST_AUTO_TEST_CASE(layout_list_test) { - DataLayout layout; + std::unique_ptr layout = std::make_unique(); Block block_1{20, 8 * 20}; Block block_2{1, 4 * 1}; Block block_3{100, static_cast(std::ceil(100 / 64.))}; - layout.SetBlock("/ch/edge_filter/block1", block_1); - layout.SetBlock("/ch/edge_filter/block2", block_2); - layout.SetBlock("/ch/edge_filter/block3", block_3); - layout.SetBlock("/mld/metrics/0/durations", block_2); - layout.SetBlock("/mld/metrics/0/weights", block_3); - layout.SetBlock("/mld/metrics/1/durations", block_2); - layout.SetBlock("/mld/metrics/1/weights", block_3); + layout->SetBlock("/ch/edge_filter/block1", block_1); + layout->SetBlock("/ch/edge_filter/block2", block_2); + layout->SetBlock("/ch/edge_filter/block3", block_3); + layout->SetBlock("/mld/metrics/0/durations", block_2); + layout->SetBlock("/mld/metrics/0/weights", block_3); + layout->SetBlock("/mld/metrics/1/durations", block_2); + layout->SetBlock("/mld/metrics/1/weights", block_3); std::vector results_1; std::vector results_2; std::vector results_3; - layout.List("/ch/edge_filter", std::back_inserter(results_1)); - layout.List("/ch/edge_filter/", std::back_inserter(results_2)); - layout.List("/ch/", std::back_inserter(results_3)); + layout->List("/ch/edge_filter", std::back_inserter(results_1)); + layout->List("/ch/edge_filter/", std::back_inserter(results_2)); + layout->List("/ch/", std::back_inserter(results_3)); std::vector results_4; std::vector results_5; std::vector results_6; - layout.List("/mld/metrics", std::back_inserter(results_4)); - layout.List("/mld/metrics/", std::back_inserter(results_5)); - layout.List("/mld/", std::back_inserter(results_6)); + layout->List("/mld/metrics", std::back_inserter(results_4)); + layout->List("/mld/metrics/", std::back_inserter(results_5)); + layout->List("/mld/", std::back_inserter(results_6)); std::vector results_7; - layout.List("", std::back_inserter(results_7)); + layout->List("", std::back_inserter(results_7)); BOOST_CHECK_EQUAL(results_7.size(), 7); CHECK_EQUAL_RANGE(