Ticket #1835: gradual-delete3.patch

File gradual-delete3.patch, 8.9 KB (added by bolek-mythtv@…, 13 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;