/*! \file pibinarylog.h * \ingroup IO * \~\brief * \~english Binary log * \~russian Бинарный лог */ /* PIP - Platform Independent Primitives Class for write binary data to logfile, and read or playback this data Andrey Bychkov work.a.b@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIBINARYLOG_H #define PIBINARYLOG_H #include "pichunkstream.h" #include "pifile.h" //! \~english Class for writing and reading binary data to/from log files, with support for playback in different modes. //! \~russian Класс для записи и чтения бинарных данных в/из файлов логов с поддержкой воспроизведения в различных режимах. //! \~\details //! \~english The PIBinaryLog class provides functionality to write binary data to log files and read/playback data from them. It supports //! multiple play modes including real-time, variable speed, and static delay modes. The class also supports splitting log files by size, //! time, or record count. //! \~russian Класс PIBinaryLog предоставляет функциональность для записи бинарных данных в файлы логов и чтения/воспроизведения данных из. //! них. Он поддерживает несколько режимов воспроизведения, включая режим реального времени, режим переменной скорости и режим статической //! задержки. Класс также поддерживает разделение файлов логов по размеру, времени или количеству записей. class PIP_EXPORT PIBinaryLog: public PIIODevice { PIIODEVICE(PIBinaryLog, "binlog"); public: //! \~english Constructs %PIBinaryLog with default playback and split settings. //! \~russian Создает %PIBinaryLog со стандартными настройками воспроизведения и разделения файлов. explicit PIBinaryLog(); //! \~english Stops background activity and closes the current log. //! \~russian Останавливает фоновую активность и закрывает текущий лог. virtual ~PIBinaryLog(); //! \~english Playback modes used by \a PIBinaryLog. //! \~russian Режимы воспроизведения, используемые \a PIBinaryLog. enum PlayMode { PlayRealTime /*! \~english Playback follows record timestamps in real time, default mode \~russian Воспроизведение следует временным меткам записей в реальном времени, режим по умолчанию */ , PlayVariableSpeed /*! \~english Playback uses recorded timing scaled by \a setPlaySpeed() \~russian Воспроизведение использует записанные интервалы времени, масштабированные через \a setPlaySpeed() */ , PlayStaticDelay /*! \~english Playback uses fixed delay from \a setPlayDelay() and ignores record timestamps \~russian Воспроизведение использует фиксированную задержку из \a setPlayDelay() и игнорирует временные метки записей */ , }; //! \~english File splitting modes used while writing logs. //! \~russian Режимы разделения файлов, используемые при записи логов. enum SplitMode { SplitNone /*! \~english Do not split files, default mode \~russian Не разделять файлы, режим по умолчанию */, SplitTime /*! \~english Start a new file when elapsed record time exceeds configured limit \~russian Начинать новый файл, когда накопленное время записей превышает заданный предел */ , SplitSize /*! \~english Start a new file when file size exceeds configured limit \~russian Начинать новый файл, когда размер файла превышает заданный предел */ , SplitCount /*! \~english Start a new file when written record count exceeds configured limit \~russian Начинать новый файл, когда количество записанных записей превышает заданный предел */ , }; #pragma pack(push, 8) //! \~english Statistics for records sharing the same record ID. //! \~russian Статистика по записям с одинаковым идентификатором. struct PIP_EXPORT BinLogRecordInfo { //! \~english Constructs zero-initialized statistics. //! \~russian Создает статистику, инициализированную нулями. BinLogRecordInfo() { id = count = 0; minimum_size = maximum_size = 0; } //! \~english Unique identifier for this record type within the log file. //! \~russian Уникальный идентификатор для этого типа записи в файле лога. int id; //! \~english Total number of records with this ID in the log file. //! \~russian Общее количество записей с этим ID в файле лога. int count; //! \~english Size in bytes of the smallest record with this ID. //! \~russian Размер в байтах самой маленькой записи с этим ID. int minimum_size; //! \~english Size in bytes of the largest record with this ID. //! \~russian Размер в байтах самой большой записи с этим ID. int maximum_size; //! \~english Timestamp of the first record with this ID. //! \~russian Метка времени первой записи с этим ID. PISystemTime start_time; //! \~english Timestamp of the last record with this ID. //! \~russian Временная метка последней записи с этим идентификатором. PISystemTime end_time; }; //! \~english Indexed location of a record inside a log file. //! \~russian Индексированное положение записи внутри файла лога. //! \~\details //! \~english This structure provides direct access information for a single log record, including its position in the file, size, ID, //! and timestamp. //! \~russian Эта структура предоставляет информацию прямого доступа для одной записи лога, включая её позицию в файле, размер, ID и //! метку времени. struct PIP_EXPORT BinLogIndex { //! \~english Record ID. //! \~russian Идентификатор записи. int id; //! \~english Record payload size in bytes. //! \~russian Размер данных записи в байтах. int data_size; //! \~english Byte position of the record header in the file. //! \~russian Позиция заголовка записи в файле в байтах. llong pos; //! \~english Recorded timestamp. //! \~russian Сохраненная временная метка. PISystemTime timestamp; }; #pragma pack(pop) //! \~english Summary information about a log file and its indexed record types. //! \~russian Сводная информация о файле лога и его индексированных типах записей. //! \~\details //! \~english This structure provides comprehensive information about a binary log file, including file metadata, record statistics, and //! user-defined header data. //! \~russian Эта структура предоставляет исчерпывающую информацию о файле бинарного лога, включая метаданные файла, статистику записей //! и пользовательские данные заголовка. struct PIP_EXPORT BinLogInfo { //! \~english Path to the analyzed log file. //! \~russian Путь к анализируемому файлу лога. PIString path; //! \~english Total number of records in the file, or negative error code for invalid logs. //! \~russian Общее количество записей в файле или отрицательный код ошибки для некорректных логов. int records_count = 0; //! \~english File size in bytes. //! \~russian Размер файла в байтах. llong log_size = 0L; //! \~english Timestamp of the first record. //! \~russian Временная метка первой записи. PISystemTime start_time; //! \~english Timestamp of the last record. //! \~russian Временная метка последней записи. PISystemTime end_time; //! \~english Per-ID record statistics. //! \~russian Статистика записей по идентификаторам. PIMap records; //! \~english Custom user header stored in the file header. //! \~russian Пользовательский заголовок, сохраненный в заголовке файла. PIByteArray user_header; }; //! \~english Returns current \a PlayMode. //! \~russian Возвращает текущий \a PlayMode. PlayMode playMode() const { return play_mode; } //! \~english Returns current \a SplitMode. //! \~russian Возвращает текущий \a SplitMode. SplitMode splitMode() const { return split_mode; } //! \~english Returns directory used for new log files. //! \~russian Возвращает каталог, используемый для новых файлов лога. PIString logDir() const { return property("logDir").toString(); } //! \~english Returns filename prefix used for new log files. //! \~russian Возвращает префикс имени файла, используемый для новых файлов лога. PIString filePrefix() const { return property("filePrefix").toString(); } //! \~english Returns default record ID used by \a write(). //! \~russian Возвращает идентификатор записи по умолчанию, используемый \a write(). //! \~\return //! \~english The default record ID used when writing without explicitly specifying an ID. //! \~russian ID записи по умолчанию, используемый при записи без явного указания ID. int defaultID() const { return default_id; } //! \~english Returns current playback speed multiplier. //! \~russian Возвращает текущий множитель скорости воспроизведения. double playSpeed() const { return play_speed > 0 ? 1. / play_speed : 0.; } //! \~english Returns static delay used in \a PlayStaticDelay mode. //! \~russian Возвращает фиксированную задержку, используемую в режиме \a PlayStaticDelay. PISystemTime playDelay() const { return play_delay; } //! \~english Returns elapsed-time threshold for \a SplitTime mode. //! \~russian Возвращает порог накопленного времени для режима \a SplitTime. //! \~\return //! \~english The time interval used for splitting log files in SplitTime mode. //! \~russian Временной интервал, используемый для разделения файлов логов в режиме SplitTime. PISystemTime splitTime() const { return split_time; } //! \~english Returns size threshold for \a SplitSize mode. //! \~russian Возвращает порог размера для режима \a SplitSize. //! \~\return //! \~english The maximum file size in bytes for splitting log files in SplitSize mode. //! \~russian Максимальный размер файла в байтах для разделения файлов логов в режиме SplitSize. llong splitFileSize() const { return split_size; } //! \~english Returns record-count threshold for \a SplitCount mode. //! \~russian Возвращает порог количества записей для режима \a SplitCount. //! \~\return //! \~english The maximum number of records per file for splitting log files in SplitCount mode. //! \~russian Максимальное количество записей на файл для разделения файлов логов в режиме SplitCount. int splitRecordCount() const { return split_count; } //! \~english Returns whether the first threaded-read record is emitted without initial delay. //! \~russian Возвращает, выдается ли первая запись потокового чтения без начальной задержки. bool rapidStart() const { return rapid_start; } //! \~english Returns whether index data is collected while writing. //! \~russian Возвращает, собираются ли данные индекса во время записи. //! \~\return //! \~english true if index is created on-the-fly during writing, false otherwise. //! \~russian true, если индекс создается "на лету" во время записи, иначе false. bool createIndexOnFly() const { return create_index_on_fly; } //! \~english Creates or reopens a log file at exact path "path" for writing. //! \~russian Создает или повторно открывает файл лога по точному пути "path" для записи. //! \~\details //! \~english Creates a new binary log file at the specified path. If a file already exists, it will be overwritten. //! \~russian Создает новый файл бинарного лога по указанному пути. Если файл уже существует, он будет перезаписан. void createNewFile(const PIString & path); //! \~english Sets current \a PlayMode. //! \~russian Устанавливает текущий \a PlayMode. void setPlayMode(PlayMode mode) { setProperty("playMode", (int)mode); } //! \~english Sets current \a SplitMode. //! \~russian Устанавливает текущий \a SplitMode. void setSplitMode(SplitMode mode) { setProperty("splitMode", (int)mode); } //! \~english Sets directory used for newly created log files. //! \~russian Устанавливает каталог, используемый для вновь создаваемых файлов лога. void setLogDir(const PIString & path) { setProperty("logDir", path); } //! \~english Sets filename prefix used for newly created log files. //! \~russian Устанавливает префикс имени файла для вновь создаваемых файлов лога. //! \~\details //! \~english Sets the filename prefix used when generating log file names. Combined with the log directory and timestamp to create //! unique filenames. //! \~russian Устанавливает префикс имени файла, используемый при генерации имен файлов логов. Объединяется с каталогом логов и //! временной меткой для создания уникальных имен файлов. //! \~\param prefix //! \~english The filename prefix. //! \~russian Префикс имени файла. void setFilePrefix(const PIString & prefix) { setProperty("filePrefix", prefix); } //! \~english Sets default record ID used by \a write(). //! \~russian Устанавливает идентификатор записи по умолчанию, используемый \a write(). //! \~\details //! \~english Sets the default record ID used when calling write without specifying an ID. //! \~russian Устанавливает ID записи по умолчанию, используемый при вызове write без указания ID. //! \~\param id //! \~english The default record ID. Must be greater than 0. //! \~russian ID записи по умолчанию. Должен быть больше 0. void setDefaultID(int id) { setProperty("defaultID", id); } //! \~english Enables immediate delivery of the first record in threaded playback. //! \~russian Включает немедленную выдачу первой записи при потоковом воспроизведении. //! \~\details //! \~english When enabled, the first record is read immediately at the start of playback without waiting for its timestamp. This //! reduces initial latency. //! \~russian При включении первая запись читается немедленно при запуске воспроизведения без ожидания её метки времени. Это уменьшает //! начальную задержку. //! \~\param enabled //! \~english true to enable rapid start, false to disable. //! \~russian true для включения быстрого старта, false для отключения. void setRapidStart(bool enabled) { setProperty("rapidStart", enabled); } //! \~english Enables or disables index collection while writing. //! \~russian Включает или выключает сбор индекса во время записи. //! \~\details //! \~english Enables or disables automatic index creation during the writing process. When enabled, the index is built incrementally as //! data is written. //! \~russian Включает или отключает автоматическое создание индекса в процессе записи. При включении индекс строится по мере записи //! данных. //! \~\param yes //! \~english true to enable on-the-fly index creation, false to disable. //! \~russian true для включения создания индекса "на лету", false для отключения. void setCreateIndexOnFly(bool yes); //! \~english Sets playback speed multiplier and switches mode to \a PlayVariableSpeed. //! \~russian Устанавливает множитель скорости воспроизведения и переключает режим в \a PlayVariableSpeed. //! \~\details //! \~english Sets the playback speed multiplier. A value of 1.0 means real-time playback. Values greater than 1.0 speed up playback, //! while values between 0 and 1.0 slow it down. //! \~russian Устанавливает множитель скорости воспроизведения. Значение 1.0 означает воспроизведение в реальном времени. Значения //! больше 1.0 ускоряют воспроизведение, а значения между 0 и 1.0 замедляют его. //! \~\note //! \~english This function automatically sets the play mode to \a PlayVariableSpeed. //! \~russian Эта функция автоматически устанавливает режим воспроизведения в \a PlayVariableSpeed. //! \~\param speed //! \~english The playback speed multiplier. //! \~russian Множитель скорости воспроизведения. void setPlaySpeed(double speed) { setPlayMode(PlayVariableSpeed); setProperty("playSpeed", speed); } //! \~english Sets fixed delay between records and switches mode to \a PlayStaticDelay. //! \~russian Устанавливает фиксированную задержку между записями и переключает режим в \a PlayStaticDelay. //! \~\details //! \~english Sets a fixed delay between records during playback, ignoring the original timestamps in the log file. //! \~russian Устанавливает фиксированную задержку между записями во время воспроизведения, игнорируя исходные метки времени в файле //! лога. //! \~\note //! \~english This function automatically sets the play mode to \a PlayStaticDelay. //! \~russian Эта функция автоматически устанавливает режим воспроизведения в \a PlayStaticDelay. //! \~\param delay //! \~english The static delay between records. //! \~russian Статическая задержка между записями. void setPlayDelay(const PISystemTime & delay) { setPlayMode(PlayStaticDelay); setProperty("playDelay", delay); } //! \~english Switches playback to \a PlayRealTime. //! \~russian Переключает воспроизведение в режим \a PlayRealTime. //! \~\details //! \~english Sets the playback mode to real-time, where records are played at their original timestamps. //! \~russian Устанавливает режим воспроизведения в реальное время, где записи воспроизводятся по их исходным меткам времени. void setPlayRealTime() { setPlayMode(PlayRealTime); } //! \~english Sets time threshold for file splitting and switches mode to \a SplitTime. //! \~russian Устанавливает порог времени для разделения файлов и переключает режим в \a SplitTime. //! \~\details //! \~english Sets the time interval for splitting log files. When the time difference between records exceeds this value, a new file is //! created. //! \~russian Устанавливает временной интервал для разделения файлов логов. Когда разница во времени между записями превышает это //! значение, создается новый файл. //! \~\note //! \~english This function automatically sets the split mode to \a SplitTime. //! \~russian Эта функция автоматически устанавливает режим разделения в \a SplitTime. //! \~\param time //! \~english The time interval for splitting files. //! \~russian Временной интервал для разделения файлов. void setSplitTime(const PISystemTime & time) { setSplitMode(SplitTime); setProperty("splitTime", time); } //! \~english Sets size threshold for file splitting and switches mode to \a SplitSize. //! \~russian Устанавливает порог размера для разделения файлов и переключает режим в \a SplitSize. //! \~\details //! \~english Sets the maximum file size in bytes for splitting log files. When a file reaches this size, a new file is created. //! \~russian Устанавливает максимальный размер файла в байтах для разделения файлов логов. Когда файл достигает этого размера, //! создается новый файл. //! \~\note //! \~english This function automatically sets the split mode to \a SplitSize. //! \~russian Эта функция автоматически устанавливает режим разделения в \a SplitSize. //! \~\param size //! \~english The maximum file size in bytes. //! \~russian Максимальный размер файла в байтах. void setSplitFileSize(llong size) { setSplitMode(SplitSize); setProperty("splitFileSize", size); } //! \~english Sets record-count threshold for file splitting and switches mode to \a SplitCount. //! \~russian Устанавливает порог количества записей для разделения файлов и переключает режим в \a SplitCount. //! \~\details //! \~english Sets the maximum number of records per file for splitting log files. When a file reaches this record count, a new file is //! created. //! \~russian Устанавливает максимальное количество записей на файл для разделения файлов логов. Когда файл достигает этого количества //! записей, создается новый файл. //! \~\note //! \~english This function automatically sets the split mode to \a SplitCount. //! \~russian Эта функция автоматически устанавливает режим разделения в \a SplitCount. //! \~\param count //! \~english The maximum number of records per file. //! \~russian Максимальное количество записей на файл. void setSplitRecordCount(int count) { setSplitMode(SplitCount); setProperty("splitRecordCount", count); } //! \~english Pauses or resumes threaded playback and direct writes. //! \~russian Ставит на паузу или возобновляет потоковое воспроизведение и прямую запись. void setPause(bool pause); //! \~english Sets custom path generator used for split files and implicit file creation. //! \~russian Устанавливает пользовательский генератор путей, используемый для разделяемых файлов и неявного создания файла. //! \~\details //! \~english Sets a custom callback function that returns the path for the next log file when using split mode. This overrides the //! internal path generator (logdir() + prefix() + current_time()). To restore the internal generator, set this function to nullptr. //! \~russian Устанавливает пользовательскую функцию обратного вызова, возвращающую путь к следующему файлу лога при использовании //! режима разделения. Это переопределяет внутренний генератор путей (logdir() + prefix() + current_time()). Для восстановления //! внутреннего генератора установите эту функцию в nullptr. //! \~\param f //! \~english The callback function returning the next file path, or nullptr to use the internal generator. //! \~russian Функция обратного вызова, возвращающая путь к следующему файлу, или nullptr для использования внутреннего генератора. void setFuncGetNewFilePath(std::function f) { f_new_path = std::move(f); } //! \~english Writes one record with explicit ID and payload. //! \~russian Записывает одну запись с явным идентификатором и данными. //! \~\details //! \~english Writes a single record to the binary log file with the specified ID and data. //! \~russian Записывает одну запись в файл бинарного лога с указанным ID и данными. //! \~\param id //! \~english The record ID. Must be greater than 0. //! \~russian ID записи. Должен быть больше 0. //! \~\param data //! \~english The data to write. //! \~russian Данные для записи. //! \~\return //! \~english Data size on success, negative value on error. //! \~russian Размер данных data в случае успеха, отрицательное значение в случае ошибки. int writeBinLog(int id, PIByteArray data) { return writeBinLog(id, data.data(), data.size_s()); } //! \~english Writes one record with explicit ID and payload buffer. //! \~russian Записывает одну запись с явным идентификатором и буфером данных. //! \~\details //! \~english Returns written payload size, \c 0 while paused, or negative value on error. ID must be greater than zero. //! \~russian Возвращает размер записанных данных, \c 0 во время паузы или отрицательное значение при ошибке. Идентификатор должен быть //! больше нуля. int writeBinLog(int id, const void * data, int size); //! \~english Write one RAW record to BinLog file, with ID = id, Timestamp = time //! \~russian Записать один НЕОБРАБОТАННЫЙ (RAW) запись в файл BinLog, с ID = id, Метка времени = time //! \~\details //! \~english Writes a single record with an explicit timestamp to the binary log file. The timestamp is stored as-is, without //! modification. //! \~russian Записывает одну запись с явной меткой времени в файл бинарного лога. Метка времени сохраняется как есть, без модификации. //! \~\param id //! \~english The record ID. Must be greater than 0. //! \~russian ID записи. Должен быть больше 0. //! \~\param time //! \~english The timestamp to associate with this record. //! \~russian Метка времени, связанная с этой записью. //! \~\param data //! \~english The data to write. //! \~russian Данные для записи. //! \~\return //! \~english 0 on success, negative value on error. //! \~russian 0 в случае успеха, отрицательное значение в случае ошибки. int writeBinLog_raw(int id, const PISystemTime & time, const PIByteArray & data) { return writeBinLog_raw(id, time, data.data(), data.size_s()); } //! \~english Write one RAW record to BinLog file, with ID = id, Timestamp = time //! \~russian Записать один НЕОБРАБОТАННЫЙ (RAW) запись в файл BinLog, с ID = id, Метка времени = time //! \~\details //! \~english Writes a single record with an explicit timestamp to the binary log file. The timestamp is stored as-is, without //! modification. //! \~russian Записывает одну запись с явной меткой времени в файл бинарного лога. Метка времени сохраняется как есть, без модификации. //! \~\param id //! \~english The record ID. Must be greater than 0. //! \~russian ID записи. Должен быть больше 0. //! \~\param time //! \~english The timestamp to associate with this record. //! \~russian Метка времени, связанная с этой записью. //! \~\param data //! \~english Pointer to the data to write. //! \~russian Указатель на данные для записи. //! \~\param size //! \~english Size of the data in bytes. //! \~russian Размер данных в байтах. //! \~\return //! \~english 0 on success, negative value on error. //! \~russian 0 в случае успеха, отрицательное значение в случае ошибки. int writeBinLog_raw(int id, const PISystemTime & time, const void * data, int size); //! \~english Returns number of records successfully written in current session. //! \~russian Возвращает количество записей, успешно записанных в текущей сессии. int writeCount() const { return write_count; } //! \~english Read one record from BinLog file, with ID = id, if id = 0 than any id will be readed //! \~russian Прочитать одну запись из файла BinLog, с ID = id, если id = 0, то будет прочитана любая запись //! \~\details //! \~english Reads a single record from the binary log file. If id is 0, records of any ID can be read. Returns the record data as a //! byte array. //! \~russian Читает одну запись из файла бинарного лога. Если id равен 0, могут быть прочитаны записи любого ID. Возвращает данные //! записи как массив байт. //! \~\param id //! \~english The record ID to read, or 0 to read any record. //! \~russian ID записи для чтения, или 0 для чтения любой записи. //! \~\param time //! \~english Optional pointer to store the record's timestamp. //! \~russian Необязательный указатель для сохранения метки времени записи. //! \~\param readed_id //! \~english Optional pointer to store the record's ID. //! \~russian Необязательный указатель для сохранения ID записи. //! \~\return //! \~english The record data as a byte array. //! \~russian Данные записи как массив байт. PIByteArray readBinLog(int id = 0, PISystemTime * time = 0, int * readed_id = 0); //! \~english Read one record from BinLog file, with ID = id, if id = 0 than any id will be readed //! \~russian Прочитать одну запись из файла BinLog, с ID = id, если id = 0 чем любая запись будет прочитана //! \~\details //! \~english Reads a single record from the binary log file into a user-provided buffer. If id is 0, records of any ID can be read. //! \~russian Читает одну запись из файла бинарного лога в пользовательский буфер. Если id равен 0, могут быть прочитаны записи любого //! ID. //! \~\param id //! \~english The record ID to read, or 0 to read any record. //! \~russian ID записи для чтения, или 0 для чтения любой записи. //! \~\param read_to //! \~english Pointer to the buffer where the record data will be stored. //! \~russian Указатель на буфер, куда будут сохранены данные записи. //! \~\param max_size //! \~english Maximum size of the buffer in bytes. //! \~russian Максимальный размер буфера в байтах. //! \~\param time //! \~english Optional pointer to store the record's timestamp. //! \~russian Необязательный указатель для сохранения метки времени записи. //! \~\param readed_id //! \~english Optional pointer to store the record's ID. //! \~russian Необязательный указатель для сохранения ID записи. //! \~\return //! \~english The actual number of bytes read, or negative value on error. //! \~russian Фактическое количество прочитанных байт, или отрицательное значение в случае ошибки. int readBinLog(int id, void * read_to, int max_size, PISystemTime * time = 0, int * readed_id = 0); //! \~english Returns current log file size in bytes. //! \~russian Возвращает текущий размер файла лога в байтах. llong logSize() const { return log_size; } //! \~english Returns current byte position in the opened log file. //! \~russian Возвращает текущую позицию в байтах в открытом файле лога. llong logPos() const { return file.pos(); } //! \~english Returns \b true when reading position is at end of file or the log is closed. //! \~russian Возвращает \b true, когда позиция чтения находится в конце файла или лог закрыт. bool isEnd() const { if (isClosed()) return true; return file.isEnd(); } //! \~english Returns whether the log contains no records beyond the file header. //! \~russian Возвращает, не содержит ли лог записей сверх заголовка файла. bool isEmpty() const; //! \~english Returns current pause state. //! \~russian Возвращает текущее состояние паузы. bool isPause() const { return is_pause; } //! \~english Returns ID of the last record read from the file. //! \~russian Возвращает идентификатор последней записи, прочитанной из файла. int lastReadedID() const { return lastrecord.id; } //! \~english Returns timestamp of the last record read from the file. //! \~russian Возвращает временную метку последней записи, прочитанной из файла. PISystemTime lastReadedTimestamp() const { return lastrecord.timestamp; } //! \~english Returns session start timestamp used for playback timing. //! \~russian Возвращает временную метку начала сессии, используемую для тайминга воспроизведения. PISystemTime logStartTimestamp() const { return startlogtime; } //! \~english Sets custom file header for subsequently created log files. //! \~russian Устанавливает пользовательский заголовок файла для последовательно создаваемых логов. //! \~\details //! \~english Sets custom header data that will be written to the log file and can be retrieved later using getHeader(). //! \~russian Устанавливает пользовательские данные заголовка, которые будут записаны в файл лога и могут быть получены позже с помощью //! getHeader(). //! \~\param header //! \~english The custom header data to write. //! \~russian Пользовательские данные заголовка для записи. void setHeader(const PIByteArray & header); //! \~english Returns custom header stored in the currently opened log. //! \~russian Возвращает пользовательский заголовок, сохраненный в текущем открытом логе. PIByteArray getHeader() const; #ifdef DOXYGEN //! \~english Reads one message using \a filterID when it is not empty. //! \~russian Читает одно сообщение, используя \a filterID, если он не пуст. int read(void * read_to, int max_size); //! \~english Writes one record using \a defaultID(). //! \~russian Записывает одну запись, используя \a defaultID(). int write(const void * data, int size); #endif //! \~english Optional list of record IDs accepted by \a read() and threaded playback. //! \~russian Необязательный список идентификаторов записей, допустимых для \a read() и потокового воспроизведения. //! \~\details //! \~english A list of record IDs to filter when reading. Only records with these IDs will be read. Empty list means all IDs are read. //! \~russian Список ID записей для фильтрации при чтении. Будут прочитаны только записи с этими ID. Пустой список означает чтение всех //! ID. PIVector filterID; //! \~english Restarts reading and playback from the beginning of the current log. //! \~russian Перезапускает чтение и воспроизведение с начала текущего лога. void restart(); //! \~english Returns cached index info when available, otherwise reparses current file info. //! \~russian Возвращает кэшированную информацию индекса, если она есть, иначе заново разбирает информацию текущего файла. //! \~\return //! \~english A \a BinLogInfo structure containing comprehensive information about the log file. //! \~russian Структура \a BinLogInfo, содержащая исчерпывающую информацию о файле лога. BinLogInfo logInfo() const { if (is_indexed) return index.info; return getLogInfo(path()); } //! \~english Returns current record index data. //! \~russian Возвращает текущие данные индекса записей. //! \~\details //! \~english Meaningful data appears after \a createIndex(), \a loadIndex() or indexed writing. //! \~russian Осмысленные данные появляются после \a createIndex(), \a loadIndex() или записи с активным индексированием. const PIVector & logIndex() const { return index.index; } //! \~english Builds record index for the current log file. //! \~russian Строит индекс записей для текущего файла лога. //! \~\details //! \~english Builds an index of the log file for fast random access to records. The index stores position, ID, and timestamp for each //! record. //! \~russian Строит индекс файла лога для быстрого случайного доступа к записям. Индекс хранит позицию, ID и метку времени для каждой //! записи. //! \~\return //! \~english true if index creation was successful, false otherwise. //! \~russian true, если создание индекса прошло успешно, иначе false. bool createIndex(); //! \~english Returns whether the current log has loaded index data. //! \~russian Возвращает, имеет ли текущий лог загруженные данные индекса. bool isIndexed() { return is_indexed; } //! \~english Returns index of the first indexed record at or after "time". //! \~russian Возвращает индекс первой индексированной записи в момент "time" или позже. //! \~\details //! \~english Finds the index of the record with the timestamp closest to the specified time. Requires the file to be indexed first. //! \~russian Находит индекс записи с меткой времени, ближайшей к указанному времени. Требует, чтобы файл был проиндексирован заранее. //! \~\param time //! \~english The target timestamp to find. //! \~russian Целевая метка времени для поиска. //! \~\return //! \~english The index of the nearest record, or -1 if not indexed or the time is before the first record. //! \~russian Индекс ближайшей записи, или -1, если не проиндексировано или время раньше первой записи. int posForTime(const PISystemTime & time); //! \~english Seeks to indexed record number "rindex". //! \~russian Переходит к индексированной записи номер "rindex". //! \~\details //! \~english Seeks to a specific record by its index position in the log file. //! \~russian Переходит к конкретной записи по её индексу в файле лога. //! \~\param rindex //! \~english The index of the record to seek to. //! \~russian Индекс записи, к которой нужно перейти. void seekTo(int rindex); //! \~english Seeks to the first indexed record at or after "time". //! \~russian Переходит к первой индексированной записи в момент "time" или позже. //! \~\details //! \~english Seeks to the record with the timestamp closest to the specified time. Requires the file to be indexed first. //! \~russian Переходит к записи с меткой времени, ближайшей к указанному времени. Требует, чтобы файл был проиндексирован заранее. //! \~\param time //! \~english The target timestamp to seek to. //! \~russian Целевая метка времени для перехода. //! \~\return //! \~english true if the seek was successful, false otherwise. //! \~russian true, если переход прошел успешно, иначе false. bool seek(const PISystemTime & time); //! \~english Seeks to the first indexed record whose file position is at or after "filepos". //! \~russian Переходит к первой индексированной записи, чья позиция в файле находится в точке "filepos" или позже. //! \~\details //! \~english Seeks to a specific byte position in the log file for reading or playing. //! \~russian Переходит к конкретной байтовой позиции в файле лога для чтения или воспроизведения. //! \~\param filepos //! \~english The byte position in the file. //! \~russian Позиция в байтах в файле. //! \~\return //! \~english true if the seek was successful, false otherwise. //! \~russian true, если переход прошел успешно, иначе false. bool seek(llong filepos); //! \~english Returns current indexed record position, or -1 when not indexed. //! \~russian Возвращает текущую позицию индексированной записи или -1, если индекс отсутствует. int pos() const; //! \~english Serializes current index data. //! \~russian Сериализует текущие данные индекса. PIByteArray saveIndex() const; //! \~english Loads previously serialized index data for the current readable log. //! \~russian Загружает ранее сериализованные данные индекса для текущего читаемого лога. //! \~\details //! \~english Loads an index that was previously saved with saveIndex(). The file must be opened before loading the index. //! \~russian Загружает индекс, который был ранее сохранен с помощью saveIndex(). Файл должен быть открыт перед загрузкой индекса. //! \~\param saved //! \~english The serialized index data to load. //! \~russian Сериализованные данные индекса для загрузки. //! \~\return //! \~english true if the index was loaded successfully, false otherwise. //! \~russian true, если индекс был загружен успешно, иначе false. bool loadIndex(PIByteArray saved); //! \handlers //! \{ //! \fn PIString createNewFile() //! \~english Creates a new log file in \a logDir() and returns its path, or empty string on failure. //! \~russian Создает новый файл лога в \a logDir() и возвращает его путь или пустую строку при ошибке. //! \~\details //! \~english Default filenames look like \a filePrefix() + "yyyy_MM_dd__hh_mm_ss.binlog". //! \~russian Имена файлов по умолчанию имеют вид \a filePrefix() + "yyyy_MM_dd__hh_mm_ss.binlog". EVENT_HANDLER(PIString, createNewFile); //! \} //! \events //! \{ //! \fn void fileEnd() //! \~english Raised when reading reaches the end of file. //! \~russian Вызывается, когда чтение достигает конца файла. EVENT(fileEnd); //! \fn void fileError() //! \~english Raised when file header validation or file creation fails. //! \~russian Вызывается при ошибке проверки заголовка файла или создания файла. EVENT(fileError); //! \fn void newFile(const PIString & filename) //! \~english Raised after a new log file is successfully created. //! \~russian Вызывается после успешного создания нового файла лога. EVENT1(newFile, const PIString &, filename); //! \fn void posChanged(int pos) //! \~english Raised when current indexed playback position changes. //! \~russian Вызывается при изменении текущей индексированной позиции воспроизведения. EVENT1(posChanged, int, pos); //! \fn void threadedReadRecord(PIByteArray data, int id, PISystemTime time) //! \~english Raised after threaded playback emits one record. //! \~russian Вызывается после выдачи одной записи потоковым воспроизведением. EVENT3(threadedReadRecord, PIByteArray, data, int, id, PISystemTime, time); //! \} //! \~english Get binlog info and statistic //! \~russian Получить информацию и статистику о бинарном логе //! \~\details //! \~english Parses the specified log file and returns comprehensive information including record statistics, file size, and time //! range. This is a static method that can be called without an instance. //! \~russian Анализирует указанный файл лога и возвращает исчерпывающую информацию, включая статистику записей, размер файла и //! временной диапазон. Это статический метод, который можно вызывать без экземпляра. //! \~\param path //! \~english The path to the log file to analyze. //! \~russian Путь к анализируемому файлу лога. //! \~\return //! \~english A \a BinLogInfo structure containing the file information and statistics. //! \~russian Структура \a BinLogInfo, содержащая информацию о файле и статистику. static BinLogInfo getLogInfo(const PIString & path); //! \~english Create new binlog from part of "src" with allowed IDs and "from" to "to" file position //! \~russian Создать новый бинарный лог из части "src" с разрешенными ID и от "from" до "to" позиции файла //! \~\details //! \~english Creates a new log file by extracting records from the source log between the specified file positions. Only records within //! the specified ID filter range are included. //! \~russian Создает новый файл лога путем извлечения записей из исходного лога между указанными позициями файла. Включаются только //! записи в пределах указанного диапазона ID фильтра. //! \~\param src //! \~english The source log information containing the path and metadata. //! \~russian Информация об исходном логе, содержащая путь и метаданные. //! \~\param dst //! \~english The path where the new log file will be created. //! \~russian Путь, где будет создан новый файл лога. //! \~\param from //! \~english The starting file position (inclusive). //! \~russian Начальная позиция файла (включительно). //! \~\param to //! \~english The ending file position (exclusive). //! \~russian Конечная позиция файла (исключительно). //! \~\return //! \~english true if the cut operation was successful, false otherwise. //! \~russian true, если операция вырезания прошла успешно, иначе false. static bool cutBinLog(const BinLogInfo & src, const PIString & dst, int from, int to); //! \~english Create new binlog from serial splitted binlogs "src" //! \~russian Создать новый бинарный лог из последовательных разделенных бинарных логов "src" //! \~\details //! \~english Concatenates multiple split log files into a single log file. The source files should be in chronological order. An //! optional progress callback can be provided to track the operation. //! \~russian Конкатенирует несколько разделенных файлов логов в один файл лога. Исходные файлы должны быть в хронологическом порядке. //! Можно предоставить необязательный обратный вызов прогресса для отслеживания операции. //! \~\param src //! \~english List of source log file paths to join. //! \~russian Список путей к исходным файлам лога для объединения. //! \~\param dst //! \~english The path where the combined log file will be created. //! \~russian Путь, где будет создан объединенный файл лога. //! \~\param progress //! \~english Optional callback function that receives the current file path and timestamp, returning true to continue or false to //! cancel. //! \~russian Необязательная функция обратного вызова, получающая текущий путь к файлу и метку времени, возвращающая true для //! продолжения или false для отмены. //! \~\return //! \~english true if the join operation was successful, false otherwise. //! \~russian true, если операция объединения прошла успешно, иначе false. static bool joinBinLogsSerial(const PIStringList & src, const PIString & dst, std::function progress = nullptr); protected: //! \~english Construct full device path //! \~russian Создать полный путь устройства PIString constructFullPathDevice() const override; //! \~english Configure from full device path //! \~russian Настроить из полного пути устройства void configureFromFullPathDevice(const PIString & full_path) override; //! \~english Construct variant device properties //! \~russian Создать свойства устройства варианта PIPropertyStorage constructVariantDevice() const override; //! \~english Configure from variant device properties //! \~russian Настроить из свойств устройства варианта void configureFromVariantDevice(const PIPropertyStorage & d) override; //! \~english Read from device //! \~russian Чтение из устройства ssize_t readDevice(void * read_to, ssize_t max_size) override; //! \~english Write to device //! \~russian Запись в устройство ssize_t writeDevice(const void * data, ssize_t size) override; //! \~english Open device //! \~russian Открыть устройство bool openDevice() override; //! \~english Close device //! \~russian Закрыть устройство bool closeDevice() override; //! \~english Property changed callback //! \~russian Обратный вызов изменения свойства void propertyChanged(const char * s) override; //! \~english Threaded read callback //! \~russian Обратный вызов потокового чтения bool threadedRead(const uchar * readed, ssize_t size) override; //! \~english Get device information flags //! \~russian Получить флаги информации об устройстве DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; } private: struct Record { int id; int size; PISystemTime timestamp; PIByteArray data; }; struct CompleteIndex { void clear(); void makeIndexPos(); BinLogInfo info; PIVector index; PIMap index_pos; }; BINARY_STREAM_FRIEND(CompleteIndex) bool writeFileHeader(); bool checkFileHeader(); Record readRecord(); int writeRecord(int id, PISystemTime time, const void * data, int size); static void parseLog(PIFile * f, BinLogInfo * info, PIVector * index); void moveIndex(int i); static PIString getLogfilePath(const PIString & log_dir, const PIString & prefix); CompleteIndex index; PlayMode play_mode; SplitMode split_mode; PIFile file; Record lastrecord; PISystemTime startlogtime, play_delay, split_time, pause_time; mutable PIMutex logmutex, pausemutex; double play_time, play_speed; llong split_size, log_size; int write_count, split_count, default_id, current_index; bool is_started, is_thread_ok, is_indexed, rapid_start, is_pause, create_index_on_fly; PIByteArray user_header; std::function f_new_path; }; BINARY_STREAM_WRITE(PIBinaryLog::BinLogInfo) { PIChunkStream cs; cs.add(1, v.path) .add(2, v.records_count) .add(3, v.log_size) .add(4, v.start_time) .add(5, v.end_time) .add(6, v.records) .add(7, v.user_header); s << cs.data(); return s; } BINARY_STREAM_READ(PIBinaryLog::BinLogInfo) { PIByteArray csba; s >> csba; PIChunkStream cs(csba); while (!cs.atEnd()) { switch (cs.read()) { case 1: cs.get(v.path); break; case 2: cs.get(v.records_count); break; case 3: cs.get(v.log_size); break; case 4: cs.get(v.start_time); break; case 5: cs.get(v.end_time); break; case 6: cs.get(v.records); break; case 7: cs.get(v.user_header); break; } } return s; } BINARY_STREAM_WRITE(PIBinaryLog::CompleteIndex) { s << v.info << v.index; return s; } BINARY_STREAM_READ(PIBinaryLog::CompleteIndex) { s >> v.info >> v.index; return s; } //! \relatesalso PICout //! \~english Writes \a PIBinaryLog::BinLogInfo summary to \a PICout. //! \~russian Выводит сводку \a PIBinaryLog::BinLogInfo в \a PICout. inline PICout operator<<(PICout s, const PIBinaryLog::BinLogInfo & bi) { s.space(); s.saveAndSetControls(0); s << "[PIBinaryLog] " << bi.path << "\n"; if (bi.log_size < 0) { s << "invalid file path"; s.restoreControls(); return s; } if (bi.log_size == 0) { s << "Invalid empty file"; s.restoreControls(); return s; } if (bi.records_count < 0 && bi.records_count > -4) { s << "Invalid file or corrupted signature"; s.restoreControls(); return s; } if (bi.records_count < -3) { s << "Invalid binlog version"; s.restoreControls(); return s; } s << "read records " << bi.records_count << " in " << bi.records.size() << " types, log size " << bi.log_size; s << "\nlog start " << bi.start_time << " , log end " << bi.end_time; const auto keys = bi.records.keys(); for (int i: keys) { const auto & bri(bi.records.at(i)); s << "\n record id " << bri.id << " , count " << bri.count; s << "\n record start " << bri.start_time << " , end " << bri.end_time; s << "\n record size " << bri.minimum_size << " - " << bri.maximum_size; } s.restoreControls(); return s; } #endif // PIBINARYLOG_H