610 lines
32 KiB
C++
610 lines
32 KiB
C++
/*! \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 <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#ifndef PIBINARYLOG_H
|
||
#define PIBINARYLOG_H
|
||
|
||
#include "pichunkstream.h"
|
||
#include "pifile.h"
|
||
|
||
//! \ingroup IO
|
||
//! \~\brief
|
||
//! \~english Binary log device for recording and timed playback of binary records.
|
||
//! \~russian Устройство бинарного лога для записи и воспроизведения бинарных записей по времени.
|
||
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 Record ID described by this entry.
|
||
//! \~russian Идентификатор записи, описываемый этой структурой.
|
||
int id;
|
||
//! \~english Number of records with this ID.
|
||
//! \~russian Количество записей с этим идентификатором.
|
||
int count;
|
||
//! \~english Minimum payload size among records with this ID.
|
||
//! \~russian Минимальный размер данных среди записей с этим идентификатором.
|
||
int minimum_size;
|
||
//! \~english Maximum payload size among records with this ID.
|
||
//! \~russian Максимальный размер данных среди записей с этим идентификатором.
|
||
int maximum_size;
|
||
//! \~english Timestamp of the first record with this ID.
|
||
//! \~russian Временная метка первой записи с этим идентификатором.
|
||
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 Индексированное положение записи внутри файла лога.
|
||
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 Сводная информация о файле лога и его индексированных типах записей.
|
||
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<int, BinLogRecordInfo> 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().
|
||
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.
|
||
PISystemTime splitTime() const { return split_time; }
|
||
|
||
//! \~english Returns size threshold for \a SplitSize mode.
|
||
//! \~russian Возвращает порог размера для режима \a SplitSize.
|
||
llong splitFileSize() const { return split_size; }
|
||
|
||
//! \~english Returns record-count threshold for \a SplitCount mode.
|
||
//! \~russian Возвращает порог количества записей для режима \a 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 Возвращает, собираются ли данные индекса во время записи.
|
||
bool createIndexOnFly() const { return create_index_on_fly; }
|
||
|
||
//! \~english Creates or reopens a log file at exact path "path" for writing.
|
||
//! \~russian Создает или повторно открывает файл лога по точному пути "path" для записи.
|
||
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 Устанавливает префикс имени файла для вновь создаваемых файлов лога.
|
||
void setFilePrefix(const PIString & prefix) { setProperty("filePrefix", prefix); }
|
||
|
||
//! \~english Sets default record ID used by \a write().
|
||
//! \~russian Устанавливает идентификатор записи по умолчанию, используемый \a write().
|
||
void setDefaultID(int id) { setProperty("defaultID", id); }
|
||
|
||
//! \~english Enables immediate delivery of the first record in threaded playback.
|
||
//! \~russian Включает немедленную выдачу первой записи при потоковом воспроизведении.
|
||
void setRapidStart(bool enabled) { setProperty("rapidStart", enabled); }
|
||
|
||
//! \~english Enables or disables index collection while writing.
|
||
//! \~russian Включает или выключает сбор индекса во время записи.
|
||
void setCreateIndexOnFly(bool yes);
|
||
|
||
//! \~english Sets playback speed multiplier and switches mode to \a PlayVariableSpeed.
|
||
//! \~russian Устанавливает множитель скорости воспроизведения и переключает режим в \a PlayVariableSpeed.
|
||
void setPlaySpeed(double speed) {
|
||
setPlayMode(PlayVariableSpeed);
|
||
setProperty("playSpeed", speed);
|
||
}
|
||
|
||
//! \~english Sets fixed delay between records and switches mode to \a PlayStaticDelay.
|
||
//! \~russian Устанавливает фиксированную задержку между записями и переключает режим в \a PlayStaticDelay.
|
||
void setPlayDelay(const PISystemTime & delay) {
|
||
setPlayMode(PlayStaticDelay);
|
||
setProperty("playDelay", delay);
|
||
}
|
||
|
||
//! \~english Switches playback to \a PlayRealTime.
|
||
//! \~russian Переключает воспроизведение в режим \a PlayRealTime.
|
||
void setPlayRealTime() { setPlayMode(PlayRealTime); }
|
||
|
||
//! \~english Sets time threshold for file splitting and switches mode to \a SplitTime.
|
||
//! \~russian Устанавливает порог времени для разделения файлов и переключает режим в \a SplitTime.
|
||
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.
|
||
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.
|
||
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 Passing \c nullptr restores the internal generator based on \a logDir(), \a filePrefix() and current time.
|
||
//! \~russian Передача \c nullptr восстанавливает внутренний генератор на основе \a logDir(), \a filePrefix() и текущего времени.
|
||
void setFuncGetNewFilePath(std::function<PIString()> f) { f_new_path = f; }
|
||
|
||
//! \~english Writes one record with explicit ID and payload.
|
||
//! \~russian Записывает одну запись с явным идентификатором и данными.
|
||
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 Writes one record with explicit timestamp.
|
||
//! \~russian Записывает одну запись с явной временной меткой.
|
||
int writeBinLog_raw(int id, const PISystemTime & time, const PIByteArray & data) {
|
||
return writeBinLog_raw(id, time, data.data(), data.size_s());
|
||
}
|
||
//! \~english Writes one record with explicit timestamp and payload buffer.
|
||
//! \~russian Записывает одну запись с явной временной меткой и буфером данных.
|
||
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 Reads next record matching "id" from current position.
|
||
//! \~russian Читает следующую запись, соответствующую "id", из текущей позиции.
|
||
//! \~\details
|
||
//! \~english When "id" is zero, accepts any positive record ID.
|
||
//! \~russian Если "id" равно нулю, принимает любой положительный идентификатор записи.
|
||
PIByteArray readBinLog(int id = 0, PISystemTime * time = 0, int * readed_id = 0);
|
||
|
||
//! \~english Reads next record matching "id" into caller buffer.
|
||
//! \~russian Читает следующую запись, соответствующую "id", в буфер вызывающей стороны.
|
||
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 Устанавливает пользовательский заголовок файла для последовательно создаваемых логов.
|
||
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() и потокового воспроизведения.
|
||
PIVector<int> 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 Возвращает кэшированную информацию индекса, если она есть, иначе заново разбирает информацию текущего файла.
|
||
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<BinLogIndex> & logIndex() const { return index.index; }
|
||
|
||
//! \~english Builds record index for the current log file.
|
||
//! \~russian Строит индекс записей для текущего файла лога.
|
||
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" или позже.
|
||
int posForTime(const PISystemTime & time);
|
||
|
||
//! \~english Seeks to indexed record number "rindex".
|
||
//! \~russian Переходит к индексированной записи номер "rindex".
|
||
void seekTo(int rindex);
|
||
|
||
//! \~english Seeks to the first indexed record at or after "time".
|
||
//! \~russian Переходит к первой индексированной записи в момент "time" или позже.
|
||
bool seek(const PISystemTime & time);
|
||
|
||
//! \~english Seeks to the first indexed record whose file position is at or after "filepos".
|
||
//! \~russian Переходит к первой индексированной записи, чья позиция в файле находится в точке "filepos" или позже.
|
||
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 Загружает ранее сериализованные данные индекса для текущего читаемого лога.
|
||
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".
|
||
|
||
//! \}
|
||
//! \events
|
||
//! \{
|
||
|
||
//! \fn void fileEnd()
|
||
//! \~english Raised when reading reaches the end of file.
|
||
//! \~russian Вызывается, когда чтение достигает конца файла.
|
||
|
||
//! \fn void fileError()
|
||
//! \~english Raised when file header validation or file creation fails.
|
||
//! \~russian Вызывается при ошибке проверки заголовка файла или создания файла.
|
||
|
||
//! \fn void newFile(const PIString & filename)
|
||
//! \~english Raised after a new log file is successfully created.
|
||
//! \~russian Вызывается после успешного создания нового файла лога.
|
||
|
||
//! \fn void posChanged(int pos)
|
||
//! \~english Raised when current indexed playback position changes.
|
||
//! \~russian Вызывается при изменении текущей индексированной позиции воспроизведения.
|
||
|
||
//! \fn void threadedReadRecord(PIByteArray data, int id, PISystemTime time)
|
||
//! \~english Raised after threaded playback emits one record.
|
||
//! \~russian Вызывается после выдачи одной записи потоковым воспроизведением.
|
||
|
||
//! \}
|
||
|
||
EVENT_HANDLER(PIString, createNewFile);
|
||
EVENT(fileEnd);
|
||
EVENT(fileError);
|
||
EVENT1(newFile, const PIString &, filename);
|
||
EVENT1(posChanged, int, pos);
|
||
EVENT3(threadedReadRecord, PIByteArray, data, int, id, PISystemTime, time);
|
||
|
||
//! \~english Parses file at "path" and returns its summary statistics.
|
||
//! \~russian Разбирает файл по пути "path" и возвращает его сводную статистику.
|
||
static BinLogInfo getLogInfo(const PIString & path);
|
||
|
||
//! \~english Creates a new log at "dst" from indexed range of "src".
|
||
//! \~russian Создает новый лог в "dst" из индексированного диапазона "src".
|
||
static bool cutBinLog(const BinLogInfo & src, const PIString & dst, int from, int to);
|
||
|
||
//! \~english Joins sequential split logs from "src" into a single destination log.
|
||
//! \~russian Объединяет последовательные разделенные логи из "src" в один результирующий лог.
|
||
static bool joinBinLogsSerial(const PIStringList & src,
|
||
const PIString & dst,
|
||
std::function<bool(const PIString &, PISystemTime)> progress = nullptr);
|
||
|
||
protected:
|
||
PIString constructFullPathDevice() const override;
|
||
void configureFromFullPathDevice(const PIString & full_path) override;
|
||
PIPropertyStorage constructVariantDevice() const override;
|
||
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||
ssize_t writeDevice(const void * data, ssize_t size) override;
|
||
bool openDevice() override;
|
||
bool closeDevice() override;
|
||
void propertyChanged(const char * s) override;
|
||
bool threadedRead(const uchar * readed, ssize_t size) override;
|
||
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<BinLogIndex> index;
|
||
PIMap<llong, int> 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<BinLogIndex> * 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<PIString()> 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
|