Adds immediate migration results

This commit is contained in:
torsten committed 2026-08-18 22:12:24 +02:00
1 parent ba4121728b
commit 6a2a0667ab
2395 files changed
+357322 -2524

No files matched your search

@@ -0,0 +1,83 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
All rights reserved.
No duplications, whole or partial, manual or electronic, may be made
without express written permission. Any such copies, or
revisions thereof, must display this notice unaltered.
This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef HPP_APPUTILS_LOCKEDBUFFER_HPP_
#define HPP_APPUTILS_LOCKEDBUFFER_HPP_
// IMPORTANT: macros.hpp must be the first RTI header included in every header
// file so that symbols are exported correctly on Windows
#include <dds/core/macros.hpp>
#include "dds/core/types.hpp"
namespace rti { namespace apputils { namespace util {
/**
* A type-agnostic class that services as a locked, unmodifiable region in
* memory. This is handy to transport a data buffer from one code region to
* another without having to perform any copy operations. Producer of the buffer
* and consumer of the buffer know how to work with the raw data.
*/
class UntypedLockedBuffer {
public:
UntypedLockedBuffer() : buffer_(NULL), size_(0) {}
UntypedLockedBuffer(const void *buffer, const uint32_t size) :
buffer_(buffer), size_(size) {}
~UntypedLockedBuffer() {}
void set(const void *buffer, const uint32_t size)
{
buffer_ = buffer;
size_ = size;
}
void reset()
{
buffer_ = NULL;
size_ = 0;
}
uint32_t size() const { return size_; }
protected:
const void * buffer() const { return buffer_; }
private:
const void *buffer_;
uint32_t size_;
};
/**
* This class represents a locked, unmodifiable region in memory. This is handy
* to transport a data buffer from one code region to another without having to
* perform any copy operations. Producer of the buffer and consumer of the
* buffer know how to work with the raw data.
*/
template <typename T>
class LockedBuffer : public UntypedLockedBuffer {
public:
LockedBuffer() : UntypedLockedBuffer() {}
LockedBuffer(const T *buffer, const uint32_t size) :
UntypedLockedBuffer(static_cast<const void *>(buffer), size) {}
~LockedBuffer() {}
void set(const T *buffer, const uint32_t size)
{
UntypedLockedBuffer::set(static_cast<const void *>(buffer), size);
}
const T * buffer() const {
return static_cast<const T *>(UntypedLockedBuffer::buffer());
}
};
} } } // namespace rti::apputils::util
#endif /* HPP_APPUTILS_LOCKEDBUFFER_HPP_ */
@@ -0,0 +1,495 @@
/*
* (c) Copyright, Real-Time Innovations, 2018.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef HPP_APPUTILS_PATH_HPP_
#define HPP_APPUTILS_PATH_HPP_
// IMPORTANT: macros.hpp must be the first RTI header included in every header
// file so that symbols are exported correctly on Windows
#include <dds/core/macros.hpp>
#include <string>
#include <vector>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdint.h>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(RTI_UNIX) || defined(RTI_QNX)
#include <unistd.h>
#include <time.h>
#endif
#if defined(RTI_UNIX) || defined(RTI_QNX)
#if !defined(_XOPEN_SOURCE) && !defined(RTI_DARWIN)
#define _XOPEN_SOURCE 600
#endif
#include <ftw.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdint.h>
#endif
#ifdef RTI_WIN32
#include <windows.h>
#endif
#include "osapi/osapi_type.h"
#include "osapi/osapi_utility.h"
#include <rti/core/Exception.hpp>
#include <rti/apputils/ServiceException.hpp>
namespace rti { namespace apputils { namespace util {
class Path {
public:
Path()
{ }
Path(const std::string& path) : path_string_(path)
{
path_string_ = remove_double_separators(path_string_);
path_string_ = remove_trailing_separators(path_string_);
}
Path(const Path& path) : path_string_(path.path_string_)
{ }
operator const std::string &() const
{
return path_string_;
}
operator const char *() const
{
return path_string_.c_str();
}
const char *c_str() const
{
return path_string_.c_str();
}
bool empty() const
{
return path_string_.empty();
}
void append(const std::string& fragment)
{
if (!path_string_.empty()) {
path_string_ += "/";
}
path_string_ += fragment;
path_string_ = remove_double_separators(path_string_);
path_string_ = remove_trailing_separators(path_string_);
}
void append(const Path& fragment)
{
append((const std::string&) fragment);
}
void operator+=(const std::string& fragment)
{
append(fragment);
}
void operator+=(const Path& fragment)
{
append((const std::string&) fragment);
}
Path operator+(const std::string& other) const
{
Path path(*this);
path.append(other);
return path;
}
Path operator+(const Path& other) const
{
Path path(*this);
path.append(other);
return path;
}
int compare(const Path& other)
{
return path_string_.compare((const std::string&) other);
}
int compare(const std::string& other)
{
return path_string_.compare(other);
}
int compare(const char *other)
{
return path_string_.compare(other);
}
/**
* Path is interpreted as a file. Return whether the file exists or not.
*/
bool exists() const
{
// Check if the path is a file and if it exists
if (RTIOsapiFile_exists(path_string_.c_str()) == RTI_TRUE) {
return true;
} else {
#if defined(RTI_UNIX) || defined(RTI_QNX)
// Otherwise check if it's a directory and if it exists
struct stat info;
if (stat(path_string_.c_str(), &info) == 0
&& S_ISDIR(info.st_mode)) {
return true;
} else {
return false;
}
#elif defined(RTI_WIN32)
#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode) &_S_IFMT) == _S_IFDIR)
#endif
// Otherwise check if it's a directory and if it exists
struct _stat info;
if (_stat(path_string_.c_str(), &info) == 0
&& S_ISDIR(info.st_mode)) {
return true;
} else {
return false;
}
#endif
}
}
static void create_directory(const Path& path)
{
#if defined(RTI_UNIX) || defined(RTI_QNX)
errno = 0;
if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0
&& (errno != EEXIST)) {
std::stringstream error_msg;
error_msg << "!create directory: " << path << "\n"
<< "CreateDirectory() error code: " << errno << "\n";
throw dds::core::IllegalOperationError(error_msg.str());
}
#elif defined(RTI_WIN32)
if (!CreateDirectory(path, NULL)) {
DWORD last_error = GetLastError();
if (last_error != ERROR_ALREADY_EXISTS) {
std::stringstream error_msg;
error_msg << "!create directory: " << path << "\n"
<< "CreateDirectory() error code: " << last_error
<< "\n";
throw dds::core::IllegalOperationError(error_msg.str());
}
}
#else
throw dds::core::IllegalOperationError("unsupported");
#endif
}
/**
* Interpreting the path as a directory, create any non-existing directories
* in the path.
*/
void create_directory()
{
// If the path is a file, and it exists, exit
if (exists()) {
return;
}
// Get splits, build a
std::vector<std::string> splits = split();
Path aux;
for (std::vector<std::string>::iterator split_it = splits.begin();
split_it != splits.end();
split_it++) {
aux += *split_it;
if (!aux.exists()) {
create_directory(aux);
}
}
}
static void remove_directory(const Path& path)
{
#if defined(RTI_UNIX) || defined(RTI_QNX)
errno = 0;
if (nftw(path, remove_file, 20, FTW_DEPTH) == -1) {
if (errno != ENOENT) {
perror("nftw");
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"remove_directory() error");
}
}
#else
if (!RTIOsapiFile_removeFileOrDirectory(path.c_str())) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_ss,
"Failed to delete directory: ",
path.c_str());
}
#endif
}
void copy_to(const Path& destination_path)
{
if (!exists()) {
return;
}
try {
std::ifstream src(path_string_.c_str(), std::ios::binary);
std::ofstream dst(
destination_path.path_string_.c_str(),
std::ios::binary);
dst << src.rdbuf();
} catch (std::exception& ex) {
std::stringstream stream;
stream << "Failed to copy file" << std::endl;
stream << " origin : " << path_string_ << std::endl;
stream << " destination: " << destination_path << std::endl;
stream << " error message: " << ex.what() << std::endl;
DDSLog_exception(&RTI_LOG_ANY_s, stream.str().c_str());
}
}
void append_extension(const std::string& extension)
{
path_string_ += extension;
}
/**
* This method detects and returns a (last) "." in the last split of a
* string. The substring after this dot is considered to be the file
* extension.
*/
std::string detect_file_extension()
{
std::string file_extension;
std::vector<std::string> splits = split();
std::string last_split = splits[splits.size() - 1];
std::string::size_type pos = last_split.find_last_of('.');
if (pos != std::string::npos) {
file_extension = last_split.substr(pos + 1);
}
return file_extension;
}
/**
* This method returns the file name (the last split in the path). Depending
* on the parameter, it will strip out the file extension or not.
*/
std::string detect_file_name(bool include_extension = true) const
{
std::vector<std::string> splits = split();
std::string last_split = splits[splits.size() - 1];
if (!include_extension) {
std::string::size_type pos = last_split.find_last_of('.');
if (pos != std::string::npos) {
return last_split.substr(0, pos);
}
}
return last_split;
}
std::vector<std::string> split() const
{
std::vector<std::string> splits;
std::istringstream stream(path_string_);
std::string string_split;
bool prepend_separator = false;
while (getline(stream, string_split, '/')) {
if (string_split.empty()) {
// This can happen if the path is absolute (starts with a
// separator). The first split should contain that separator.
// Signal this with a boolean variable
prepend_separator = true;
continue;
}
if (prepend_separator) {
splits.push_back("/" + string_split);
prepend_separator = false;
} else {
splits.push_back(string_split);
}
}
return splits;
}
static Path from_splits(const std::vector<std::string>& splits)
{
Path path;
for (size_t i = 0; i < splits.size(); i++) {
path += splits[i];
}
return path;
}
uint64_t file_size() const
{
#ifdef RTI_WIN32
HANDLE file_handle = CreateFile(
path_string_.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
DDSLog_warn(
&RTI_LOG_ANY_ss,
"Failed to get file size for file: ",
path_string_.c_str());
return 0;
}
LARGE_INTEGER size;
if (!GetFileSizeEx(file_handle, &size)) {
CloseHandle(file_handle);
DDSLog_warn(
&RTI_LOG_ANY_ss,
"Failed to get file size for file: ",
path_string_.c_str());
return 0;
}
CloseHandle(file_handle);
return size.QuadPart;
#else
struct stat buffer;
if (stat(path_string_.c_str(), &buffer) != 0) {
DDSLog_warn(
&RTI_LOG_ANY_ss,
"Failed to get file size for file: ",
path_string_.c_str());
return 0;
}
return (uint64_t) buffer.st_size;
#endif
}
#if !defined(RTI_INTY)
/*
* CORE-10727 [Antonio L]:
* cwd() is not supported in all the architectures. We have to
* port it.
*/
static Path cwd()
{
char working_directory[RTI_OSAPI_STRING_SEQ_STRING_MAX_SIZE] = { 0 };
bool no_error = false;
no_error =
(RTIOsapiUtility_getCurrentDirectory(
working_directory,
RTI_OSAPI_STRING_SEQ_STRING_MAX_SIZE)
!= NULL);
if (!no_error) {
int errnum = RTIOsapiUtility_getError();
char error_string[RTI_OSAPI_ERROR_STRING_MAX_SIZE] = { 0 };
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_OS_FAILURE_sXs,
"getcwd",
errnum,
RTIOsapiUtility_getErrorString(
error_string,
RTI_OSAPI_ERROR_STRING_MAX_SIZE,
errnum));
}
return Path(working_directory);
}
#endif
private:
std::string path_string_;
#define SEPARATOR_STR "/"
/**
* Converter Windows-style separators into Unix-style ones
*/
std::string normalize(const std::string& path)
{
std::string normalized(path);
const std::string SEPARATOR(SEPARATOR_STR);
std::string::size_type pos = normalized.find_first_of('\\');
while (pos != std::string::npos) {
normalized = normalized.replace(pos, 1, SEPARATOR);
pos = normalized.find_first_of('\\', pos + 1);
}
return normalized;
}
std::string remove_trailing_separators(const std::string& path)
{
std::string modified(normalize(path));
if (!modified.empty() && modified.at(modified.size() - 1) == '/') {
modified.erase(modified.size() - 1);
}
return modified;
}
std::string remove_double_separators(std::string& path)
{
const std::string DOUBLE_SEPARATOR_STR("//");
std::string modified(normalize(path));
std::string::size_type pos = modified.find(DOUBLE_SEPARATOR_STR);
while (pos != std::string::npos) {
modified = modified.replace(
pos,
DOUBLE_SEPARATOR_STR.size(),
SEPARATOR_STR);
pos = modified.find(DOUBLE_SEPARATOR_STR, pos + 1);
}
return modified;
}
static int remove_file(
const char *fpath,
const struct stat *sb,
int tflag,
struct FTW *ftwbuf)
{
RTIOsapiUtility_unusedParameter(sb);
RTIOsapiUtility_unusedParameter(tflag);
RTIOsapiUtility_unusedParameter(ftwbuf);
#ifdef RTI_QNX
/**
* In QNX we create the working directory in the NFS. Because the NFS
* have important delays, if we try to remove all the directories,
* the remove will fail because the NFS will accept the request to
* remove the files, but they won't be removed once we reach the upper
* level. Therefore, we will not remove the directories of the QNX
* testers
*/
struct stat buf;
int err = stat(fpath, &buf);
errno = 0;
if (err == 0 && (buf.st_mode & _S_IFMT) != S_IFDIR)
errno = remove(fpath);
return errno;
#else
return remove(fpath);
#endif
}
};
}}} // namespace rti::apputils::util
#endif /* HPP_APPUTILS_PATH_HPP_ */
@@ -0,0 +1,122 @@
/*
* (c) Copyright, Real-Time Innovations, 2016-.
* All rights reserved.
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef APPUTILS_HPP_
#define APPUTILS_HPP_
// IMPORTANT: macros.hpp must be the first RTI header included in every header
// file so that symbols are exported correctly on Windows
#include <dds/core/macros.hpp>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <limits>
#include <string>
#include <sstream>
#include "osapi/osapi_utility.h"
#include <dds/core/types.hpp>
#include <rti/core/Exception.hpp>
#include "dds/core/Time.hpp"
#define STATIC_CONST_STRING_DEFINITION(classname, name, value) \
const std::string& classname::name() \
{ \
static std::string name##var(value); \
return name##var; \
}
#define RECORDER_FILE_PATH_MAX_LENGTH (4096)
namespace rti { namespace apputils { namespace util {
constexpr int64_t g_int64_max = 0x7FFFFFFFFFFFFFFFULL;
constexpr uint64_t g_uint64_max = 0xFFFFFFFFFFFFFFFFULL;
inline
std::string normalize_path(const std::string& file_name)
{
char normalized[RECORDER_FILE_PATH_MAX_LENGTH] = {'\0'};
if (!RTIOsapiUtility_normalizePath(
normalized,
RECORDER_FILE_PATH_MAX_LENGTH,
file_name.c_str())) {
std::stringstream error_msg;
error_msg << "!normalize path " << file_name.c_str() << "\n";
throw dds::core::IllegalOperationError(error_msg.str());
}
return normalized;
}
inline
int64_t convert_uint64_into_int64(uint64_t value)
{
int64_t signed_int64 = 0;
if (value > g_int64_max) {
signed_int64 = g_int64_max;
} else {
signed_int64 = (int64_t) value;
}
return signed_int64;
}
inline
uint64_t to_nanosecs(dds::core::Time time)
{
uint64_t nanosec;
try {
nanosec = time.to_nanosecs();
} catch (std::overflow_error&) {
nanosec = g_uint64_max;
}
return nanosec;
}
/**
* @brief Check if the sum of two values would produce an overflow.
*
* @tparam T type of the elements to be summed.
*
* @param lhs Left-hand side of the sum
* @param rhs Right-hand side of the sum
*
* @return true if the sum overflows, false otherwise.
*/
template <typename T>
bool sum_overflows(T lhs, T rhs)
{
return lhs > 0 && rhs > 0 && (std::numeric_limits<T>::max)() - lhs < rhs;
}
/**
* @brief Check if the sum of two values would produce an underflow.
*
* @tparam T type of the elements to be summed.
*
* @param lhs Left-hand side of the sum
* @param rhs Right-hand side of the sum
*
* @return true if the sum underflows, false otherwise.
*/
template <typename T>
bool sum_underflows(T lhs, T rhs)
{
return lhs < 0 && rhs < 0 && std::numeric_limits<T>::lowest() - lhs > rhs;
}
} } } // namespace rti:apputils::util
#endif /* APPUTILS_HPP_ */
@@ -0,0 +1,155 @@
/*
(c) Copyright, Real-Time Innovations, 2018.
All rights reserved.
No duplications, whole or partial, manual or electronic, may be made
without express written permission. Any such copies, or
revisions thereof, must display this notice unaltered.
This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef HPP_RTI_APPUTILS_VERSIONABLECOMPONENT_HPP_
#define HPP_RTI_APPUTILS_VERSIONABLECOMPONENT_HPP_
// IMPORTANT: macros.hpp must be the first RTI header included in every header
// file so that symbols are exported correctly on Windows
#include <dds/core/macros.hpp>
#include <sstream>
#include <string>
#include <stdint.h>
#include <assert.h>
#include "dds/core/Exception.hpp"
namespace rti { namespace apputils { namespace util {
class ComponentVersion {
public:
constexpr ComponentVersion() noexcept :
major_(0),
minor_(0)
{ }
constexpr ComponentVersion(const uint8_t major, const uint8_t minor) noexcept :
major_(major),
minor_(minor)
{ }
ComponentVersion(const std::string& version_str)
{
std::istringstream stream(version_str);
int16_t value;
stream >> value;
if (stream.fail()) {
throw dds::core::InvalidArgumentError(version_string_error(version_str));
}
major_ = static_cast<uint8_t>(value);
char separator;
stream >> separator;
if (stream.fail() || separator != '.') {
throw dds::core::InvalidArgumentError(version_string_error(version_str));
}
stream >> value;
if (stream.fail()) {
throw dds::core::InvalidArgumentError(version_string_error(version_str));
}
minor_ = static_cast<uint8_t>(value);
}
uint8_t get_major() const noexcept { return major_; }
uint8_t get_minor() const noexcept { return minor_; }
bool operator ==(const ComponentVersion& other) const noexcept
{
return (major_ == other.major_ && minor_ == other.minor_);
}
bool operator !=(const ComponentVersion& other) const noexcept
{
return !(*this == other);
}
bool operator < (const ComponentVersion& other) const noexcept
{
if ((int16_t) major_ - (int16_t) other.major_ == 0) {
return ((int16_t) minor_ - (int16_t) other.minor_ < 0);
} else {
return ((int16_t) major_ - (int16_t) other.major_ < 0);
}
}
bool operator > (const ComponentVersion& other) const noexcept
{
if ((int16_t) major_ - (int16_t) other.major_ == 0) {
return ((int16_t) minor_ - (int16_t) other.minor_ > 0);
} else {
return ((int16_t) major_ - (int16_t) other.major_ > 0);
}
}
operator std::string () const noexcept
{
return std::to_string(major_) + "." + std::to_string(minor_);
}
private:
uint8_t major_;
uint8_t minor_;
std::string version_string_error (const std::string & str) const noexcept
{
return "VersionableComponent: invalid version string: " + str;
}
};
/**
* @brief A versionable component has a name and a version and it's used to
* keep track of the versions of the components used to record data.
* This information is kept in the 'metadata' database file. It can later
* be recovered by Replay/Converter to use exactly the same components'
* versions that were when recording.
* @param VersionType The version object to be used. By default, the Version
* type implemented above is used (a simple, two-digit, stringifyable
* version type).
*/
template<typename VersionType>
class VersionableComponent {
public:
VersionableComponent(
std::string component_name,
const VersionType& version) :
component_name_(component_name),
version_(version) { }
const VersionType& version() const { return version_; }
const std::string& component_name() const { return component_name_; }
void verify_version(const VersionType& version) const
{
if (version > version_) {
std::stringstream error_stream;
error_stream << "VersionableComponent: " << component_name_.c_str()
<< ": detected newer version. The current version of the "
<< "component in this tool ("
<< ((const std::string&) version_).c_str()
<< ") is unable to read the newer "
<< component_name_.c_str() <<" version ("
<< ((const std::string&) version).c_str() <<") found ";
throw dds::core::IllegalOperationError(error_stream.str());
}
}
private:
std::string component_name_;
VersionType version_;
};
typedef VersionableComponent<ComponentVersion> DefaultVersionableComponent;
} } } /* namespace rti::apputils::util */
#endif /* HPP_RTI_APPUTILS_VERSIONABLECOMPONENT_HPP_ */