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"
|
2018-03-15 16:10:21 -04:00
|
|
|
#include "util/integer_range.hpp"
|
2018-03-14 05:51:41 -04:00
|
|
|
#include "util/version.hpp"
|
|
|
|
|
2024-06-20 15:44:28 -04:00
|
|
|
#include <filesystem>
|
2018-03-14 05:51:41 -04:00
|
|
|
|
2020-11-26 10:21:39 -05:00
|
|
|
extern "C"
|
|
|
|
{
|
2018-03-14 05:51:41 -04:00
|
|
|
#include "microtar.h"
|
|
|
|
}
|
|
|
|
|
2022-12-11 04:10:26 -05:00
|
|
|
namespace osrm::storage::tar
|
2018-03-14 20:27:16 -04:00
|
|
|
{
|
2018-03-22 14:25:43 -04:00
|
|
|
namespace detail
|
|
|
|
{
|
|
|
|
inline void
|
2024-06-20 15:44:28 -04:00
|
|
|
checkMTarError(int error_code, const std::filesystem::path &filepath, const std::string &name)
|
2018-03-22 14:25:43 -04:00
|
|
|
{
|
|
|
|
switch (error_code)
|
|
|
|
{
|
|
|
|
case MTAR_ESUCCESS:
|
|
|
|
return;
|
|
|
|
case MTAR_EFAILURE:
|
2018-04-10 06:26:26 -04:00
|
|
|
throw util::RuntimeError(
|
|
|
|
filepath.string() + " : " + name, ErrorCode::FileIOError, SOURCE_REF);
|
2018-03-22 14:25:43 -04:00
|
|
|
case MTAR_EOPENFAIL:
|
|
|
|
throw util::RuntimeError(filepath.string() + " : " + name,
|
|
|
|
ErrorCode::FileOpenError,
|
|
|
|
SOURCE_REF,
|
|
|
|
std::strerror(errno));
|
|
|
|
case MTAR_EREADFAIL:
|
|
|
|
throw util::RuntimeError(filepath.string() + " : " + name,
|
|
|
|
ErrorCode::FileReadError,
|
|
|
|
SOURCE_REF,
|
|
|
|
std::strerror(errno));
|
|
|
|
case MTAR_EWRITEFAIL:
|
|
|
|
throw util::RuntimeError(filepath.string() + " : " + name,
|
|
|
|
ErrorCode::FileWriteError,
|
|
|
|
SOURCE_REF,
|
|
|
|
std::strerror(errno));
|
|
|
|
case MTAR_ESEEKFAIL:
|
|
|
|
throw util::RuntimeError(filepath.string() + " : " + name,
|
|
|
|
ErrorCode::FileIOError,
|
|
|
|
SOURCE_REF,
|
|
|
|
std::strerror(errno));
|
|
|
|
case MTAR_EBADCHKSUM:
|
|
|
|
throw util::RuntimeError(filepath.string() + " : " + name,
|
|
|
|
ErrorCode::FileIOError,
|
|
|
|
SOURCE_REF,
|
|
|
|
std::strerror(errno));
|
|
|
|
case MTAR_ENULLRECORD:
|
|
|
|
throw util::RuntimeError(filepath.string() + " : " + name,
|
|
|
|
ErrorCode::UnexpectedEndOfFile,
|
|
|
|
SOURCE_REF,
|
|
|
|
std::strerror(errno));
|
|
|
|
case MTAR_ENOTFOUND:
|
|
|
|
throw util::RuntimeError(filepath.string() + " : " + name,
|
|
|
|
ErrorCode::FileIOError,
|
|
|
|
SOURCE_REF,
|
|
|
|
std::strerror(errno));
|
|
|
|
default:
|
|
|
|
throw util::exception(filepath.string() + " : " + name + ":" + mtar_strerror(error_code));
|
|
|
|
}
|
|
|
|
}
|
2020-11-26 10:21:39 -05:00
|
|
|
} // namespace detail
|
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-15 09:55:06 -04:00
|
|
|
enum FingerprintFlag
|
|
|
|
{
|
|
|
|
VerifyFingerprint,
|
|
|
|
HasNoFingerprint
|
|
|
|
};
|
|
|
|
|
2024-06-20 15:44:28 -04:00
|
|
|
FileReader(const std::filesystem::path &path, FingerprintFlag flag) : path(path)
|
2018-03-14 05:51:41 -04:00
|
|
|
{
|
2018-03-26 09:13:17 -04:00
|
|
|
auto ret = mtar_open(&handle, path.string().c_str(), "r");
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, "");
|
2018-03-14 05:51:41 -04:00
|
|
|
|
2018-03-15 09:55:06 -04:00
|
|
|
if (flag == VerifyFingerprint)
|
|
|
|
{
|
|
|
|
ReadAndCheckFingerprint();
|
|
|
|
}
|
2018-03-14 19:42:18 -04:00
|
|
|
}
|
2018-03-14 05:51:41 -04:00
|
|
|
|
2018-03-15 09:55:06 -04:00
|
|
|
~FileReader() { mtar_close(&handle); }
|
|
|
|
|
2018-03-14 20:27:16 -04:00
|
|
|
std::uint64_t ReadElementCount64(const std::string &name)
|
|
|
|
{
|
2018-03-19 19:31:49 -04:00
|
|
|
std::uint64_t size;
|
|
|
|
ReadInto(name + ".meta", size);
|
|
|
|
return size;
|
2018-03-14 20:27:16 -04:00
|
|
|
}
|
|
|
|
|
2018-03-22 14:25:43 -04:00
|
|
|
template <typename T> void ReadInto(const std::string &name, T &tmp)
|
2018-03-14 19:42:18 -04:00
|
|
|
{
|
|
|
|
ReadInto(name, &tmp, 1);
|
2018-03-14 05:51:41 -04:00
|
|
|
}
|
|
|
|
|
2018-03-15 16:10:21 -04:00
|
|
|
template <typename T, typename OutIter> void ReadStreaming(const std::string &name, OutIter out)
|
|
|
|
{
|
|
|
|
mtar_header_t header;
|
|
|
|
auto ret = mtar_find(&handle, name.c_str(), &header);
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-15 16:10:21 -04:00
|
|
|
|
|
|
|
auto number_of_elements = header.size / sizeof(T);
|
|
|
|
auto expected_size = sizeof(T) * number_of_elements;
|
|
|
|
if (header.size != expected_size)
|
|
|
|
{
|
2018-03-22 14:25:43 -04:00
|
|
|
throw util::RuntimeError(name + ": Datatype size does not match file size.",
|
|
|
|
ErrorCode::UnexpectedEndOfFile,
|
|
|
|
SOURCE_REF);
|
2018-03-15 16:10:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
T tmp;
|
|
|
|
for (auto index : util::irange<std::size_t>(0, number_of_elements))
|
|
|
|
{
|
2018-03-22 14:25:43 -04:00
|
|
|
(void)index;
|
2018-03-15 16:10:21 -04:00
|
|
|
ret = mtar_read_data(&handle, reinterpret_cast<char *>(&tmp), sizeof(T));
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-15 16:10:21 -04:00
|
|
|
|
|
|
|
*out++ = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-14 19:42:18 -04:00
|
|
|
template <typename T>
|
2018-03-15 09:55:06 -04:00
|
|
|
void ReadInto(const std::string &name, T *data, const std::size_t number_of_elements)
|
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);
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-14 19:42:18 -04:00
|
|
|
|
2018-03-15 09:55:06 -04:00
|
|
|
auto expected_size = sizeof(T) * number_of_elements;
|
|
|
|
if (header.size != expected_size)
|
2018-03-14 05:51:41 -04:00
|
|
|
{
|
2018-03-22 14:25:43 -04:00
|
|
|
throw util::RuntimeError(name + ": Datatype size does not match file size.",
|
|
|
|
ErrorCode::UnexpectedEndOfFile,
|
|
|
|
SOURCE_REF);
|
2018-03-14 05:51:41 -04:00
|
|
|
}
|
|
|
|
|
2018-03-14 19:42:18 -04:00
|
|
|
ret = mtar_read_data(&handle, reinterpret_cast<char *>(data), header.size);
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-14 05:51:41 -04:00
|
|
|
}
|
|
|
|
|
2018-03-22 08:15:40 -04:00
|
|
|
struct FileEntry
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
std::size_t size;
|
|
|
|
std::size_t offset;
|
|
|
|
};
|
|
|
|
|
2018-03-14 05:51:41 -04:00
|
|
|
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)
|
|
|
|
{
|
2018-03-22 14:25:43 -04:00
|
|
|
int ret = mtar_read_data(&handle, nullptr, 0);
|
|
|
|
detail::checkMTarError(ret, path, header.name);
|
|
|
|
|
2018-03-22 08:15:40 -04:00
|
|
|
auto offset = handle.pos;
|
|
|
|
// seek back to the header
|
|
|
|
handle.remaining_data = 0;
|
2018-03-22 14:25:43 -04:00
|
|
|
ret = mtar_seek(&handle, handle.last_header);
|
|
|
|
detail::checkMTarError(ret, path, header.name);
|
|
|
|
|
2018-03-22 08:15:40 -04:00
|
|
|
*out++ = FileEntry{header.name, header.size, offset};
|
2018-03-14 19:42:18 -04:00
|
|
|
}
|
|
|
|
mtar_next(&handle);
|
2018-03-14 05:51:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool ReadAndCheckFingerprint()
|
|
|
|
{
|
2018-03-19 19:31:49 -04:00
|
|
|
util::FingerPrint loaded_fingerprint;
|
|
|
|
ReadInto("osrm_fingerprint.meta", loaded_fingerprint);
|
2018-03-14 05:51:41 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-06-20 15:44:28 -04:00
|
|
|
std::filesystem::path path;
|
2018-03-14 05:51:41 -04:00
|
|
|
mtar_t handle;
|
|
|
|
};
|
|
|
|
|
2018-03-14 20:27:16 -04:00
|
|
|
class FileWriter
|
2018-03-14 05:51:41 -04:00
|
|
|
{
|
|
|
|
public:
|
2018-03-15 09:55:06 -04:00
|
|
|
enum FingerprintFlag
|
|
|
|
{
|
|
|
|
GenerateFingerprint,
|
|
|
|
HasNoFingerprint
|
|
|
|
};
|
|
|
|
|
2024-06-20 15:44:28 -04:00
|
|
|
FileWriter(const std::filesystem::path &path, FingerprintFlag flag) : path(path)
|
2018-03-14 05:51:41 -04:00
|
|
|
{
|
2018-03-26 09:13:17 -04:00
|
|
|
auto ret = mtar_open(&handle, path.string().c_str(), "w");
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, "");
|
2018-03-15 09:55:06 -04:00
|
|
|
|
|
|
|
if (flag == GenerateFingerprint)
|
|
|
|
{
|
|
|
|
WriteFingerprint();
|
|
|
|
}
|
2018-03-14 05:51:41 -04:00
|
|
|
}
|
|
|
|
|
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-19 19:31:49 -04:00
|
|
|
WriteFrom(name + ".meta", count);
|
2018-03-14 05:51:41 -04:00
|
|
|
}
|
|
|
|
|
2018-03-19 19:31:49 -04:00
|
|
|
template <typename T> void WriteFrom(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
|
|
|
}
|
|
|
|
|
2018-03-15 16:10:21 -04:00
|
|
|
template <typename T, typename Iter>
|
|
|
|
void WriteStreaming(const std::string &name, Iter iter, const std::uint64_t number_of_elements)
|
|
|
|
{
|
|
|
|
auto number_of_bytes = number_of_elements * sizeof(T);
|
|
|
|
|
|
|
|
auto ret = mtar_write_file_header(&handle, name.c_str(), number_of_bytes);
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-15 16:10:21 -04:00
|
|
|
|
|
|
|
for (auto index : util::irange<std::size_t>(0, number_of_elements))
|
|
|
|
{
|
2018-03-22 14:25:43 -04:00
|
|
|
(void)index;
|
2018-03-15 16:10:21 -04:00
|
|
|
T tmp = *iter++;
|
|
|
|
ret = mtar_write_data(&handle, &tmp, sizeof(T));
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-15 16:10:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-22 07:33:02 -04:00
|
|
|
// Continue writing an existing file, overwrites all data after the file!
|
|
|
|
template <typename T>
|
|
|
|
void ContinueFrom(const std::string &name, const T *data, const std::size_t number_of_elements)
|
|
|
|
{
|
|
|
|
auto number_of_bytes = number_of_elements * sizeof(T);
|
|
|
|
|
|
|
|
mtar_header_t header;
|
|
|
|
auto ret = mtar_find(&handle, name.c_str(), &header);
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-22 07:33:02 -04:00
|
|
|
|
|
|
|
// update header to reflect increased tar size
|
|
|
|
auto old_size = header.size;
|
|
|
|
header.size += number_of_bytes;
|
2018-04-04 12:36:16 -04:00
|
|
|
ret = mtar_write_header(&handle, &header);
|
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-22 07:33:02 -04:00
|
|
|
|
|
|
|
// now seek to the end of the old record
|
|
|
|
handle.remaining_data = number_of_bytes;
|
|
|
|
ret = mtar_seek(&handle, handle.pos + old_size);
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-22 07:33:02 -04:00
|
|
|
|
|
|
|
ret = mtar_write_data(&handle, data, number_of_bytes);
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-22 07:33:02 -04:00
|
|
|
}
|
|
|
|
|
2018-03-14 19:42:18 -04:00
|
|
|
template <typename T>
|
2018-03-15 09:55:06 -04:00
|
|
|
void WriteFrom(const std::string &name, const T *data, const std::size_t number_of_elements)
|
2018-03-14 19:42:18 -04:00
|
|
|
{
|
2018-03-15 09:55:06 -04:00
|
|
|
auto number_of_bytes = number_of_elements * sizeof(T);
|
|
|
|
|
2018-03-14 19:42:18 -04:00
|
|
|
auto ret = mtar_write_file_header(&handle, name.c_str(), number_of_bytes);
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-15 09:55:06 -04:00
|
|
|
|
2018-03-14 19:42:18 -04:00
|
|
|
ret = mtar_write_data(&handle, reinterpret_cast<const char *>(data), number_of_bytes);
|
2018-03-22 14:25:43 -04:00
|
|
|
detail::checkMTarError(ret, path, name);
|
2018-03-14 05:51:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void WriteFingerprint()
|
|
|
|
{
|
|
|
|
const auto fingerprint = util::FingerPrint::GetValid();
|
2018-03-19 19:31:49 -04:00
|
|
|
WriteFrom("osrm_fingerprint.meta", fingerprint);
|
2018-03-14 05:51:41 -04:00
|
|
|
}
|
|
|
|
|
2024-06-20 15:44:28 -04:00
|
|
|
std::filesystem::path path;
|
2018-03-14 05:51:41 -04:00
|
|
|
mtar_t handle;
|
|
|
|
};
|
2022-12-20 12:00:11 -05:00
|
|
|
} // namespace osrm::storage::tar
|
2018-03-14 05:51:41 -04:00
|
|
|
|
|
|
|
#endif
|