Ticket #4242: myth_IOMultiplierV2_r15966.diff

File myth_IOMultiplierV2_r15966.diff, 29.1 KB (added by Mark Buechler <Mark.Buechler@…>, 16 years ago)

V2 of the patch enabling read/write multiplier per storage group/directory

  • libs/libmythtv/ThreadedFileWriter.cpp

     
    2323#define LOC_ERR QString("TFW, Error: ")
    2424
    2525const uint ThreadedFileWriter::TFW_DEF_BUF_SIZE   = 2*1024*1024;
    26 const uint ThreadedFileWriter::TFW_MAX_WRITE_SIZE = TFW_DEF_BUF_SIZE / 4;
    27 const uint ThreadedFileWriter::TFW_MIN_WRITE_SIZE = TFW_DEF_BUF_SIZE / 32;
     26const uint ThreadedFileWriter::TFW_MAX_WRITE_SIZE = TFW_DEF_BUF_SIZE /
     27                                                    (128 / (2<<(5-1)));
     28const uint ThreadedFileWriter::TFW_MIN_WRITE_SIZE = TFW_DEF_BUF_SIZE /
     29                                                    (1024 / (2<<(5-1)));
    2830
    2931/** \class ThreadedFileWriter
    3032 *  \brief This class supports the writing of recordings to disk.
     
    114116 *  \brief Creates a threaded file writer.
    115117 */
    116118ThreadedFileWriter::ThreadedFileWriter(const QString &fname,
    117                                        int pflags, mode_t pmode) :
     119                                       int pflags, mode_t pmode,
     120                                       uint io_mult) :
    118121    // file stuff
    119122    filename(QDeepCopy<QString>(fname)), flags(pflags),
    120123    mode(pmode),                         fd(-1),
     
    126129    rpos(0),                             wpos(0),
    127130    written(0),
    128131    // buffer
    129     buf(NULL),                           tfw_buf_size(0)
     132    buf(NULL),                           tfw_buf_size(0),
     133    io_multiplier(io_mult)
    130134{
    131135}
    132136
     
    151155        bzero(buf, TFW_DEF_BUF_SIZE + 64);
    152156
    153157        tfw_buf_size = TFW_DEF_BUF_SIZE;
    154         tfw_min_write_size = TFW_MIN_WRITE_SIZE;
     158
     159        tfw_min_write_size = TFW_DEF_BUF_SIZE / (1024 / (2<<(io_multiplier - 1)));
     160        tfw_max_write_size = TFW_DEF_BUF_SIZE / (128 / (2<<(io_multiplier - 1)));
     161
     162        VERBOSE(VB_RECORD, LOC + QString("Using io multiplier %1, "
     163                                          "min/max = %2/%3")
     164                                                     .arg(io_multiplier)
     165                                                     .arg(tfw_min_write_size)
     166                                                     .arg(tfw_max_write_size));
     167
    155168        pthread_create(&writer, NULL, boot_writer, this);
    156169        pthread_create(&syncer, NULL, boot_syncer, this);
    157170        return true;
     
    367380           buffer is valid, and we try to write all of it at once which
    368381           takes a long time. During this time, the other thread fills up
    369382           the 10% that was free... */
    370         size = (size > TFW_MAX_WRITE_SIZE) ? TFW_MAX_WRITE_SIZE : size;
     383        size = (size > tfw_max_write_size) ? tfw_max_write_size : size;
    371384
    372385        bool write_ok;
    373386        if (ignore_writes)
  • libs/libmythtv/dbcheck.cpp

     
    1414#define MINIMUM_DBMS_VERSION 5
    1515
    1616/// This is the DB schema version expected by the running MythTV instance.
    17 const QString currentDatabaseVersion = "1211";
     17const QString currentDatabaseVersion = "1212";
    1818
    1919static bool UpdateDBVersionNumber(const QString &newnumber);
    2020static bool performActualUpdate(const QString updates[], QString version,
     
    35213521            return false;
    35223522    }
    35233523
     3524    if (dbver == "1211")
     3525    {
     3526        const QString updates[] = {
     3527"ALTER TABLE storagegroup ADD COLUMN io_multiplier TINYINT(1) NULL; ",
     3528""
     3529};
     3530        if (!performActualUpdate(updates, "1211", dbver))
     3531            return false;
     3532    }
     3533
    35243534//"ALTER TABLE cardinput DROP COLUMN preference;" in 0.22
    35253535//"ALTER TABLE channel DROP COLUMN atscsrcid;" in 0.22
    35263536//"ALTER TABLE recordedmarkup DROP COLUMN offset;" in 0.22
  • libs/libmythtv/RingBuffer.cpp

     
    4747
    4848const uint RingBuffer::kBufferSize = 3 * 1024 * 1024;
    4949
    50 #define CHUNK 32768 /* readblocksize increments */
     50#define DEF_CHUNK 32768 /* default readblocksize increments */
    5151
    5252#define PNG_MIN_SIZE   20 /* header plus one empty chunk */
    5353#define NUV_MIN_SIZE  204 /* header size? */
     
    8686 */
    8787RingBuffer::RingBuffer(const QString &lfilename,
    8888                       bool write, bool readahead,
    89                        uint read_retries)
     89                       uint read_retries, uint io_multiplier)
    9090    : filename(QDeepCopy<QString>(lfilename)),
    9191      tfw(NULL),                fd2(-1),
    9292      writemode(false),
     
    101101      readsallowed(false),      wantseek(false), setswitchtonext(false),
    102102      rawbitrate(4000),         playspeed(1.0f),
    103103      fill_threshold(65536),    fill_min(-1),
    104       readblocksize(CHUNK),    wanttoread(0),
     104      readblocksize(DEF_CHUNK), wanttoread(0),
    105105      numfailures(0),           commserror(false),
    106106      dvdPriv(NULL),            oldfile(false),
    107107      livetvchain(NULL),        ignoreliveeof(false),
     
    109109{
    110110    pthread_rwlock_init(&rwlock, NULL);
    111111
     112    if ((io_multiplier > 5) || (io_multiplier < 2))
     113    {
     114        VERBOSE(VB_IMPORTANT, LOC + QString("Read/Write multiplier value of %1 is "
     115                                  "out of range, setting to the default value %2.")
     116                         .arg(io_multiplier).arg(StorageGroup::DEF_IO_MULTIPLIER));
     117        io_multiplier = StorageGroup::DEF_IO_MULTIPLIER;
     118    }
     119
    112120    if (write)
    113121    {
    114122        tfw = new ThreadedFileWriter(
    115             filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644);
     123            filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644,
     124            io_multiplier);
    116125
    117126        if (!tfw->Open())
    118127        {
     
    123132        return;
    124133    }
    125134
     135    read_chunk_size = (2<<(io_multiplier - 1)) * 1024;
     136    max_read_size = 640 / (32 / (2<<(io_multiplier - 1))) * 1024;
     137
     138    VERBOSE(VB_GENERAL, LOC + QString("Using io multiplier %1, chunk/max = "
     139                                                                     "%2/%3")
     140                                                          .arg(io_multiplier)
     141                                                          .arg(read_chunk_size)
     142                                                          .arg(max_read_size));
     143
    126144    if (read_retries != (uint)-1)
    127145        OpenFile(filename, read_retries);
    128146}
     
    537555    pthread_rwlock_wrlock(&rwlock);
    538556    wantseek       = false;
    539557    readsallowed   = false;
    540     readblocksize  = CHUNK;
     558    readblocksize  = read_chunk_size;
    541559
    542560    // loop without sleeping if the buffered data is less than this
    543     fill_threshold = CHUNK * 2;
     561    fill_threshold = read_chunk_size * 2;
    544562    fill_min       = 1;
    545563
    546564#ifdef USING_FRONTEND
     
    612630void RingBuffer::ResetReadAhead(long long newinternal)
    613631{
    614632    readAheadLock.lock();
    615     readblocksize = CHUNK;
     633    readblocksize = read_chunk_size;
    616634    rbrpos = 0;
    617635    rbwpos = 0;
    618636    internalreadpos = newinternal;
     
    726744
    727745    struct timeval lastread, now;
    728746    gettimeofday(&lastread, NULL);
    729     const int KB640 = 640*1024;
    730747    int readtimeavg = 300;
    731748    int readinterval;
    732749
    733750    pausereadthread = false;
    734751
    735     readAheadBuffer = new char[kBufferSize + KB640];
     752    readAheadBuffer = new char[kBufferSize + max_read_size];
    736753
    737754    ResetReadAhead(0);
    738755    totfree = ReadBufFree();
     
    783800
    784801            readtimeavg = (readtimeavg * 9 + readinterval) / 10;
    785802
    786             if (readtimeavg < 200 && readblocksize < KB640)
     803            if (readtimeavg < 200 && readblocksize < max_read_size)
    787804            {
    788                 readblocksize += CHUNK;
     805                readblocksize += read_chunk_size;
    789806                //VERBOSE(VB_PLAYBACK,
    790807                //    QString("Avg read interval was %1 msec. %2K block size")
    791808                //            .arg(readtimeavg).arg(readblocksize/1024));
    792809                readtimeavg = 300;
    793810            }
    794             else if (readtimeavg > 400 && readblocksize > CHUNK)
     811            else if (readtimeavg > 400 && readblocksize > read_chunk_size)
    795812            {
    796                 readblocksize -= CHUNK;
     813                readblocksize -= read_chunk_size;
    797814                //VERBOSE(VB_PLAYBACK,
    798815                //    QString("Avg read interval was %1 msec. %2K block size")
    799816                //            .arg(readtimeavg).arg(readblocksize/1024));
  • libs/libmythtv/tv_play.cpp

     
    4444#include "datadirect.h"
    4545#include "sourceutil.h"
    4646#include "cardutil.h"
     47#include "storagegroup.h"
    4748#include "util-osx-cocoa.h"
    4849#include "compat.h"
    4950
     
    15011502        {
    15021503            QString playbackURL = playbackinfo->GetPlaybackURL();
    15031504
     1505            StorageGroup sgroup(playbackinfo->storagegroup,
     1506                                playbackinfo->hostname);
     1507
     1508            QString dirname =
     1509              sgroup.FindRecordingDir(playbackinfo->GetRecordBasename());
     1510
     1511            uint io_multiplier = sgroup.ioMultiplier(dirname);
     1512
    15041513            tvchain->SetProgram(playbackinfo);
    15051514
    15061515            bool opennow = (tvchain->GetCardType(-1) != "DUMMY");
    15071516            prbuffer = new RingBuffer(playbackURL, false, true,
    1508                                       opennow ? 12 : (uint)-1);
     1517                                      opennow ? 12 : (uint)-1,
     1518                                      io_multiplier);
    15091519            prbuffer->SetLiveMode(tvchain);
    15101520        }
    15111521
     
    15631573            playbackURL = playbackinfo->GetPlaybackURL(
    15641574                              desiredNextState != kState_WatchingRecording);
    15651575
    1566         prbuffer = new RingBuffer(playbackURL, false);
     1576        StorageGroup sgroup(playbackinfo->storagegroup,
     1577                            playbackinfo->hostname);
     1578
     1579        QString dirname =
     1580          sgroup.FindRecordingDir(playbackinfo->GetRecordBasename());
     1581
     1582        uint io_multiplier = sgroup.ioMultiplier(dirname);
     1583
     1584        prbuffer = new RingBuffer(playbackURL, false, true, 12, io_multiplier);
    15671585        if (prbuffer->IsOpen())
    15681586        {
    15691587            gContext->DisableScreensaver();
     
    38053823        {
    38063824            QString playbackURL = playbackinfo->GetPlaybackURL();
    38073825
     3826            StorageGroup sgroup(playbackinfo->storagegroup,
     3827                                playbackinfo->hostname);
     3828
     3829            QString dirname =
     3830              sgroup.FindRecordingDir(playbackinfo->GetRecordBasename());
     3831
     3832            uint io_multiplier = sgroup.ioMultiplier(dirname);
     3833
    38083834            piptvchain->SetProgram(playbackinfo);
    3809             piprbuffer = new RingBuffer(playbackURL, false);
     3835            piprbuffer = new RingBuffer(playbackURL, false, true, 12,
     3836                                        io_multiplier);
    38103837            piprbuffer->SetLiveMode(piptvchain);
    38113838        }
    38123839
     
    45574584        {
    45584585            QString playbackURL = playbackinfo->GetPlaybackURL();
    45594586
     4587            StorageGroup sgroup(playbackinfo->storagegroup,
     4588                                playbackinfo->hostname);
     4589
     4590            QString dirname =
     4591              sgroup.FindRecordingDir(playbackinfo->GetRecordBasename());
     4592
     4593            uint io_multiplier = sgroup.ioMultiplier(dirname);
     4594
    45604595            tvchain->SetProgram(playbackinfo);
    4561             prbuffer = new RingBuffer(playbackURL, false);
     4596            prbuffer = new RingBuffer(playbackURL, false, true, 12,
     4597                                      io_multiplier);
    45624598            prbuffer->SetLiveMode(tvchain);
    45634599        }
    45644600
  • libs/libmythtv/RingBuffer.h

     
    1313}
    1414
    1515#include "mythexp.h"
     16#include "storagegroup.h"
    1617
    1718class RemoteFile;
    1819class RemoteEncoder;
     
    2425{
    2526  public:
    2627    RingBuffer(const QString &lfilename, bool write,
    27                bool usereadahead = true, uint read_retries = 12/*6*/);
     28               bool usereadahead = true, uint read_retries = 12/*6*/,
     29               uint io_multiplier = StorageGroup::DEF_IO_MULTIPLIER);
    2830   ~RingBuffer();
    2931
    3032    // Sets
     
    126128    long long readpos;
    127129    long long writepos;
    128130
     131    uint read_chunk_size;
     132    uint max_read_size;
     133
    129134    bool stopreads;
    130135
    131136    mutable pthread_rwlock_t rwlock;
     
    155160    float          playspeed;
    156161    int            fill_threshold;
    157162    int            fill_min;
    158     int            readblocksize;
     163    uint           readblocksize;
    159164
    160165    QWaitCondition pauseWait;
    161166
  • libs/libmythtv/tv_rec.cpp

     
    1414#include <qapplication.h>
    1515#include <qsqldatabase.h>
    1616#include <qsocket.h>
     17#include <qfileinfo.h>
    1718
    1819// MythTV headers
    1920#include "mythconfig.h"
     
    39313932
    39323933    if (lastTuningRequest.flags & kFlagRecording)
    39333934    {
    3934         SetRingBuffer(new RingBuffer(rec->GetFileName(), true));
     3935        StorageGroup sgroup(rec->storagegroup, gContext->GetHostName());
     3936        QString filename = rec->GetFileName();
     3937        QString dirname = QFileInfo(filename).dirPath(true);
     3938        uint io_multiplier = sgroup.ioMultiplier(dirname);
     3939
     3940        SetRingBuffer(new RingBuffer(filename, true, true, 12,
     3941                                     io_multiplier));
    39353942        if (!ringBuffer->IsOpen())
    39363943        {
    39373944            VERBOSE(VB_IMPORTANT, LOC_ERR +
    39383945                    QString("RingBuffer '%1' not open...")
    3939                     .arg(rec->GetFileName()));
     3946                    .arg(filename));
    39403947            SetRingBuffer(NULL);
    39413948            ClearFlags(kFlagPendingActions);
    39423949            goto err_ret;
     
    43034310    MythEvent me(QString("QUERY_NEXT_LIVETV_DIR %1").arg(cardid));
    43044311    gContext->dispatch(me);
    43054312
     4313    StorageGroup sgroup(prog->storagegroup, gContext->GetHostName());
     4314
    43064315    if (WaitForNextLiveTVDir())
    43074316    {
    43084317        QMutexLocker lock(&nextLiveTVDirLock);
    43094318        prog->pathname = nextLiveTVDir;
    43104319    }
    43114320    else
    4312     {
    4313         StorageGroup sgroup("LiveTV", gContext->GetHostName());
    43144321        prog->pathname = sgroup.FindNextDirMostFree();
    4315     }
    43164322
    43174323    StartedRecording(prog);
    43184324
    4319     *rb = new RingBuffer(prog->GetFileName(), true);
     4325    QString filename = prog->GetFileName();
     4326    QString dirname = QFileInfo(filename).dirPath(true);
     4327
     4328    uint io_multiplier = sgroup.ioMultiplier(dirname);
     4329
     4330    *rb = new RingBuffer(filename, true, true, 12, io_multiplier);
    43204331    if (!(*rb)->IsOpen())
    43214332    {
    43224333        VERBOSE(VB_IMPORTANT, LOC_ERR +
    43234334                QString("RingBuffer '%1' not open...")
    4324                 .arg(prog->GetFileName()));
     4335                .arg(filename));
    43254336
    43264337        delete *rb;
    43274338        delete prog;
  • libs/libmythtv/ThreadedFileWriter.h

     
    77#include <qwaitcondition.h>
    88#include <qstring.h>
    99
     10#include "storagegroup.h"
     11
    1012class ThreadedFileWriter
    1113{
    1214  public:
    13     ThreadedFileWriter(const QString &fname, int flags, mode_t mode);
     15    ThreadedFileWriter(const QString &fname, int flags, mode_t mode,
     16                       uint io_mult = StorageGroup::DEF_IO_MULTIPLIER);
    1417    ~ThreadedFileWriter();
    1518
    1619    bool Open(void);
     
    4043    int             flags;
    4144    mode_t          mode;
    4245    int             fd;
     46    uint            io_multiplier;
    4347
    4448    // state
    4549    bool            no_writes;
     
    4852    bool            in_dtor;
    4953    bool            ignore_writes;
    5054    long long       tfw_min_write_size;
     55    long long       tfw_max_write_size;
    5156
    5257    // buffer position state
    5358    uint            rpos;    ///< points to end of data written to disk
  • libs/libmyth/storagegroup.cpp

     
    1919    << "DB Backups"
    2020    ;
    2121
     22DirectoryConfig::DirectoryConfig(QString &dir, uint &io_multiplier)
     23{
     24    ConfigurationGroup* group = new VerticalConfigurationGroup(false, false);
     25
     26    if (dir.isEmpty())
     27        group->setLabel(QObject::tr("Add new directory"));
     28    else
     29        group->setLabel(QObject::tr("Settings for directory: ") + dir);
     30
     31    group->addChild(new DirectoryPathSetting(dir));
     32    group->addChild(new ioMultiplierSetting(io_multiplier));
     33
     34    addChild(group);
     35}
     36
     37
    2238/****************************************************************************/
    2339
    2440/** \brief StorageGroup constructor.
     
    314330    return QDeepCopy<QStringList>(groups);
    315331}
    316332
     333uint StorageGroup::ioMultiplier(QString dirname)
     334{
     335    if (dirname.isEmpty() || m_groupname.isEmpty() || m_hostname.isEmpty())
     336        return StorageGroup::DEF_IO_MULTIPLIER;
     337
     338    if (dirname.right(1) != "/")
     339        dirname.append("/");
     340
     341    uint io_multiplier;
     342    MSqlQuery query(MSqlQuery::InitCon());
     343
     344    query.prepare("SELECT io_multiplier FROM storagegroup "
     345                  "WHERE groupname = :GROUP "
     346                  "AND hostname = :HOSTNAME "
     347                  "AND dirname = :DIRNAME;");
     348    query.bindValue(":GROUP", m_groupname);
     349    query.bindValue(":HOSTNAME", m_hostname);
     350    query.bindValue(":DIRNAME", dirname);
     351
     352    if (!query.exec() || !query.isActive())
     353        MythContext::DBError("StorageGroup::ioMultiplier()", query);
     354    else if (!query.next())
     355    {
     356        VERBOSE(VB_FILE, LOC + QString("Unable to find storage group %1 "
     357                                       "for hostname %2, using default "
     358                                       "io_multiplier of %3.")
     359                                     .arg(m_groupname).arg(m_hostname)
     360                                     .arg(StorageGroup::DEF_IO_MULTIPLIER));
     361
     362        return StorageGroup::DEF_IO_MULTIPLIER;
     363    }
     364
     365    io_multiplier = query.value(0).toUInt();
     366
     367    if (!io_multiplier)
     368        io_multiplier = StorageGroup::DEF_IO_MULTIPLIER;
     369
     370    return io_multiplier;
     371}
     372
    317373/****************************************************************************/
    318374typedef enum {
    319375    SGPopup_OK = 0,
     
    385441
    386442    if (name == "__CREATE_NEW_STORAGE_DIRECTORY__")
    387443    {
     444        uint m_io_multiplier = StorageGroup::DEF_IO_MULTIPLIER;
    388445        name = "";
    389         SGPopupResult result = StorageGroupPopup::showPopup(
    390             gContext->GetMainWindow(),
    391             tr("Add Storage Group Directory"),
    392             tr("Enter directory name or press SELECT to enter text via the "
    393                "On Screen Keyboard"), name);
    394         if (result == SGPopup_CANCEL)
     446
     447        DirectoryConfig config(name, m_io_multiplier);
     448
     449        if (config.exec() != MythDialog::Accepted)
    395450            return;
    396451
    397452        if (name.right(1) != "/")
    398453            name.append("/");
    399454
    400455        MSqlQuery query(MSqlQuery::InitCon());
    401         query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) "
    402                       "VALUES (:NAME, :HOSTNAME, :DIRNAME);");
     456        query.prepare("INSERT INTO storagegroup (groupname, hostname, "
     457                      "dirname, io_multiplier) "
     458                      "VALUES (:NAME, :HOSTNAME, :DIRNAME, :IO_MULTIPLIER);");
    403459        query.bindValue(":NAME", m_group.utf8());
    404460        query.bindValue(":DIRNAME", name.utf8());
     461        query.bindValue(":IO_MULTIPLIER", m_io_multiplier);
    405462        query.bindValue(":HOSTNAME", gContext->GetHostName());
    406463        if (!query.exec())
    407464            MythContext::DBError("StorageGroupEditor::open", query);
    408465        else
    409466            lastValue = name;
    410467    } else {
    411         SGPopupResult result = StorageGroupPopup::showPopup(
    412             gContext->GetMainWindow(),
    413             tr("Edit Storage Group Directory"),
    414             tr("Enter directory name or press SELECT to enter text via the "
    415                "On Screen Keyboard"), name);
    416         if (result == SGPopup_CANCEL)
     468        uint m_io_multiplier = multiplier_map[name];
     469
     470        if (!m_io_multiplier)
     471            m_io_multiplier = StorageGroup::DEF_IO_MULTIPLIER;
     472
     473        DirectoryConfig config(name, m_io_multiplier);
     474
     475        if (config.exec() != MythDialog::Accepted)
    417476            return;
    418477
    419478        if (name.right(1) != "/")
     
    431490        if (!query.exec())
    432491            MythContext::DBError("StorageGroupEditor::open", query);
    433492
    434         query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) "
    435                       "VALUES (:NAME, :HOSTNAME, :DIRNAME);");
     493        query.prepare("INSERT INTO storagegroup (groupname, hostname, "
     494                      "dirname, io_multiplier) "
     495                      "VALUES (:NAME, :HOSTNAME, :DIRNAME, :IO_MULTIPLIER);");
    436496        query.bindValue(":NAME", m_group.utf8());
    437497        query.bindValue(":DIRNAME", name.utf8());
     498        query.bindValue(":IO_MULTIPLIER", m_io_multiplier);
    438499        query.bindValue(":HOSTNAME", gContext->GetHostName());
    439500        if (!query.exec())
    440501            MythContext::DBError("StorageGroupEditor::open", query);
     
    482543
    483544void StorageGroupEditor::load(void) {
    484545    listbox->clearSelections();
     546    multiplier_map.clear();
    485547
    486548    MSqlQuery query(MSqlQuery::InitCon());
    487     query.prepare("SELECT dirname, id FROM storagegroup "
     549    query.prepare("SELECT dirname, io_multiplier, id FROM storagegroup "
    488550                  "WHERE groupname = :NAME AND hostname = :HOSTNAME "
    489551                  "ORDER BY id;");
    490552    query.bindValue(":NAME", m_group.utf8());
     
    502564                first = false;
    503565            }
    504566            listbox->addSelection(query.value(0).toString());
     567            multiplier_map[query.value(0).toString()] = query.value(1).toUInt();
    505568        }
    506569    }
    507570
     
    528591    return dialog;
    529592}
    530593
     594
    531595/****************************************************************************/
    532596
    533597StorageGroupListEditor::StorageGroupListEditor(void) :
  • libs/libmyth/storagegroup.h

     
    33
    44#include <qstringlist.h>
    55#include <qdeepcopy.h>
     6#include <qmap.h>
    67
    78#include "libmyth/settings.h"
    89#include "libmyth/mythwidgets.h"
    910
     11class DirectoryPathSetting : public LineEditSetting, public Storage
     12{
     13  public:
     14    DirectoryPathSetting(QString &dir) :
     15        LineEditSetting(this), m_dir(dir)
     16    {
     17        setLabel(QObject::tr("Directory Path"));
     18        QString help = QObject::tr("Specify the path to add to this "
     19                                   "storage group.");
     20        setHelpText(help);
     21    }
     22
     23    virtual void load(void)
     24    {
     25        setValue(m_dir);
     26    }
     27
     28    virtual void save(void)
     29    {
     30        m_dir = getValue();
     31    }
     32
     33  private:
     34    QString &m_dir;
     35};
     36
     37class ioMultiplierSetting : public SpinBoxSetting, public Storage
     38{
     39  public:
     40    ioMultiplierSetting(uint &io_multiplier) :
     41        SpinBoxSetting(this, 2, 5, 1), m_io_multiplier(io_multiplier)
     42    {
     43        setLabel(QObject::tr("Read/Write Buffer"));
     44        QString help = QObject::tr("Specify the amount of buffering to "
     45                                   "use for this directory. Default 5. "
     46                                   "Use caution when adjusting this.");
     47        setHelpText(help);
     48    }
     49
     50    virtual void load(void)
     51    {
     52        setValue(m_io_multiplier);
     53    }
     54
     55    virtual void save(void)
     56    {
     57        m_io_multiplier = getValue().toUInt();
     58    }
     59
     60  private:
     61    uint &m_io_multiplier;
     62};
     63
     64class DirectoryConfig : public QObject, public ConfigurationWizard
     65{
     66  public:
     67    DirectoryConfig(QString &dir, uint &io_multiplier);
     68};
     69
     70
    1071class MPUBLIC StorageGroup: public ConfigurationWizard
    1172{
    1273  public:
     
    3394
    3495    static QStringList getRecordingsGroups(void);
    3596
     97    uint ioMultiplier(QString dirname);
     98
     99    static const uint DEF_IO_MULTIPLIER = 5;
     100
    36101  private:
    37102    QString      m_groupname;
    38103    QString      m_hostname;
    39104    QStringList  m_dirlist;
     105    uint         io_multiplier;
    40106};
    41107
    42108class MPUBLIC StorageGroupEditor :
     
    57123    void doDelete(void);
    58124
    59125  protected:
     126    void editDirectory(QString &dir, uint &io_multiplier);
     127
    60128    QString         m_group;
    61129    ListBoxSetting *listbox;
    62130    QString         lastValue;
     131    QMap<QString, uint> multiplier_map;
    63132};
    64133
    65134class MPUBLIC StorageGroupListEditor :
  • programs/mythbackend/mainserver.h

     
    142142    FileTransfer *getFileTransferByID(int id);
    143143    FileTransfer *getFileTransferBySock(MythSocket *socket);
    144144
    145     QString LocalFilePath(QUrl &url);
     145    QString LocalFilePath(QUrl &url, uint &io_multiplier);
    146146
    147147    static void *SpawnDeleteThread(void *param);
    148148    void DoDeleteThread(const DeleteStruct *ds);
  • programs/mythbackend/filetransfer.cpp

     
    1414#include "libmyth/mythsocket.h"
    1515
    1616FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
    17                            bool usereadahead, int retries) :
     17                           bool usereadahead, int retries, uint io_mult) :
    1818    readthreadlive(true),
    19     rbuffer(new RingBuffer(filename, false, usereadahead, retries)),
     19    rbuffer(new RingBuffer(filename, false, usereadahead, retries, io_mult)),
    2020    sock(remote), ateof(false), refCount(0)
    2121{
    2222}
    2323
    24 FileTransfer::FileTransfer(QString &filename, MythSocket *remote)
     24FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
     25                           uint io_mult)
    2526{
    26     rbuffer = new RingBuffer(filename, false);
     27    rbuffer = new RingBuffer(filename, false, true, 12, io_mult);
    2728    sock = remote;
    2829    readthreadlive = true;
    2930    ateof = false;
  • programs/mythbackend/mainserver.cpp

     
    10071007        VERBOSE(VB_IMPORTANT, QString("adding: %1 as a remote file transfer")
    10081008                               .arg(commands[2]));
    10091009        QUrl qurl = slist[1];
    1010         QString filename = LocalFilePath(qurl);
     1010        uint io_multiplier = 0;
    10111011
     1012        QString filename = LocalFilePath(qurl, io_multiplier);
     1013
    10121014        FileTransfer *ft = NULL;
    10131015        bool usereadahead = true;
    10141016        int retries = -1;
     
    10191021        }
    10201022
    10211023        if (retries >= 0)
    1022             ft = new FileTransfer(filename, socket, usereadahead, retries);
     1024            ft = new FileTransfer(filename, socket, usereadahead, retries,
     1025                                  io_multiplier);
    10231026        else
    1024             ft = new FileTransfer(filename, socket);
     1027            ft = new FileTransfer(filename, socket, io_multiplier);
    10251028       
    10261029        sockListLock.lock();
    10271030        fileTransferList.push_back(ft);
     
    42334236    delete chain;
    42344237}
    42354238
    4236 QString MainServer::LocalFilePath(QUrl &url)
     4239QString MainServer::LocalFilePath(QUrl &url, uint &io_multiplier)
    42374240{
    42384241    QString lpath = url.path();
    42394242
     4243    io_multiplier = StorageGroup::DEF_IO_MULTIPLIER;
     4244
    42404245    if (lpath.section('/', -2, -2) == "channels")
    42414246    {
    42424247        // This must be an icon request. Check channel.icon to be safe.
     
    42704275        ProgramInfo *pginfo = ProgramInfo::GetProgramFromBasename(fpath);
    42714276        if (pginfo)
    42724277        {
     4278            StorageGroup sgroup(pginfo->storagegroup, gContext->GetHostName());
     4279            QString dirname =
     4280              sgroup.FindRecordingDir(pginfo->GetRecordBasename());
     4281            io_multiplier = sgroup.ioMultiplier(dirname);
    42734282            QString pburl = GetPlaybackURL(pginfo);
    42744283            if (pburl.left(1) == "/")
    42754284            {
     
    42924301            lpath = QFileInfo(lpath).fileName();
    42934302            StorageGroup sgroup;
    42944303            QString tmpFile = sgroup.FindRecordingFile(lpath);
     4304            QString tmpPath = QFileInfo(tmpFile).dirPath(true);
     4305            io_multiplier = sgroup.ioMultiplier(tmpPath);
    42954306            if (!tmpFile.isEmpty())
    42964307            {
    42974308                lpath = tmpFile;
  • programs/mythbackend/filetransfer.h

     
    1212#include <qstring.h>
    1313#include <qmutex.h>
    1414
     15#include "storagegroup.h"
     16
    1517class RingBuffer;
    1618class MythSocket;
    1719
     
    2022    friend class QObject; // quiet OSX gcc warning
    2123
    2224  public:
    23     FileTransfer(QString &filename, MythSocket *remote);
    2425    FileTransfer(QString &filename, MythSocket *remote,
    25                  bool usereadahead, int retries);
     26                 uint io_mult = StorageGroup::DEF_IO_MULTIPLIER);
     27    FileTransfer(QString &filename, MythSocket *remote, bool usereadahead,
     28                 int retries, uint io_mult = StorageGroup::DEF_IO_MULTIPLIER);
    2629
    2730    MythSocket *getSocket() { return sock; }
    2831