Add mmap allocator
This commit is contained in:
parent
43f0723b73
commit
bec57258a4
45
include/engine/datafacade/mmap_memory_allocator.hpp
Normal file
45
include/engine/datafacade/mmap_memory_allocator.hpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#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_
|
@ -4,6 +4,7 @@
|
|||||||
#include "engine/data_watchdog.hpp"
|
#include "engine/data_watchdog.hpp"
|
||||||
#include "engine/datafacade.hpp"
|
#include "engine/datafacade.hpp"
|
||||||
#include "engine/datafacade/contiguous_internalmem_datafacade.hpp"
|
#include "engine/datafacade/contiguous_internalmem_datafacade.hpp"
|
||||||
|
#include "engine/datafacade/mmap_memory_allocator.hpp"
|
||||||
#include "engine/datafacade/process_memory_allocator.hpp"
|
#include "engine/datafacade/process_memory_allocator.hpp"
|
||||||
#include "engine/datafacade_factory.hpp"
|
#include "engine/datafacade_factory.hpp"
|
||||||
|
|
||||||
@ -25,6 +26,31 @@ template <typename AlgorithmT, template <typename A> class FacadeT> class DataFa
|
|||||||
virtual std::shared_ptr<const Facade> Get(const api::TileParameters &) const = 0;
|
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 ¶ms) const override final
|
||||||
|
{
|
||||||
|
return facade_factory.Get(params);
|
||||||
|
}
|
||||||
|
std::shared_ptr<const Facade> Get(const api::BaseParameters ¶ms) const override final
|
||||||
|
{
|
||||||
|
return facade_factory.Get(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DataFacadeFactory<FacadeT, AlgorithmT> facade_factory;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename AlgorithmT, template <typename A> class FacadeT>
|
template <typename AlgorithmT, template <typename A> class FacadeT>
|
||||||
class ImmutableProvider final : public DataFacadeProvider<AlgorithmT, FacadeT>
|
class ImmutableProvider final : public DataFacadeProvider<AlgorithmT, FacadeT>
|
||||||
{
|
{
|
||||||
@ -74,6 +100,8 @@ template <typename AlgorithmT>
|
|||||||
using WatchingProvider = detail::WatchingProvider<AlgorithmT, DataFacade>;
|
using WatchingProvider = detail::WatchingProvider<AlgorithmT, DataFacade>;
|
||||||
template <typename AlgorithmT>
|
template <typename AlgorithmT>
|
||||||
using ImmutableProvider = detail::ImmutableProvider<AlgorithmT, DataFacade>;
|
using ImmutableProvider = detail::ImmutableProvider<AlgorithmT, DataFacade>;
|
||||||
|
template <typename AlgorithmT>
|
||||||
|
using ExternalProvider = detail::ExternalProvider<AlgorithmT, DataFacade>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,13 @@ template <typename Algorithm> class Engine final : public EngineInterface
|
|||||||
<< routing_algorithms::name<Algorithm>();
|
<< routing_algorithms::name<Algorithm>();
|
||||||
facade_provider = std::make_unique<WatchingProvider<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
|
else
|
||||||
{
|
{
|
||||||
util::Log(logDEBUG) << "Using internal memory with algorithm "
|
util::Log(logDEBUG) << "Using internal memory with algorithm "
|
||||||
|
@ -88,6 +88,7 @@ struct EngineConfig final
|
|||||||
int max_results_nearest = -1;
|
int max_results_nearest = -1;
|
||||||
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
|
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
|
||||||
bool use_shared_memory = true;
|
bool use_shared_memory = true;
|
||||||
|
boost::filesystem::path memory_file;
|
||||||
Algorithm algorithm = Algorithm::CH;
|
Algorithm algorithm = Algorithm::CH;
|
||||||
std::string verbosity;
|
std::string verbosity;
|
||||||
};
|
};
|
||||||
|
@ -115,14 +115,31 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
|
|||||||
if (path.IsEmpty())
|
if (path.IsEmpty())
|
||||||
return engine_config_ptr();
|
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());
|
auto shared_memory = params->Get(Nan::New("shared_memory").ToLocalChecked());
|
||||||
if (shared_memory.IsEmpty())
|
if (shared_memory.IsEmpty())
|
||||||
return engine_config_ptr();
|
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())
|
if (!path->IsUndefined())
|
||||||
{
|
{
|
||||||
engine_config->storage_config =
|
engine_config->storage_config =
|
||||||
osrm::StorageConfig(*v8::String::Utf8Value(Nan::To<v8::String>(path).ToLocalChecked()));
|
osrm::StorageConfig(*v8::String::Utf8Value(Nan::To<v8::String>(path).ToLocalChecked()));
|
||||||
|
|
||||||
engine_config->use_shared_memory = false;
|
engine_config->use_shared_memory = false;
|
||||||
}
|
}
|
||||||
if (!shared_memory->IsUndefined())
|
if (!shared_memory->IsUndefined())
|
||||||
|
@ -33,6 +33,32 @@ util::vector_view<T> mmapFile(const boost::filesystem::path &file, RegionT ®i
|
|||||||
SOURCE_REF);
|
SOURCE_REF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename RegionT>
|
||||||
|
util::vector_view<T>
|
||||||
|
mmapFile(const boost::filesystem::path &file, RegionT ®ion, 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.string();
|
||||||
|
params.flags = boost::iostreams::mapped_file::readwrite;
|
||||||
|
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>
|
template <typename T>
|
||||||
@ -48,6 +74,14 @@ util::vector_view<T> mmapFile(const boost::filesystem::path &file,
|
|||||||
{
|
{
|
||||||
return detail::mmapFile<T>(file, region);
|
return detail::mmapFile<T>(file, region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
util::vector_view<T> mmapFile(const boost::filesystem::path &file,
|
||||||
|
boost::iostreams::mapped_file ®ion,
|
||||||
|
std::size_t size)
|
||||||
|
{
|
||||||
|
return detail::mmapFile<T>(file, region, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
53
src/engine/datafacade/mmap_memory_allocator.cpp
Normal file
53
src/engine/datafacade/mmap_memory_allocator.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#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
|
@ -112,6 +112,9 @@ inline unsigned generateServerProgramOptions(const int argc,
|
|||||||
("shared-memory,s",
|
("shared-memory,s",
|
||||||
value<bool>(&config.use_shared_memory)->implicit_value(true)->default_value(false),
|
value<bool>(&config.use_shared_memory)->implicit_value(true)->default_value(false),
|
||||||
"Load data from shared memory") //
|
"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",
|
("algorithm,a",
|
||||||
value<EngineConfig::Algorithm>(&config.algorithm)
|
value<EngineConfig::Algorithm>(&config.algorithm)
|
||||||
->default_value(EngineConfig::Algorithm::CH, "CH"),
|
->default_value(EngineConfig::Algorithm::CH, "CH"),
|
||||||
|
@ -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.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.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.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);
|
console.log('Setting custom data path to ' + exports.data_path);
|
||||||
} else {
|
} else {
|
||||||
exports.data_path = path.resolve(path.join(__dirname, "../data/ch/monaco.osrm"));
|
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.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.corech_data_path = path.resolve(path.join(__dirname, "../data/corech/monaco.osrm"));
|
||||||
|
exports.test_memory_path = path.resolve(path.join(__dirname, "../data/test_memory"));
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
var OSRM = require('../../');
|
var OSRM = require('../../');
|
||||||
var test = require('tape');
|
var test = require('tape');
|
||||||
var monaco_path = require('./constants').data_path;
|
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_mld_path = require('./constants').mld_data_path;
|
||||||
var monaco_corech_path = require('./constants').corech_data_path;
|
var monaco_corech_path = require('./constants').corech_data_path;
|
||||||
|
|
||||||
@ -37,6 +38,12 @@ test('constructor: takes a shared memory argument', function(assert) {
|
|||||||
assert.ok(osrm);
|
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) {
|
test('constructor: throws if shared_memory==false with no path defined', function(assert) {
|
||||||
assert.plan(1);
|
assert.plan(1);
|
||||||
assert.throws(function() { new OSRM({shared_memory: false}); },
|
assert.throws(function() { new OSRM({shared_memory: false}); },
|
||||||
|
Loading…
Reference in New Issue
Block a user