| #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 |