From 6ee614bed38168e1b1b96fa60671d7e41eee2aac Mon Sep 17 00:00:00 2001
From: Jean-Yves Avenard <jyavenard@mythtv.org>
Date: Sat, 31 Aug 2013 07:22:03 -0400
Subject: [PATCH] =?UTF-8?q?Wait=20until=20there=E2=80=99s=20more=20space?=
=?UTF-8?q?=20to=20write=20in=20buffer.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Writing should never result in a truncated file.
Also write using blocks of 1MB maximum, and reduce write buffer from 128MB to 8MB.
Fixes #11801
(cherry picked from commit b15ea225af5e601d3a12ffaa72cf013b730c3b9d)
Conflicts:
mythtv/libs/libmythtv/ThreadedFileWriter.cpp
---
mythtv/libs/libmythtv/ThreadedFileWriter.cpp | 97 ++++++++++++++++++----------
mythtv/libs/libmythtv/ThreadedFileWriter.h | 5 ++
2 files changed, 67 insertions(+), 35 deletions(-)
diff --git a/mythtv/libs/libmythtv/ThreadedFileWriter.cpp b/mythtv/libs/libmythtv/ThreadedFileWriter.cpp
index 3b24d58..698f7e9 100644
a
|
b
|
void TFWSyncThread::run(void) |
40 | 40 | RunEpilog(); |
41 | 41 | } |
42 | 42 | |
43 | | const uint ThreadedFileWriter::kMaxBufferSize = 128 * 1024 * 1024; |
44 | | const uint ThreadedFileWriter::kMinWriteSize = 64 * 1024; |
| 43 | const uint ThreadedFileWriter::kMaxBufferSize = 8 * 1024 * 1024; |
| 44 | const uint ThreadedFileWriter::kMinWriteSize = 64 * 1024; |
| 45 | const uint ThreadedFileWriter::kMaxBlockSize = 1 * 1024 * 1024; |
45 | 46 | |
46 | 47 | /** \class ThreadedFileWriter |
47 | 48 | * \brief This class supports the writing of recordings to disk. |
… |
… |
ThreadedFileWriter::ThreadedFileWriter(const QString &fname, |
67 | 68 | ignore_writes(false), tfw_min_write_size(kMinWriteSize), |
68 | 69 | totalBufferUse(0), |
69 | 70 | // threads |
70 | | writeThread(NULL), syncThread(NULL) |
| 71 | writeThread(NULL), syncThread(NULL), |
| 72 | m_warned(false) |
71 | 73 | { |
72 | 74 | filename.detach(); |
73 | 75 | } |
… |
… |
uint ThreadedFileWriter::Write(const void *data, uint count) |
206 | 208 | if (ignore_writes) |
207 | 209 | return count; |
208 | 210 | |
209 | | if (totalBufferUse + count > kMaxBufferSize) |
| 211 | uint written = 0; |
| 212 | uint left = count; |
| 213 | |
| 214 | while (written < count) |
210 | 215 | { |
211 | | LOG(VB_GENERAL, LOG_ERR, LOC + |
212 | | "Maximum buffer size exceeded." |
213 | | "\n\t\t\tfile will be truncated, no further writing " |
214 | | "will be done." |
215 | | "\n\t\t\tThis generally indicates your disk performance " |
216 | | "\n\t\t\tis insufficient to deal with the number of on-going " |
217 | | "\n\t\t\trecordings, or you have a disk failure."); |
218 | | ignore_writes = true; |
219 | | return count; |
220 | | } |
| 216 | uint towrite = (left > kMaxBlockSize) ? kMaxBlockSize : left; |
221 | 217 | |
222 | | TFWBuffer *buf = NULL; |
| 218 | if (totalBufferUse + towrite > kMaxBufferSize) |
| 219 | { |
| 220 | if (!m_warned) |
| 221 | { |
| 222 | LOG(VB_GENERAL, LOG_WARNING, LOC + |
| 223 | "Maximum buffer size exceeded." |
| 224 | "\n\t\t\tThis generally indicates your disk performance " |
| 225 | "\n\t\t\tis insufficient or you have a disk failure."); |
| 226 | m_warned = true; |
| 227 | } |
| 228 | // wait until some was written to disk, and try again |
| 229 | if (!bufferWasFreed.wait(locker.mutex(), 1000)) |
| 230 | { |
| 231 | LOG(VB_GENERAL, LOG_DEBUG, LOC + |
| 232 | QString("Taking a long time waiting to write.. " |
| 233 | "buffer size %1 (needing %2, %3 to go)") |
| 234 | .arg(totalBufferUse).arg(towrite) |
| 235 | .arg(towrite-(kMaxBufferSize-totalBufferUse))); |
| 236 | } |
| 237 | continue; |
| 238 | } |
223 | 239 | |
224 | | if (!writeBuffers.empty() && |
225 | | (writeBuffers.back()->data.size() + count) < kMinWriteSize) |
226 | | { |
227 | | buf = writeBuffers.back(); |
228 | | writeBuffers.pop_back(); |
229 | | } |
230 | | else |
231 | | { |
232 | | if (!emptyBuffers.empty()) |
| 240 | TFWBuffer *buf = NULL; |
| 241 | |
| 242 | if (!writeBuffers.empty() && |
| 243 | (writeBuffers.back()->data.size() + towrite) < kMinWriteSize) |
233 | 244 | { |
234 | | buf = emptyBuffers.front(); |
235 | | emptyBuffers.pop_front(); |
236 | | buf->data.clear(); |
| 245 | buf = writeBuffers.back(); |
| 246 | writeBuffers.pop_back(); |
237 | 247 | } |
238 | 248 | else |
239 | 249 | { |
240 | | buf = new TFWBuffer(); |
| 250 | if (!emptyBuffers.empty()) |
| 251 | { |
| 252 | buf = emptyBuffers.front(); |
| 253 | emptyBuffers.pop_front(); |
| 254 | buf->data.clear(); |
| 255 | } |
| 256 | else |
| 257 | { |
| 258 | buf = new TFWBuffer(); |
| 259 | } |
241 | 260 | } |
242 | | } |
243 | 261 | |
244 | | totalBufferUse += count; |
245 | | const char *cdata = (const char*) data; |
246 | | buf->data.insert(buf->data.end(), cdata, cdata+count); |
247 | | buf->lastUsed = MythDate::current(); |
| 262 | totalBufferUse += towrite; |
248 | 263 | |
249 | | writeBuffers.push_back(buf); |
| 264 | const char *cdata = (const char*) data + written; |
| 265 | buf->data.insert(buf->data.end(), cdata, cdata+towrite); |
| 266 | buf->lastUsed = MythDate::current(); |
250 | 267 | |
251 | | bufferHasData.wakeAll(); |
| 268 | writeBuffers.push_back(buf); |
| 269 | |
| 270 | if ((writeBuffers.size() > 1) || (buf->data.size() >= kMinWriteSize)) |
| 271 | { |
| 272 | bufferHasData.wakeAll(); |
| 273 | } |
| 274 | |
| 275 | written += towrite; |
| 276 | left -= towrite; |
| 277 | } |
252 | 278 | |
253 | 279 | LOG(VB_FILE, LOG_DEBUG, LOC + QString("Write(*, %1) total %2 cnt %3") |
254 | 280 | .arg(count,4).arg(totalBufferUse).arg(writeBuffers.size())); |
… |
… |
void ThreadedFileWriter::DiskLoop(void) |
432 | 458 | TFWBuffer *buf = writeBuffers.front(); |
433 | 459 | writeBuffers.pop_front(); |
434 | 460 | totalBufferUse -= buf->data.size(); |
| 461 | bufferWasFreed.wakeAll(); |
435 | 462 | minWriteTimer.start(); |
436 | 463 | |
437 | 464 | ////////////////////////////////////////// |
diff --git a/mythtv/libs/libmythtv/ThreadedFileWriter.h b/mythtv/libs/libmythtv/ThreadedFileWriter.h
index df7aeb1..7ff9ae3 100644
a
|
b
|
class ThreadedFileWriter |
94 | 94 | QWaitCondition bufferEmpty; |
95 | 95 | QWaitCondition bufferHasData; |
96 | 96 | QWaitCondition bufferSyncWait; |
| 97 | QWaitCondition bufferWasFreed; |
97 | 98 | |
98 | 99 | // constants |
99 | 100 | static const uint kMaxBufferSize; |
100 | 101 | /// Minimum to write to disk in a single write, when not flushing buffer. |
101 | 102 | static const uint kMinWriteSize; |
| 103 | /// Maximum block size to write at a time |
| 104 | static const uint kMaxBlockSize; |
| 105 | |
| 106 | bool m_warned; |
102 | 107 | }; |
103 | 108 | |
104 | 109 | #endif |