blob: 75e5d52337e397e03a4602cc93290fe4ca857a53 [file] [log] [blame]
#pragma once
#include <fstream>
#include <memory>
#include <mutex>
#include <optional>
#include <string_view>
#include <vector>
namespace boot_time_monitor
{
/**
* @brief Contains interfaces and implementations for resource management (data
* storage).
*
* This namespace defines how boot time data (checkpoints and durations) is
* stored and retrieved. Currently, it provides a file-based implementation.
*/
namespace resource
{
namespace btm = boot_time_monitor;
/** @brief Default directory for storing boot time monitor data files. */
extern std::string BTMonitorDir;
/** @brief Reboot complete checkpoint name */
const std::string kRebootCompleteCheckpoint = "RebootEnd";
/** @brief Suffix appended to filenames when a boot cycle is completed. */
const std::string kCompletedSuffix = ".completed";
/** @brief Suffix added to a checkpoint name to indicate the start of a
* self-measured duration. */
const std::string kBeginStageSuffix = ":BEGIN";
/** @brief Base filename for storing checkpoint data. */
const std::string kCheckpointFile = "checkpoints.csv";
/** @brief Base filename for storing duration data. */
const std::string kDurationFile = "durations.csv";
/**
* @brief Represents a single boot checkpoint record.
*/
struct Checkpoint
{
/** @brief The name identifying the checkpoint. */
std::string name;
/** @brief The wall clock time (epoch time in ms) when the checkpoint was
* reached. */
int64_t wallTime;
/** @brief The monotonic clock time (uptime in ms) when the checkpoint was
* reached. */
int64_t monoTime;
/** @brief Constructs a Checkpoint object. */
Checkpoint(std::string name, int64_t wallTime, int64_t monoTime) :
name(std::move(name)), wallTime(wallTime), monoTime(monoTime)
{}
};
/**
* @brief Represents a single boot duration measurement record.
*/
struct Duration
{
/** @brief The name identifying the duration measurement. */
std::string name;
/** @brief The measured duration in milliseconds. */
int64_t duration;
/** @brief Constructs a Duration object. */
Duration(std::string name, int64_t duration) :
name(std::move(name)), duration(duration)
{}
};
/**
* @brief Interface for managing boot time data storage for a single node.
*
* Defines the contract for storing checkpoints and durations, retrieving cached
* data, marking a boot cycle as complete, and checking the current reboot
* status.
*/
class IResource
{
public:
virtual ~IResource() = default;
/**
* @brief Records a boot checkpoint.
*
* @param name The name of the checkpoint.
* @param epochTime The wall clock time (epoch time in ms). If 0, current
* time is used.
* @param duration The self-measured duration (in ms). If non-zero, a
* ":BEGIN" checkpoint might be added.
*/
virtual void SetCheckpoint(std::string_view name, int64_t epochTime,
int64_t duration) = 0;
/**
* @brief Records a boot duration measurement.
*
* @param name The name of the duration measurement.
* @param duration The measured duration in milliseconds.
*/
virtual void SetDuration(std::string_view name, int64_t duration) = 0;
/**
* @brief Retrieves the cached list of checkpoints for the current or last
* completed boot.
*
* @return A vector of Checkpoint objects. Returns current boot data if
* IsRebooting() is true, otherwise returns data from the last completed
* boot.
*/
virtual std::vector<btm::resource::Checkpoint> GetCheckpointCache() = 0;
/**
* @brief Retrieves the cached list of durations for the current or last
* completed boot.
*
* @return A vector of Duration objects. Returns current boot data if
* IsRebooting() is true, otherwise returns data from the last completed
* boot.
*/
virtual std::vector<btm::resource::Duration> GetDurationCache() = 0;
/**
* @brief Marks the current boot cycle as complete.
* This typically involves finalizing storage (e.g., renaming files)
* and clearing current caches.
*/
virtual void MarkComplete() = 0;
/**
* @brief Checks if the node is currently considered to be in a reboot
* cycle.
*
* @return True if data is being actively recorded for the current boot,
* false otherwise.
*/
virtual bool IsRebooting() = 0;
};
/**
* @brief File-based implementation of the IResource interface.
*
* Stores checkpoint and duration data in separate CSV files per node.
* Manages current boot data and data from the last completed boot cycle.
* Provides caching for efficient retrieval.
*/
class File : public IResource
{
public:
/**
* @brief Constructs a File resource handler for a specific node.
*
* Initializes file streams and loads data from existing files (current and
* completed).
*
* @param nodeName The name of the node this resource belongs to.
*/
explicit File(std::string_view nodeName);
~File() override = default;
// Declare noncopyable
File(const File&) = delete;
File& operator=(const File&) = delete;
// Declare nonmoveable
File(File&&) = delete;
File& operator=(File&&) = delete;
/** @copydoc IResource::SetCheckpoint */
void SetCheckpoint(std::string_view name, int64_t epochTime,
int64_t duration) override;
/** @copydoc IResource::SetDuration */
void SetDuration(std::string_view name, int64_t duration) override;
/** @copydoc IResource::GetCheckpointCache */
std::vector<btm::resource::Checkpoint> GetCheckpointCache() override;
/** @copydoc IResource::GetDurationCache */
std::vector<btm::resource::Duration> GetDurationCache() override;
/** @copydoc IResource::MarkComplete */
void MarkComplete() override;
/** @copydoc IResource::IsRebooting */
bool IsRebooting() override;
private:
/** @brief Mutex protecting file access and cache modifications. */
std::mutex mFileMutex;
/** @brief The name of the node associated with this resource. */
std::string mNodeName;
/** @brief Output file stream for the current checkpoint file. */
std::ofstream mCpOfs;
/** @brief Output file stream for the current duration file. */
std::ofstream mDurOfs;
/** @brief Cache for checkpoints recorded during the current boot cycle. */
std::vector<btm::resource::Checkpoint> mCheckpointCache;
/** @brief Cache for checkpoints from the last completed boot cycle. */
std::vector<btm::resource::Checkpoint> mCheckpointCompletedCache;
/** @brief Cache for durations recorded during the current boot cycle. */
std::vector<btm::resource::Duration> mDurationCache;
/** @brief Cache for durations from the last completed boot cycle. */
std::vector<btm::resource::Duration> mDurationCompletedCache;
/**
* @brief Appends a checkpoint record to the current checkpoint file and
* cache.
* @param name Checkpoint name.
* @param wallTimeInMs Wall clock time (ms).
* @param monoTimeInMs Monotonic clock time (ms).
*/
void AppendCheckpointToFile(const std::string& name, int64_t wallTimeInMs,
int64_t monoTimeInMs);
/**
* @brief Appends a duration record to the current duration file and cache.
* @param name Duration name.
* @param durationInMs Duration value (ms).
*/
void AppendDurationToFile(const std::string& name, int64_t durationInMs);
/**
* @brief Opens or creates a file for appending and returns the stream.
* @param filename Full path to the file.
* @return std::ofstream The opened file stream.
* @throws std::invalid_argument if the stream cannot be opened.
*/
std::ofstream StartFileInstance(std::string_view filename);
/**
* @brief Finalizes a data file by closing it and renaming it with the
* ".complete" suffix. Reopens the original filename for the next boot.
* @param ofs The output stream to close and manage.
* @param filename The base filename (without suffix).
*/
void CompleteCurrentFile(std::ofstream& ofs, const std::string& filename);
/**
* @brief Checks if the file associated with the stream is currently empty.
* @param ofs The output stream to check.
* @return True if the file is empty, false otherwise.
* @throws std::runtime_error if `tellp` fails.
*/
bool IsEmptyFile(std::ofstream& ofs);
/**
* @brief Loads checkpoint data from a specified file (current or
* completed).
* @param loadComplete If true, loads from the ".complete" file; otherwise,
* loads from the current file.
* @return std::vector<btm::resource::Checkpoint> The loaded checkpoints.
*/
std::vector<btm::resource::Checkpoint> LoadCheckpoints(bool loadComplete);
/**
* @brief Loads duration data from a specified file (current or completed).
* @param loadComplete If true, loads from the ".complete" file; otherwise,
* loads from the current file.
* @return std::vector<btm::resource::Duration> The loaded durations.
*/
std::vector<btm::resource::Duration> LoadDurations(bool loadComplete);
/**
* @brief Gets the current system uptime in milliseconds from /proc/uptime.
* @return std::optional<int64_t> Uptime in ms, or std::nullopt if reading
* fails.
*/
static std::optional<int64_t> GetUpTimeInMs();
/** @brief Gets the current wall clock time (epoch) in milliseconds. */
static inline int64_t GetWallTimeInMs();
/** @brief Validates if a name contains only allowed characters
* ([0-9a-zA-Z_:]). */
static inline bool IsValidName(std::string_view name);
/** @brief Constructs the full path for the checkpoint file for this node.
*/
inline std::string GetCpFullFileName();
/** @brief Constructs the full path for the duration file for this node. */
inline std::string GetDurFullFileName();
};
} // namespace resource
} // namespace boot_time_monitor