14#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
15#include <QtSystemDetection>
28#define LOC QString("TFW(%1:%2): ").arg(m_filename).arg(m_fd)
84 if (!newFilename.isEmpty())
112 LOG(VB_GENERAL, LOG_ERR,
LOC +
120 LOG(VB_FILE, LOG_INFO,
LOC +
"Open() successful");
123 _setmode(
m_fd, _O_BINARY);
209 while (written < count)
217 LOG(VB_GENERAL, LOG_ERR,
LOC +
218 "Maximum buffer size exceeded."
219 "\n\t\t\tfile will be truncated, no further writing "
221 "\n\t\t\tThis generally indicates your disk performance "
222 "\n\t\t\tis insufficient to deal with the number of on-going "
223 "\n\t\t\trecordings, or you have a disk failure.");
229 LOG(VB_GENERAL, LOG_WARNING,
LOC +
230 "Maximum buffer size exceeded."
231 "\n\t\t\tThis generally indicates your disk performance "
232 "\n\t\t\tis insufficient or you have a disk failure.");
238 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
239 QString(
"Taking a long time waiting to write.. "
240 "buffer size %1 (needing %2, %3 to go)")
271 const char *cdata = (
const char*) data + written;
272 buf->
data.insert(buf->
data.end(), cdata, cdata+towrite);
286 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"Write(*, %1) total %2 cnt %3")
312 LOG(VB_GENERAL, LOG_WARNING,
LOC +
313 QString(
"Taking a long time to flush.. buffer size %1")
318 return lseek(
m_fd, pos, whence);
333 LOG(VB_GENERAL, LOG_WARNING,
LOC +
334 QString(
"Taking a long time to flush.. buffer size %1")
365#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
419 signal(SIGXFSZ, SIG_IGN);
429 minWriteTimer.
start();
430 lastRegisterTimer.
start();
432 uint64_t total_written = 0LL;
461 auto mwte = minWriteTimer.
elapsed();
480 minWriteTimer.
start();
484 const void *data = (buf->
data).data();
487 bool write_ok =
true;
491 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"write(%1) cnt %2 total %3")
502 int ret =
write(
m_fd, (
char *)data + tot, sz - tot);
508 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Got EAGAIN.");
513 LOG(VB_GENERAL, LOG_ERR,
LOC +
"File I/O " +
514 QString(
" errcnt: %1").arg(errcnt) +
ENO);
517 if ((errcnt >= 3) || (ENOSPC == errno) || (EFBIG == errno))
527 total_written += ret;
528 LOG(VB_FILE, LOG_DEBUG,
LOC +
529 QString(
"total written so far: %1 bytes")
530 .arg(total_written));
541 if (lastRegisterTimer.
elapsed() >= 10s)
553 LOG(VB_GENERAL, LOG_WARNING,
LOC +
554 QString(
"write(%1) cnt %2 total %3 -- took a long time, %4 ms")
559 if (!write_ok && ((EFBIG == errno) || (ENOSPC == errno)))
566 "Maximum file size exceeded by '%1'"
568 "You must either change the process ulimits, configure"
570 "your operating system with \"Large File\" support, "
573 "a filesystem which supports 64-bit or 128-bit files."
575 "HINT: FAT32 is a 32-bit filesystem.";
579 "No space left on the device for file '%1'"
581 "file will be truncated, no further writing "
595 QDateTime cur_m_60 = cur.addSecs(-60);
600 if (((*it)->lastUsed < cur_m_60) ||
601 ((*it)->data.capacity() > 3 * (*it)->data.size() &&
602 (*it)->data.capacity() > 64 * 1024LL))
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
void RegisterFileForWrite(const QString &file, uint64_t size=0LL)
void UnregisterFileForWrite(const QString &file)
A QElapsedTimer based timer to replace use of QTime as a timer.
std::chrono::milliseconds restart(void)
Returns milliseconds elapsed since last start() or restart() and resets the count.
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
void start(void)
starts measuring elapsed time.
void run(void) override
Runs ThreadedFileWriter::SyncLoop(void)
ThreadedFileWriter * m_parent
void run(void) override
Runs ThreadedFileWriter::DiskLoop(void)
ThreadedFileWriter * m_parent
void DiskLoop(void)
The thread run method that actually calls writes to disk.
void SetWriteBufferMinWriteSize(uint newMinSize=kMinWriteSize)
Sets the minumum number of bytes to write to disk in a single write.
QWaitCondition m_bufferHasData
TFWWriteThread * m_writeThread
void Sync(void) const
Flush data written to the file descriptor to disk.
bool SetBlocking(bool block=true)
Set write blocking mode While in blocking mode, ThreadedFileWriter::Write will wait for buffers to be...
QWaitCondition m_bufferEmpty
long long Seek(long long pos, int whence)
Seek to a position within stream; May be unsafe.
static const uint kMaxBufferSize
friend class TFWSyncThread
bool Open(void)
Opens the file we will be writing to.
void Flush(void)
Allow DiskLoop() to flush buffer completely ignoring low watermark.
static const uint kMinWriteSize
Minimum to write to disk in a single write, when not flushing buffer.
void TrimEmptyBuffers(void)
friend class TFWWriteThread
QWaitCondition m_bufferWasFreed
int Write(const void *data, uint count)
Writes data to the end of the write buffer.
QList< TFWBuffer * > m_emptyBuffers
bool ReOpen(const QString &newFilename="")
Reopens the file we are writing to or opens a new file.
void SyncLoop(void)
The thread run method that calls Sync(void).
static const uint kMaxBlockSize
Maximum block size to write at a time.
QList< TFWBuffer * > m_writeBuffers
~ThreadedFileWriter()
Commits all writes and closes the file.
QWaitCondition m_bufferSyncWait
TFWSyncThread * m_syncThread
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
def write(text, progress=True)