osrm-backend/include/storage/tar.hpp

176 lines
4.5 KiB
C++
Raw Normal View History

2018-03-14 05:51:41 -04:00
#ifndef OSRM_STORAGE_TAR_HPP
#define OSRM_STORAGE_TAR_HPP
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/fingerprint.hpp"
#include "util/version.hpp"
#include <boost/filesystem/path.hpp>
extern "C" {
#include "microtar.h"
}
namespace osrm
{
namespace storage
{
2018-03-14 20:27:16 -04:00
namespace tar
{
2018-03-14 05:51:41 -04:00
2018-03-14 20:27:16 -04:00
class FileReader
2018-03-14 05:51:41 -04:00
{
public:
2018-03-14 20:27:16 -04:00
FileReader(const boost::filesystem::path &path) : path(path)
2018-03-14 05:51:41 -04:00
{
2018-03-14 19:42:18 -04:00
auto ret = mtar_open(&handle, path.c_str(), "r");
if (ret != MTAR_ESUCCESS)
{
throw util::exception(mtar_strerror(ret));
}
2018-03-14 05:51:41 -04:00
}
2018-03-14 20:27:16 -04:00
~FileReader()
2018-03-14 05:51:41 -04:00
{
2018-03-14 19:42:18 -04:00
mtar_close(&handle);
}
2018-03-14 05:51:41 -04:00
2018-03-14 20:27:16 -04:00
std::uint64_t ReadElementCount64(const std::string &name)
{
return ReadOne<std::uint64_t>(name + "_count");
}
2018-03-14 19:42:18 -04:00
template <typename T> T ReadOne(const std::string &name)
{
2018-03-14 05:51:41 -04:00
T tmp;
2018-03-14 19:42:18 -04:00
ReadInto(name, &tmp, 1);
2018-03-14 05:51:41 -04:00
return tmp;
}
2018-03-14 19:42:18 -04:00
template <typename T>
void ReadInto(const std::string &name, T *data, const std::size_t number_of_entries)
2018-03-14 05:51:41 -04:00
{
mtar_header_t header;
2018-03-14 19:42:18 -04:00
auto ret = mtar_find(&handle, name.c_str(), &header);
if (ret != MTAR_ESUCCESS)
{
throw util::exception(mtar_strerror(ret));
}
2018-03-14 05:51:41 -04:00
if (header.size != sizeof(T) * number_of_entries)
{
throw util::exception("Datatype size does not match file size.");
}
2018-03-14 19:42:18 -04:00
ret = mtar_read_data(&handle, reinterpret_cast<char *>(data), header.size);
if (ret != MTAR_ESUCCESS)
{
throw util::exception(mtar_strerror(ret));
}
2018-03-14 05:51:41 -04:00
}
using TarEntry = std::tuple<std::string, std::size_t>;
template <typename OutIter> void List(OutIter out)
{
mtar_header_t header;
2018-03-14 19:42:18 -04:00
while (mtar_read_header(&handle, &header) != MTAR_ENULLRECORD)
2018-03-14 05:51:41 -04:00
{
2018-03-14 19:42:18 -04:00
if (header.type == MTAR_TREG)
{
*out++ = TarEntry {header.name, header.size};
}
mtar_next(&handle);
2018-03-14 05:51:41 -04:00
}
}
private:
bool ReadAndCheckFingerprint()
{
auto loaded_fingerprint = ReadOne<util::FingerPrint>("osrm_fingerprint");
const auto expected_fingerprint = util::FingerPrint::GetValid();
if (!loaded_fingerprint.IsValid())
{
throw util::RuntimeError(path.string(), ErrorCode::InvalidFingerprint, SOURCE_REF);
}
if (!expected_fingerprint.IsDataCompatible(loaded_fingerprint))
{
const std::string fileversion =
std::to_string(loaded_fingerprint.GetMajorVersion()) + "." +
std::to_string(loaded_fingerprint.GetMinorVersion()) + "." +
std::to_string(loaded_fingerprint.GetPatchVersion());
throw util::RuntimeError(std::string(path.string()) + " prepared with OSRM " +
fileversion + " but this is " + OSRM_VERSION,
ErrorCode::IncompatibleFileVersion,
SOURCE_REF);
}
return true;
}
boost::filesystem::path path;
mtar_t handle;
};
2018-03-14 20:27:16 -04:00
class FileWriter
2018-03-14 05:51:41 -04:00
{
public:
2018-03-14 20:27:16 -04:00
FileWriter(const boost::filesystem::path &path) : path(path)
2018-03-14 05:51:41 -04:00
{
2018-03-14 19:42:18 -04:00
auto ret = mtar_open(&handle, path.c_str(), "w");
if (ret != MTAR_ESUCCESS)
throw util::exception(mtar_strerror(ret));
2018-03-14 05:51:41 -04:00
WriteFingerprint();
}
2018-03-14 20:27:16 -04:00
~FileWriter()
2018-03-14 19:42:18 -04:00
{
mtar_finalize(&handle);
mtar_close(&handle);
}
2018-03-14 20:27:16 -04:00
void WriteElementCount64(const std::string &name, const std::uint64_t count)
2018-03-14 05:51:41 -04:00
{
2018-03-14 20:27:16 -04:00
WriteOne(name + "_count", count);
2018-03-14 05:51:41 -04:00
}
2018-03-14 20:27:16 -04:00
template <typename T> void WriteOne(const std::string &name, const T &data)
2018-03-14 05:51:41 -04:00
{
2018-03-14 20:27:16 -04:00
WriteFrom(name, &data, 1);
2018-03-14 19:42:18 -04:00
}
template <typename T>
void WriteFrom(const std::string &name, const T *data, const std::size_t number_of_entries)
{
auto number_of_bytes = number_of_entries * sizeof(T);
auto ret = mtar_write_file_header(&handle, name.c_str(), number_of_bytes);
if (ret != MTAR_ESUCCESS)
{
throw util::exception(mtar_strerror(ret));
}
ret = mtar_write_data(&handle, reinterpret_cast<const char *>(data), number_of_bytes);
if (ret != MTAR_ESUCCESS)
{
throw util::exception(mtar_strerror(ret));
}
2018-03-14 05:51:41 -04:00
}
private:
void WriteFingerprint()
{
const auto fingerprint = util::FingerPrint::GetValid();
WriteOne("osrm_fingerprint", fingerprint);
}
boost::filesystem::path path;
mtar_t handle;
};
2018-03-14 20:27:16 -04:00
}
2018-03-14 05:51:41 -04:00
}
}
#endif