Skip to content

Commit

Permalink
Add mmap allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMarex committed Feb 13, 2018
1 parent 342da81 commit 93718b5
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 2 deletions.
44 changes: 44 additions & 0 deletions include/engine/datafacade/mmap_memory_allocator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef OSRM_ENGINE_DATAFACADE_MMAP_MEMORY_ALLOCATOR_HPP_
#define OSRM_ENGINE_DATAFACADE_MMAP_MEMORY_ALLOCATOR_HPP_

#include "engine/datafacade/contiguous_block_allocator.hpp"

#include "storage/storage_config.hpp"

#include "util/vector_view.hpp"

#include <boost/iostreams/device/mapped_file.hpp>

#include <memory>

namespace osrm
{
namespace engine
{
namespace datafacade
{

/**
* This allocator uses file backed mmap memory block as the data location.
*/
class MMapMemoryAllocator : public ContiguousBlockAllocator
{
public:
explicit MMapMemoryAllocator(const storage::StorageConfig &config, const boost::filesystem::path &memory_file);
~MMapMemoryAllocator() override final;

// interface to give access to the datafacades
storage::DataLayout &GetLayout() override final;
char *GetMemory() override final;

private:
storage::DataLayout *data_layout;
util::vector_view<char> mapped_memory;
boost::iostreams::mapped_file mapped_memory_file;
};

} // namespace datafacade
} // namespace engine
} // namespace osrm

#endif // OSRM_ENGINE_DATAFACADE_SHARED_MEMORY_ALLOCATOR_HPP_
27 changes: 27 additions & 0 deletions include/engine/datafacade_provider.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "engine/datafacade.hpp"
#include "engine/datafacade/contiguous_internalmem_datafacade.hpp"
#include "engine/datafacade/process_memory_allocator.hpp"
#include "engine/datafacade/mmap_memory_allocator.hpp"
#include "engine/datafacade_factory.hpp"

namespace osrm
Expand All @@ -25,6 +26,30 @@ template <typename AlgorithmT, template <typename A> class FacadeT> class DataFa
virtual std::shared_ptr<const Facade> Get(const api::TileParameters &) const = 0;
};

template <typename AlgorithmT, template <typename A> class FacadeT>
class ExternalProvider final : public DataFacadeProvider<AlgorithmT, FacadeT>
{
public:
using Facade = typename DataFacadeProvider<AlgorithmT, FacadeT>::Facade;

ExternalProvider(const storage::StorageConfig &config, const boost::filesystem::path &memory_file)
: facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config, memory_file))
{
}

std::shared_ptr<const Facade> Get(const api::TileParameters &params) const override final
{
return facade_factory.Get(params);
}
std::shared_ptr<const Facade> Get(const api::BaseParameters &params) const override final
{
return facade_factory.Get(params);
}

private:
DataFacadeFactory<FacadeT, AlgorithmT> facade_factory;
};

template <typename AlgorithmT, template <typename A> class FacadeT>
class ImmutableProvider final : public DataFacadeProvider<AlgorithmT, FacadeT>
{
Expand Down Expand Up @@ -74,6 +99,8 @@ template <typename AlgorithmT>
using WatchingProvider = detail::WatchingProvider<AlgorithmT, DataFacade>;
template <typename AlgorithmT>
using ImmutableProvider = detail::ImmutableProvider<AlgorithmT, DataFacade>;
template <typename AlgorithmT>
using ExternalProvider = detail::ExternalProvider<AlgorithmT, DataFacade>;
}
}

Expand Down
7 changes: 7 additions & 0 deletions include/engine/engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ template <typename Algorithm> class Engine final : public EngineInterface
<< routing_algorithms::name<Algorithm>();
facade_provider = std::make_unique<WatchingProvider<Algorithm>>();
}
else if (!config.memory_file.empty())
{
util::Log(logDEBUG) << "Using memory mapped filed at " << config.memory_file
<< " with algorithm " << routing_algorithms::name<Algorithm>();
facade_provider = std::make_unique<ExternalProvider<Algorithm>>(config.storage_config,
config.memory_file);
}
else
{
util::Log(logDEBUG) << "Using internal memory with algorithm "
Expand Down
1 change: 1 addition & 0 deletions include/engine/engine_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct EngineConfig final
int max_results_nearest = -1;
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
bool use_shared_memory = true;
boost::filesystem::path memory_file;
Algorithm algorithm = Algorithm::CH;
std::string verbosity;
};
Expand Down
20 changes: 18 additions & 2 deletions include/nodejs/node_osrm_support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,30 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
if (path.IsEmpty())
return engine_config_ptr();

auto memory_file = params->Get(Nan::New("memory_file").ToLocalChecked());
if (memory_file.IsEmpty())
return engine_config_ptr();

auto shared_memory = params->Get(Nan::New("shared_memory").ToLocalChecked());
if (shared_memory.IsEmpty())
return engine_config_ptr();

if (!memory_file->IsUndefined())
{
if (path->IsUndefined())
{
Nan::ThrowError("memory_file option requires a path to a file.");
return engine_config_ptr();
}

engine_config->memory_file = *v8::String::Utf8Value(Nan::To<v8::String>(memory_file).ToLocalChecked());
}

if (!path->IsUndefined())
{
engine_config->storage_config =
osrm::StorageConfig(*v8::String::Utf8Value(Nan::To<v8::String>(path).ToLocalChecked()));
engine_config->storage_config = osrm::StorageConfig(
*v8::String::Utf8Value(Nan::To<v8::String>(path).ToLocalChecked()));

engine_config->use_shared_memory = false;
}
if (!shared_memory->IsUndefined())
Expand Down
34 changes: 34 additions & 0 deletions include/util/mmap_file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,32 @@ util::vector_view<T> mmapFile(const boost::filesystem::path &file, RegionT &regi
SOURCE_REF);
}
}

template <typename T, typename RegionT>
util::vector_view<T>
mmapFile(const boost::filesystem::path &file, RegionT &region, const std::size_t size)
{
try
{
// Create a new file with the given size in bytes
boost::iostreams::mapped_file_params params;
params.path = file.c_str();
params.mode = std::ios::in | std::ios::out;
params.new_file_size = size;
region.open(params);

std::size_t num_objects = size / sizeof(T);
auto data_ptr = region.data();
BOOST_ASSERT(reinterpret_cast<uintptr_t>(data_ptr) % alignof(T) == 0);
return util::vector_view<T>(reinterpret_cast<T *>(data_ptr), num_objects);
}
catch (const std::exception &exc)
{
throw exception(
boost::str(boost::format("File %1% mapping failed: %2%") % file % exc.what()) +
SOURCE_REF);
}
}
}

template <typename T>
Expand All @@ -48,6 +74,14 @@ util::vector_view<T> mmapFile(const boost::filesystem::path &file,
{
return detail::mmapFile<T>(file, region);
}

template <typename T>
util::vector_view<T> mmapFile(const boost::filesystem::path &file,
boost::iostreams::mapped_file &region,
std::size_t size)
{
return detail::mmapFile<T>(file, region, size);
}
}
}

Expand Down
55 changes: 55 additions & 0 deletions src/engine/datafacade/mmap_memory_allocator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "engine/datafacade/mmap_memory_allocator.hpp"

#include "storage/storage.hpp"

#include "util/log.hpp"
#include "util/mmap_file.hpp"

#include "boost/assert.hpp"

namespace osrm
{
namespace engine
{
namespace datafacade
{

MMapMemoryAllocator::MMapMemoryAllocator(const storage::StorageConfig &config, const boost::filesystem::path &memory_file)
{
storage::Storage storage(config);

if (!boost::filesystem::exists(memory_file))
{
storage::DataLayout initial_layout;
storage.PopulateLayout(initial_layout);

auto data_size = initial_layout.GetSizeOfLayout();
auto total_size = data_size + sizeof(storage::DataLayout);

mapped_memory = util::mmapFile<char>(memory_file, mapped_memory_file, total_size);

data_layout = reinterpret_cast<storage::DataLayout*>(mapped_memory.data());
*data_layout = initial_layout;
storage.PopulateData(*data_layout, GetMemory());
}
else
{
mapped_memory = util::mmapFile<char>(memory_file, mapped_memory_file);
data_layout = reinterpret_cast<storage::DataLayout*>(mapped_memory.data());
}
}

MMapMemoryAllocator::~MMapMemoryAllocator() {}

storage::DataLayout &MMapMemoryAllocator::GetLayout()
{
return *data_layout;
}
char *MMapMemoryAllocator::GetMemory()
{
return mapped_memory.data() + sizeof(storage::DataLayout);
}

} // namespace datafacade
} // namespace engine
} // namespace osrm
3 changes: 3 additions & 0 deletions src/tools/routed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ inline unsigned generateServerProgramOptions(const int argc,
("shared-memory,s",
value<bool>(&config.use_shared_memory)->implicit_value(true)->default_value(false),
"Load data from shared memory") //
("memory_file",
value<boost::filesystem::path>(&config.memory_file),
"Store data in a memory mapped file rather than in process memory.") //
("algorithm,a",
value<EngineConfig::Algorithm>(&config.algorithm)
->default_value(EngineConfig::Algorithm::CH, "CH"),
Expand Down
2 changes: 2 additions & 0 deletions test/nodejs/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ if (process.env.OSRM_DATA_PATH !== undefined) {
exports.data_path = path.join(path.resolve(process.env.OSRM_DATA_PATH), "ch/monaco.osrm");
exports.mld_data_path = path.join(path.resolve(process.env.OSRM_DATA_PATH), "mld/monaco.osrm");
exports.corech_data_path = path.join(path.resolve(process.env.OSRM_DATA_PATH), "corech/monaco.osrm");
exports.test_memory_path = path.join(path.resolve(process.env.OSRM_DATA_PATH), "test_memory");
console.log('Setting custom data path to ' + exports.data_path);
} else {
exports.data_path = path.resolve(path.join(__dirname, "../data/ch/monaco.osrm"));
exports.mld_data_path = path.resolve(path.join(__dirname, "../data/mld/monaco.osrm"));
exports.corech_data_path = path.resolve(path.join(__dirname, "../data/corech/monaco.osrm"));
exports.test_memory_path = path.resolve(path.join(__dirname, "../data/test_memory"));
}
7 changes: 7 additions & 0 deletions test/nodejs/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var OSRM = require('../../');
var test = require('tape');
var monaco_path = require('./constants').data_path;
var test_memory_file = require('./constants').test_memory_file;
var monaco_mld_path = require('./constants').mld_data_path;
var monaco_corech_path = require('./constants').corech_data_path;

Expand Down Expand Up @@ -37,6 +38,12 @@ test('constructor: takes a shared memory argument', function(assert) {
assert.ok(osrm);
});

test('constructor: takes a memory file', function(assert) {
assert.plan(1);
var osrm = new OSRM({path: monaco_path, memory_file: test_memory_file});
assert.ok(osrm);
});

test('constructor: throws if shared_memory==false with no path defined', function(assert) {
assert.plan(1);
assert.throws(function() { new OSRM({shared_memory: false}); },
Expand Down

0 comments on commit 93718b5

Please sign in to comment.