Ticket #1835: gradual-delete3.patch

File gradual-delete3.patch, 8.9 KB (added by bolek-mythtv@…, 6 years ago)
  • programs/mythbackend/mainserver.cpp

     
    13371337        tvchain->DeleteProgram(pginfo); 
    13381338 
    13391339    int err; 
     1340    int fd = -1; 
    13401341    QString filename = ds->filename; 
    13411342    bool followLinks = gContext->GetNumSetting("DeletesFollowLinks", 0); 
    13421343 
    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()) 
    13451347    { 
    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))); 
    13531354    } 
    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); 
    13571357     
    13581358    sleep(2); 
    13591359 
     
    13731373        gContext->dispatch(me); 
    13741374 
    13751375        deletelock.unlock(); 
     1376        if (fd != -1) close(fd); 
    13761377        return; 
    13771378    } 
    13781379 
     
    14751476    delete pginfo; 
    14761477 
    14771478    deletelock.unlock(); 
     1479 
     1480    if (fd != -1) 
     1481    { 
     1482        m_expirer->TruncatePending(); 
     1483        TruncateAndClose(fd, ds->filename); 
     1484        m_expirer->TruncateFinished(); 
     1485    } 
    14781486} 
    14791487 
     1488// Opens a file, unlinks it and returns the file descriptor 
     1489int 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. 
     1512int 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 
    14801551void MainServer::HandleCheckRecordingActive(QStringList &slist,  
    14811552                                            PlaybackSock *pbs) 
    14821553{ 
  • programs/mythbackend/mainserver.h

     
    142142 
    143143    static void *SpawnDeleteThread(void *param); 
    144144    void DoDeleteThread(DeleteStruct *ds); 
     145    int OpenAndUnlink(QString filename); 
     146    int TruncateAndClose(int fd, QString filename); 
    145147 
    146148    LiveTVChain *GetExistingChain(QString id); 
    147149    LiveTVChain *GetExistingChain(QSocket *sock); 
     
    169171    bool ismaster; 
    170172 
    171173    QMutex deletelock; 
     174    QMutex truncatelock; 
    172175    QMutex threadPoolLock; 
    173176    vector<ProcessRequestThread *> threadPool; 
    174177 
  • programs/mythbackend/autoexpire.cpp

     
    5353 */ 
    5454AutoExpire::AutoExpire(bool runthread, bool master) 
    5555    : 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) 
    5859{ 
    5960    if (runthread) 
    6061    { 
     
    179180    instance_lock.lock(); 
    180181    desired_space      = expireMinKB; 
    181182    desired_freq       = expireFreq; 
     183    max_record_rate    = (totalKBperMin * 1024)/60; 
    182184    record_file_prefix = recordFilePrefix; 
    183185    instance_lock.unlock(); 
    184186    DBG_CALC_PARAM("CalcParams() -- end"); 
     
    227229 */ 
    228230void AutoExpire::RunExpirer(void) 
    229231{ 
    230     QTime curTime; 
    231232    QTime timer; 
     233    QDateTime curTime; 
     234    QDateTime next_expire = QDateTime::currentDateTime().addSecs(60); 
    232235 
    233236    // wait a little for main server to come up and things to settle down 
    234237    sleep(20); 
     
    243246 
    244247        UpdateDontExpireSet(); 
    245248 
    246         curTime = QTime::currentTime(); 
     249        curTime = QDateTime::currentDateTime(); 
    247250 
    248251        // Expire Short LiveTV files for this backend every 2 minutes 
    249         if ((curTime.minute() % 2) == 0) 
     252        if ((curTime.time().minute() % 2) == 0) 
    250253            ExpireLiveTV(emShortLiveTVPrograms); 
    251254 
    252255        // Expire normal recordings depending on frequency calculated 
    253         if ((curTime.minute() % desired_freq) == 0) 
     256        if (curTime >= next_expire) 
    254257        { 
     258            // Wait for all pending truncates to finish 
     259            WaitForPendingTruncates(); 
     260 
     261            next_expire = 
     262                QDateTime::currentDateTime().addSecs(desired_freq * 60); 
     263 
    255264            ExpireLiveTV(emNormalLiveTVPrograms); 
    256265 
    257266            if (is_master_backend) 
     
    281290    } 
    282291} 
    283292 
     293void 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 
     300void 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 
     310void 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 
    284320/** \fn AutoExpire::ExpireLiveTV(int type) 
    285321 *  \brief This expires LiveTV programs. 
    286322 */ 
  • programs/mythbackend/autoexpire.h

     
    99 
    1010#include <qmap.h>  
    1111#include <qmutex.h> 
     12#include <qwaitcondition.h> 
    1213#include <qobject.h> 
    1314 
    1415using namespace std; 
     
    3334   ~AutoExpire(); 
    3435 
    3536    void CalcParams(vector<EncoderLink*>); 
     37    size_t MaxRecordRate(void) { return max_record_rate; } 
    3638    void FillExpireList(); 
    3739    void PrintExpireList(); 
    3840    void GetAllExpiring(QStringList &strList); 
     41    void TruncatePending(void); 
     42    void TruncateFinished(void); 
    3943 
    4044    static void Update(QMap<int, EncoderLink*>*, bool immediately); 
    4145  protected: 
     
    5256                            bool deleteAll = false); 
    5357    void ClearExpireList(void); 
    5458    void Sleep(int sleepTime); 
     59    void WaitForPendingTruncates(void); 
    5560 
    5661    void UpdateDontExpireSet(void); 
    5762    bool IsInDontExpireSet(QString chanid, QDateTime starttime); 
     
    6570    QString       record_file_prefix; 
    6671    size_t        desired_space; 
    6772    uint          desired_freq; 
     73    size_t        max_record_rate; // bytes/sec 
    6874    bool          expire_thread_running; 
    6975    bool          is_master_backend; 
    7076 
     77    // Pending truncates monitor 
     78    QMutex         truncate_monitor_lock; 
     79    QWaitCondition truncate_monitor_condition; 
     80    int            truncates_pending; 
     81 
    7182    // update info 
    7283    bool          update_pending; 
    7384    pthread_t     update_thread;