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..0f1441f6a 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)) { } 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 78185f9ed..97cba94ef 100644 --- a/include/storage/serialization.hpp +++ b/include/storage/serialization.hpp @@ -284,9 +284,9 @@ template void write(io::BufferWriter &writer, const std } } -inline void read(io::BufferReader &reader, DataLayout &layout) { read(reader, layout.blocks); } +inline void read(io::BufferReader &reader, BaseDataLayout &layout) { read(reader, layout.blocks); } -inline void write(io::BufferWriter &writer, const DataLayout &layout) +inline void write(io::BufferWriter &writer, const BaseDataLayout &layout) { write(writer, layout.blocks); } diff --git a/include/storage/shared_data_index.hpp b/include/storage/shared_data_index.hpp index 94f78182a..9041bc100 100644 --- a/include/storage/shared_data_index.hpp +++ b/include/storage/shared_data_index.hpp @@ -5,6 +5,7 @@ #include +#include #include namespace osrm @@ -19,8 +20,8 @@ class SharedDataIndex public: struct AllocatedRegion { - char *memory_ptr; - DataLayout layout; + void *memory_ptr; + std::unique_ptr layout; }; SharedDataIndex() = default; @@ -29,10 +30,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 +41,44 @@ 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 { +#if !defined(__GNUC__) || (__GNUC__ > 4) + // is_tivially_copyable only exists in GCC >=5 + static_assert(std::is_trivially_copyable::value, + "Block-based data must be a trivially copyable type"); + static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer"); +#endif 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) { +#if !defined(__GNUC__) || (__GNUC__ > 4) + // is_tivially_copyable only exists in GCC >=5 + static_assert(std::is_trivially_copyable::value, + "Block-based data must be a trivially copyable type"); + static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer"); +#endif 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..65addcffc 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, BaseDataLayout &layout); -inline void write(io::BufferWriter &writer, const DataLayout &layout); +inline void write(io::BufferWriter &writer, const BaseDataLayout &layout); } // namespace serialization namespace detail @@ -54,44 +54,28 @@ 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); } - inline uint64_t GetBlockEntries(const std::string &name) const + inline std::uint64_t GetBlockEntries(const std::string &name) const { return GetBlock(name).num_entries; } - inline uint64_t GetBlockSize(const std::string &name) const { return GetBlock(name).byte_size; } + inline std::uint64_t GetBlockSize(const std::string &name) const + { + return GetBlock(name).byte_size; + } inline bool HasBlock(const std::string &name) const { return blocks.find(name) != blocks.end(); } - 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; - } - // Depending on the name prefix this function either lists all blocks with the same prefix // or all entries in the sub-directory. // '/ch/edge' -> '/ch/edge_filter/0/blocks', '/ch/edge_filter/1/blocks' @@ -115,10 +99,10 @@ class DataLayout } } - private: - friend void serialization::read(io::BufferReader &reader, DataLayout &layout); - friend void serialization::write(io::BufferWriter &writer, const DataLayout &layout); + virtual inline void *GetBlockPtr(void *base_ptr, const std::string &name) const = 0; + virtual inline std::uint64_t GetSizeOfLayout() const = 0; + protected: const Block &GetBlock(const std::string &name) const { auto iter = blocks.find(name); @@ -130,10 +114,42 @@ class DataLayout return iter->second; } + friend void serialization::read(io::BufferReader &reader, BaseDataLayout &layout); + friend void serialization::write(io::BufferWriter &writer, const BaseDataLayout &layout); + + std::map blocks; +}; + +class ContiguousDataLayout final : public BaseDataLayout +{ + public: + inline std::uint64_t GetSizeOfLayout() const override final + { + std::uint64_t result = 0; + for (const auto &name_and_block : blocks) + { + result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT; + } + return result; + } + + inline void *GetBlockPtr(void *base_ptr, 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."); + + return GetAlignedBlockPtr(base_ptr, name); + } + + private: + friend void serialization::read(io::BufferReader &reader, BaseDataLayout &layout); + friend void serialization::write(io::BufferWriter &writer, const BaseDataLayout &layout); + // Fit aligned storage in buffer to 64 bytes to conform with AVX 512 types inline void *align(void *&ptr) const noexcept { - const auto intptr = reinterpret_cast(ptr); + const auto intptr = reinterpret_cast(ptr); const auto aligned = (intptr - 1u + BLOCK_ALIGNMENT) & -BLOCK_ALIGNMENT; return ptr = reinterpret_cast(aligned); } @@ -157,7 +173,27 @@ class DataLayout } static constexpr std::size_t BLOCK_ALIGNMENT = 64; - std::map blocks; +}; + +class TarDataLayout final : public BaseDataLayout +{ + public: + inline std::uint64_t GetSizeOfLayout() const override final + { + std::uint64_t result = 0; + for (const auto &name_and_block : blocks) + { + result += GetBlockSize(name_and_block.first); + } + return result; + } + + inline void *GetBlockPtr(void *base_ptr, const std::string &name) const override final + { + auto offset = GetBlock(name).offset; + const auto offset_address = reinterpret_cast(base_ptr) + offset; + return reinterpret_cast(offset_address); + } }; struct SharedRegion diff --git a/include/storage/storage.hpp b/include/storage/storage.hpp index 2c8ae02bc..b03669db0 100644 --- a/include/storage/storage.hpp +++ b/include/storage/storage.hpp @@ -35,22 +35,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include namespace osrm { namespace storage { + +void populateLayoutFromFile(const boost::filesystem::path &path, storage::BaseDataLayout &layout); + class Storage { public: 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(storage::BaseDataLayout &layout, + const std::vector> &files); + std::string PopulateLayoutWithRTree(storage::BaseDataLayout &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..fd87cc42a 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" @@ -7,7 +8,7 @@ #include "util/log.hpp" #include "util/mmap_file.hpp" -#include "boost/assert.hpp" +#include namespace osrm { @@ -16,46 +17,50 @@ 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 + + auto files = storage.GetStaticFiles(); + auto 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::populateLayoutFromFile(file.second, *layout); + allocated_regions.push_back({mapped_memory_file.data(), std::move(layout)}); + } } + + index = storage::SharedDataIndex{std::move(allocated_regions)}; } MMapMemoryAllocator::~MMapMemoryAllocator() {} diff --git a/src/engine/datafacade/process_memory_allocator.cpp b/src/engine/datafacade/process_memory_allocator.cpp index 4e20ee8b6..ed07d669f 100644 --- a/src/engine/datafacade/process_memory_allocator.cpp +++ b/src/engine/datafacade/process_memory_allocator.cpp @@ -15,14 +15,20 @@ 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); + auto static_files = storage.GetStaticFiles(); + auto 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); diff --git a/src/engine/datafacade/shared_memory_allocator.cpp b/src/engine/datafacade/shared_memory_allocator.cpp index 610503498..d90302bf9 100644 --- a/src/engine/datafacade/shared_memory_allocator.cpp +++ b/src/engine/datafacade/shared_memory_allocator.cpp @@ -25,8 +25,9 @@ SharedMemoryAllocator::SharedMemoryAllocator( auto mem = storage::makeSharedMemory(shm_key); storage::io::BufferReader reader(reinterpret_cast(mem->Ptr()), mem->Size()); - storage::DataLayout layout; - storage::serialization::read(reader, layout); + std::unique_ptr layout = + std::make_unique(); + storage::serialization::read(reader, *layout); auto layout_size = reader.GetPosition(); regions.push_back({reinterpret_cast(mem->Ptr()) + layout_size, std::move(layout)}); diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp index 213217425..503b1c10e 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) +RegionHandle setupRegion(SharedRegionRegister &shared_register, + const storage::BaseDataLayout &layout) { // This is safe because we have an exclusive lock for all osrm-datastore processes. auto shm_key = shared_register.ReserveKey(); @@ -184,6 +167,24 @@ bool swapData(Monitor &monitor, } } +void populateLayoutFromFile(const boost::filesystem::path &path, storage::BaseDataLayout &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}); + } + } +} + Storage::Storage(StorageConfig config_) : config(std::move(config_)) {} int Storage::Run(int max_wait, const std::string &dataset_name, bool only_metric) @@ -243,29 +244,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); + 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); - auto static_handle = setupRegion(shared_register, static_layout); - regions.push_back({static_handle.data_ptr, 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, std::move(static_layout)}); handles[dataset_name + "/static"] = std::move(static_handle); } - DataLayout updatable_layout; - PopulateUpdatableLayout(updatable_layout); - auto updatable_handle = setupRegion(shared_register, updatable_layout); - regions.push_back({updatable_handle.data_ptr, 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, std::move(updatable_layout)}); handles[dataset_name + "/updatable"] = std::move(updatable_handle); SharedDataIndex index{std::move(regions)}; @@ -281,24 +288,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 +305,73 @@ 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(storage::BaseDataLayout &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 + auto 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 layout parameter. + */ +void Storage::PopulateLayout(storage::BaseDataLayout &layout, + const 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()); - } + populateLayoutFromFile(file.second, layout); } } } diff --git a/src/tools/store.cpp b/src/tools/store.cpp index bd21c9b4b..533f0d010 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; - serialization::read(reader, 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..b9ef8e8ba 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(