Ticket #1835: 1835-v5.patch
File 1835-v5.patch, 10.6 KB (added by , 19 years ago) |
---|
-
programs/mythbackend/mainserver.cpp
99 99 100 100 }; 101 101 102 QMutex MainServer::truncate_and_close_lock; 103 102 104 class ProcessRequestThread : public QThread 103 105 { 104 106 public: … … 1383 1385 if (tvchain) 1384 1386 tvchain->DeleteProgram(pginfo); 1385 1387 1386 int err;1387 1388 bool followLinks = gContext->GetNumSetting("DeletesFollowLinks", 0); 1388 1389 1389 1390 /* Delete recording. */ 1390 err = deleteFile(ds->filename, followLinks, false);1391 int fd = DeleteFile(ds->filename, followLinks); 1391 1392 1392 1393 sleep(2); 1393 1394 1394 if ( checkFile.exists())1395 if ((fd < 0) && checkFile.exists()) 1395 1396 { 1396 1397 VERBOSE(VB_IMPORTANT, 1397 1398 QString("Error deleting file: %1. Keeping metadata in database.") … … 1411 1412 } 1412 1413 1413 1414 /* Delete preview thumbnail. */ 1414 err =deleteFile(ds->filename + ".png", followLinks, true);1415 deleteFile(ds->filename + ".png", followLinks, true); 1415 1416 1416 1417 MSqlQuery query(MSqlQuery::InitCon()); 1417 1418 query.prepare("DELETE FROM recorded WHERE chanid = :CHANID AND " … … 1495 1496 delete pginfo; 1496 1497 1497 1498 deletelock.unlock(); 1499 1500 if (fd != -1) 1501 { 1502 m_expirer->TruncatePending(); 1503 TruncateAndClose(m_expirer, fd, ds->filename); 1504 m_expirer->TruncateFinished(); 1505 } 1498 1506 } 1499 1507 1508 /* Return fd for success, negative number for error. */ 1509 int MainServer::DeleteFile(const QString &filename, bool followLinks) 1510 { 1511 QFileInfo finfo(filename); 1512 int fd = -1, err = 0; 1513 1514 VERBOSE(VB_FILE, QString("About to unlink/delete file: '%1'") 1515 .arg(filename)); 1516 1517 QString errmsg = QString("Delete Error '%1'").arg(filename.local8Bit()); 1518 if (finfo.isSymLink()) 1519 errmsg += QString(" -> '%2'").arg(finfo.readLink().local8Bit()); 1520 1521 if (followLinks && finfo.isSymLink()) 1522 { 1523 if (followLinks) 1524 fd = OpenAndUnlink(finfo.readLink()); 1525 if (fd >= 0) 1526 err = unlink(filename.local8Bit()); 1527 } 1528 else if (!finfo.isSymLink()) 1529 { 1530 fd = OpenAndUnlink(filename); 1531 } 1532 else // just delete symlinks immediately 1533 { 1534 err = unlink(filename.local8Bit()); 1535 if (err == 0) 1536 return -1; // no error 1537 } 1538 1539 if (fd < 0) 1540 VERBOSE(VB_IMPORTANT, errmsg + ENO); 1541 1542 return fd; 1543 } 1544 1545 /** \fn MainServer::OpenAndUnlink(const QString&) 1546 * \brief Opens a file, unlinks it and returns the file descriptor. 1547 */ 1548 int MainServer::OpenAndUnlink(const QString &filename) 1549 { 1550 QString msg = QString("Error deleting '%1'").arg(filename.local8Bit()); 1551 int fd = open(filename.local8Bit(), O_WRONLY); 1552 1553 if (fd == -1) 1554 { 1555 VERBOSE(VB_IMPORTANT, msg + " could not open " + ENO); 1556 return -1; 1557 } 1558 1559 if (unlink(filename.local8Bit())) 1560 { 1561 VERBOSE(VB_IMPORTANT, msg + " could not unlink " + ENO); 1562 close(fd); 1563 return -1; 1564 } 1565 1566 return fd; 1567 } 1568 1569 /** \fn MainServer::TruncateAndClose(const AutoExpire*,int,const QString&) 1570 * \brief Repeatedly truncate an open file in small increments. 1571 * 1572 * When the file is small enough this closes the file and returns. 1573 * 1574 * NOTE: This aquires a lock so that only one instance of TruncateAndClose() 1575 * is running at a time. 1576 */ 1577 bool MainServer::TruncateAndClose(const AutoExpire *expirer, 1578 int fd, const QString &filename) 1579 { 1580 QMutexLocker locker(&truncate_and_close_lock); 1581 1582 // Time between truncation steps in milliseconds 1583 const size_t sleep_time = 500; 1584 const size_t min_tps = 8 * 1024 * 1024; 1585 const size_t min_trunc = (size_t) (min_tps * (sleep_time * 0.001f)); 1586 1587 // Compute the truncate increment such that we delete 1588 // 20% faster than the maximum recording rate. 1589 size_t increment; 1590 increment = (expirer->GetMinTruncateRate() * sleep_time + 999) / 1000; 1591 increment = max(increment, min_trunc); 1592 1593 VERBOSE(VB_FILE, 1594 QString("Truncating '%1' by %2 MB every %3 milliseconds") 1595 .arg(filename) 1596 .arg(increment / (1024.0 * 1024.0), 0, 'f', 2) 1597 .arg(sleep_time)); 1598 1599 const QString err_msg = QString("Error truncating '%1'").arg(filename); 1600 1601 // Get the on disk file size and disk block size. 1602 struct stat buf; 1603 fstat(fd, &buf); 1604 size_t fsize = buf.st_blksize * buf.st_blocks; 1605 1606 // Round truncate increment up to a blocksize, w/min of 1 block. 1607 increment = ((increment / buf.st_blksize) + 1) * buf.st_blksize; 1608 1609 while (fsize > increment) 1610 { 1611 fsize -= increment; 1612 1613 //VERBOSE(VB_FILE, QString("Truncating '%1' to %2 MB") 1614 // .arg(filename).arg(fsize / (1024.0 * 1024.0), 0, 'f', 2)); 1615 1616 int err = ftruncate(fd, fsize); 1617 if (err) 1618 { 1619 VERBOSE(VB_IMPORTANT, err_msg + ENO); 1620 return 0 == close(fd); 1621 } 1622 1623 usleep(sleep_time * 1000); 1624 } 1625 1626 bool ok = (0 == close(fd)); 1627 1628 usleep((sleep_time * fsize * 1000) / increment); 1629 1630 VERBOSE(VB_FILE, QString("Finished truncating '%1'").arg(filename)); 1631 1632 return ok; 1633 } 1634 1500 1635 void MainServer::HandleCheckRecordingActive(QStringList &slist, 1501 1636 PlaybackSock *pbs) 1502 1637 { -
programs/mythbackend/mainserver.h
148 148 void AddToChains(LiveTVChain *chain); 149 149 void DeleteChain(LiveTVChain *chain); 150 150 151 static int DeleteFile(const QString &filename, bool followLinks); 152 static int OpenAndUnlink(const QString &filename); 153 static bool TruncateAndClose(const AutoExpire *expirer, 154 int fd, const QString &filename); 155 151 156 QPtrList<LiveTVChain> liveTVChains; 152 157 QMutex liveTVChainsLock; 153 158 … … 187 192 QValueList<DeferredDeleteStruct> deferredDeleteList; 188 193 189 194 QTimer *autoexpireUpdateTimer; 195 196 static QMutex truncate_and_close_lock; 190 197 }; 191 198 192 199 #endif -
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 297 truncates_pending++; 298 299 VERBOSE(VB_FILE, LOC<<truncates_pending<<" file truncates are pending"); 300 } 301 302 void AutoExpire::TruncateFinished(void) 303 { 304 QMutexLocker locker(&truncate_monitor_lock); 305 306 truncates_pending--; 307 308 if (truncates_pending <= 0) 309 { 310 VERBOSE(VB_FILE, LOC + "All file truncates have finished"); 311 truncate_monitor_condition.wakeAll(); 312 } 313 } 314 315 void AutoExpire::WaitForPendingTruncates(void) 316 { 317 QMutexLocker locker(&truncate_monitor_lock); 318 while (truncates_pending > 0) 319 { 320 VERBOSE(VB_FILE, LOC + "Waiting for pending file truncates"); 321 truncate_monitor_condition.wait(&truncate_monitor_lock); 322 } 323 } 324 284 325 /** \fn AutoExpire::ExpireLiveTV(int type) 285 326 * \brief This expires LiveTV programs. 286 327 */ -
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; … … 35 36 void CalcParams(vector<EncoderLink*>); 36 37 void FillExpireList(); 37 38 void PrintExpireList(); 39 void TruncatePending(void); 40 void TruncateFinished(void); 41 42 size_t GetMaxRecordRate(void) const 43 { return max_record_rate; } 44 45 size_t GetMinTruncateRate(void) const 46 { return ((max_record_rate * 6) / 5) + 1; } 47 38 48 void GetAllExpiring(QStringList &strList); 39 49 void GetAllExpiring(pginfolist_t &list); 40 50 … … 53 63 bool deleteAll = false); 54 64 void ClearExpireList(void); 55 65 void Sleep(int sleepTime); 66 void WaitForPendingTruncates(void); 56 67 57 68 void UpdateDontExpireSet(void); 58 69 bool IsInDontExpireSet(QString chanid, QDateTime starttime); … … 66 77 QString record_file_prefix; 67 78 size_t desired_space; 68 79 uint desired_freq; 80 size_t max_record_rate; // bytes/sec 69 81 bool expire_thread_running; 70 82 bool is_master_backend; 71 83 84 // Pending truncates monitor 85 mutable QMutex truncate_monitor_lock; 86 QWaitCondition truncate_monitor_condition; 87 int truncates_pending; 88 72 89 // update info 73 90 bool update_pending; 74 91 pthread_t update_thread;