Ticket #1835: gradual-delete3.patch
File gradual-delete3.patch, 8.9 KB (added by , 18 years ago) |
---|
-
programs/mythbackend/mainserver.cpp
1337 1337 tvchain->DeleteProgram(pginfo); 1338 1338 1339 1339 int err; 1340 int fd = -1; 1340 1341 QString filename = ds->filename; 1341 1342 bool followLinks = gContext->GetNumSetting("DeletesFollowLinks", 0); 1342 1343 1343 VERBOSE(VB_FILE, QString("About to unlink/delete file: %1").arg(filename)); 1344 if (followLinks) 1344 VERBOSE(VB_FILE, QString("About to unlink/delete file: '%1'").arg(filename)); 1345 QFileInfo finfo(filename); 1346 if (finfo.isSymLink()) 1345 1347 { 1346 QFileInfo finfo(filename); 1347 if (finfo.isSymLink() && (err = unlink(finfo.readLink().local8Bit()))) 1348 { 1349 VERBOSE(VB_IMPORTANT, QString("Error deleting '%1' @ '%2', %3") 1350 .arg(filename).arg(finfo.readLink().local8Bit()) 1351 .arg(strerror(errno))); 1352 } 1348 if (followLinks) 1349 fd = OpenAndUnlink(finfo.readLink()); 1350 1351 if ((err = unlink(filename.local8Bit()))) 1352 VERBOSE(VB_IMPORTANT, QString("Error deleting '%1', %2") 1353 .arg(filename).arg(strerror(errno))); 1353 1354 } 1354 if ((err = unlink(filename.local8Bit()))) 1355 VERBOSE(VB_IMPORTANT, QString("Error deleting '%1', %2") 1356 .arg(filename).arg(strerror(errno))); 1355 else 1356 fd = OpenAndUnlink(filename); 1357 1357 1358 1358 sleep(2); 1359 1359 … … 1373 1373 gContext->dispatch(me); 1374 1374 1375 1375 deletelock.unlock(); 1376 if (fd != -1) close(fd); 1376 1377 return; 1377 1378 } 1378 1379 … … 1475 1476 delete pginfo; 1476 1477 1477 1478 deletelock.unlock(); 1479 1480 if (fd != -1) 1481 { 1482 m_expirer->TruncatePending(); 1483 TruncateAndClose(fd, ds->filename); 1484 m_expirer->TruncateFinished(); 1485 } 1478 1486 } 1479 1487 1488 // Opens a file, unlinks it and returns the file descriptor 1489 int MainServer::OpenAndUnlink(QString filename) 1490 { 1491 int fd = open(filename.local8Bit(), O_WRONLY); 1492 if (fd == -1) 1493 { 1494 VERBOSE(VB_IMPORTANT, QString("Error deleting '%1', %2") 1495 .arg(filename).arg(strerror(errno))); 1496 return -1; 1497 } 1498 1499 if (unlink(filename.local8Bit())) 1500 { 1501 VERBOSE(VB_IMPORTANT, QString("Error deleting '%1', %2") 1502 .arg(filename).arg(strerror(errno))); 1503 close(fd); 1504 return -1; 1505 } 1506 1507 return fd; 1508 } 1509 1510 // Repeatedly truncate an open file in small increments. 1511 // When small enough, close the file and return. 1512 int MainServer::TruncateAndClose(int fd, QString filename) 1513 { 1514 QMutexLocker locker(&truncatelock); 1515 const int sleep_time = 2; // time between truncation steps in seconds 1516 int err; 1517 size_t increment; 1518 struct stat buf; 1519 1520 // Compute the truncate increment such that we delete 20% faster than the 1521 // maximum recording rate. 1522 increment = (m_expirer->MaxRecordRate() * sleep_time * 6) / 5; 1523 1524 VERBOSE(VB_FILE, 1525 QString("Truncating '%1' by %2 MB every %3 seconds") 1526 .arg(filename) 1527 .arg(increment / (1024.0 * 1024.0), 0, 'f', 2) 1528 .arg(sleep_time)); 1529 1530 while (1) 1531 { 1532 // Get the file size 1533 fstat(fd, &buf); 1534 if (buf.st_size <= increment) 1535 break; 1536 1537 if ((err = ftruncate(fd, buf.st_size - increment))) 1538 { 1539 VERBOSE(VB_IMPORTANT, QString("Error truncating '%1', %2") 1540 .arg(filename).arg(strerror(errno))); 1541 return close(fd); 1542 } 1543 1544 sleep(sleep_time); 1545 } 1546 1547 VERBOSE(VB_FILE, QString("Finished truncating '%1'").arg(filename)); 1548 return close(fd); 1549 } 1550 1480 1551 void MainServer::HandleCheckRecordingActive(QStringList &slist, 1481 1552 PlaybackSock *pbs) 1482 1553 { -
programs/mythbackend/mainserver.h
142 142 143 143 static void *SpawnDeleteThread(void *param); 144 144 void DoDeleteThread(DeleteStruct *ds); 145 int OpenAndUnlink(QString filename); 146 int TruncateAndClose(int fd, QString filename); 145 147 146 148 LiveTVChain *GetExistingChain(QString id); 147 149 LiveTVChain *GetExistingChain(QSocket *sock); … … 169 171 bool ismaster; 170 172 171 173 QMutex deletelock; 174 QMutex truncatelock; 172 175 QMutex threadPoolLock; 173 176 vector<ProcessRequestThread *> threadPool; 174 177 -
programs/mythbackend/autoexpire.cpp
53 53 */ 54 54 AutoExpire::AutoExpire(bool runthread, bool master) 55 55 : record_file_prefix("/"), desired_space(3*1024*1024), 56 desired_freq(10), expire_thread_running(runthread), 57 is_master_backend(master), update_pending(false) 56 desired_freq(10), max_record_rate(5*1024*1024), 57 expire_thread_running(runthread), is_master_backend(master), 58 truncates_pending(0), update_pending(false) 58 59 { 59 60 if (runthread) 60 61 { … … 179 180 instance_lock.lock(); 180 181 desired_space = expireMinKB; 181 182 desired_freq = expireFreq; 183 max_record_rate = (totalKBperMin * 1024)/60; 182 184 record_file_prefix = recordFilePrefix; 183 185 instance_lock.unlock(); 184 186 DBG_CALC_PARAM("CalcParams() -- end"); … … 227 229 */ 228 230 void AutoExpire::RunExpirer(void) 229 231 { 230 QTime curTime;231 232 QTime timer; 233 QDateTime curTime; 234 QDateTime next_expire = QDateTime::currentDateTime().addSecs(60); 232 235 233 236 // wait a little for main server to come up and things to settle down 234 237 sleep(20); … … 243 246 244 247 UpdateDontExpireSet(); 245 248 246 curTime = Q Time::currentTime();249 curTime = QDateTime::currentDateTime(); 247 250 248 251 // Expire Short LiveTV files for this backend every 2 minutes 249 if ((curTime. minute() % 2) == 0)252 if ((curTime.time().minute() % 2) == 0) 250 253 ExpireLiveTV(emShortLiveTVPrograms); 251 254 252 255 // Expire normal recordings depending on frequency calculated 253 if ( (curTime.minute() % desired_freq) == 0)256 if (curTime >= next_expire) 254 257 { 258 // Wait for all pending truncates to finish 259 WaitForPendingTruncates(); 260 261 next_expire = 262 QDateTime::currentDateTime().addSecs(desired_freq * 60); 263 255 264 ExpireLiveTV(emNormalLiveTVPrograms); 256 265 257 266 if (is_master_backend) … … 281 290 } 282 291 } 283 292 293 void AutoExpire::TruncatePending(void) 294 { 295 QMutexLocker locker(&truncate_monitor_lock); 296 if (truncates_pending++ == 0) 297 VERBOSE(VB_FILE, LOC + "File truncates are pending"); 298 } 299 300 void AutoExpire::TruncateFinished(void) 301 { 302 QMutexLocker locker(&truncate_monitor_lock); 303 if (--truncates_pending == 0) 304 { 305 VERBOSE(VB_FILE, LOC + "All file truncates are finished"); 306 truncate_monitor_condition.wakeOne(); 307 } 308 } 309 310 void AutoExpire::WaitForPendingTruncates(void) 311 { 312 QMutexLocker locker(&truncate_monitor_lock); 313 if (truncates_pending > 0) 314 { 315 VERBOSE(VB_FILE, LOC + "Waiting for pending file truncates"); 316 truncate_monitor_condition.wait(&truncate_monitor_lock); 317 } 318 } 319 284 320 /** \fn AutoExpire::ExpireLiveTV(int type) 285 321 * \brief This expires LiveTV programs. 286 322 */ -
programs/mythbackend/autoexpire.h
9 9 10 10 #include <qmap.h> 11 11 #include <qmutex.h> 12 #include <qwaitcondition.h> 12 13 #include <qobject.h> 13 14 14 15 using namespace std; … … 33 34 ~AutoExpire(); 34 35 35 36 void CalcParams(vector<EncoderLink*>); 37 size_t MaxRecordRate(void) { return max_record_rate; } 36 38 void FillExpireList(); 37 39 void PrintExpireList(); 38 40 void GetAllExpiring(QStringList &strList); 41 void TruncatePending(void); 42 void TruncateFinished(void); 39 43 40 44 static void Update(QMap<int, EncoderLink*>*, bool immediately); 41 45 protected: … … 52 56 bool deleteAll = false); 53 57 void ClearExpireList(void); 54 58 void Sleep(int sleepTime); 59 void WaitForPendingTruncates(void); 55 60 56 61 void UpdateDontExpireSet(void); 57 62 bool IsInDontExpireSet(QString chanid, QDateTime starttime); … … 65 70 QString record_file_prefix; 66 71 size_t desired_space; 67 72 uint desired_freq; 73 size_t max_record_rate; // bytes/sec 68 74 bool expire_thread_running; 69 75 bool is_master_backend; 70 76 77 // Pending truncates monitor 78 QMutex truncate_monitor_lock; 79 QWaitCondition truncate_monitor_condition; 80 int truncates_pending; 81 71 82 // update info 72 83 bool update_pending; 73 84 pthread_t update_thread;