Ticket #4242: myth_IOMultiplierV4_r19570.diff

File myth_IOMultiplierV4_r19570.diff, 29.3 KB (added by Mark.Buechler@…, 15 years ago)

v4 of the patch for trunk with minor fixes

  • libs/libmythtv/ThreadedFileWriter.cpp

     
    2727#define LOC_ERR QString("TFW, Error: ")
    2828
    2929const uint ThreadedFileWriter::TFW_DEF_BUF_SIZE   = 2*1024*1024;
    30 const uint ThreadedFileWriter::TFW_MAX_WRITE_SIZE = TFW_DEF_BUF_SIZE / 4;
    31 const uint ThreadedFileWriter::TFW_MIN_WRITE_SIZE = TFW_DEF_BUF_SIZE / 32;
     30const uint ThreadedFileWriter::TFW_MAX_WRITE_SIZE = TFW_DEF_BUF_SIZE /
     31                                                    (128 / (2<<(5-1)));
     32const uint ThreadedFileWriter::TFW_MIN_WRITE_SIZE = TFW_DEF_BUF_SIZE /
     33                                                    (1024 / (2<<(5-1)));
    3234
    3335/** \class ThreadedFileWriter
    3436 *  \brief This class supports the writing of recordings to disk.
     
    118120 *  \brief Creates a threaded file writer.
    119121 */
    120122ThreadedFileWriter::ThreadedFileWriter(const QString &fname,
    121                                        int pflags, mode_t pmode) :
     123                                       int pflags, mode_t pmode,
     124                                       uint io_mult) :
    122125    // file stuff
    123126    filename(fname),                     flags(pflags),
    124127    mode(pmode),                         fd(-1),
     
    130133    rpos(0),                             wpos(0),
    131134    written(0),
    132135    // buffer
     136    io_multiplier(io_mult),
    133137    buf(NULL),                           tfw_buf_size(0)
    134138{
    135139    filename.detach();
     
    163167        bzero(buf, TFW_DEF_BUF_SIZE + 64);
    164168
    165169        tfw_buf_size = TFW_DEF_BUF_SIZE;
    166         tfw_min_write_size = TFW_MIN_WRITE_SIZE;
     170
     171        tfw_min_write_size = TFW_DEF_BUF_SIZE / (1024 / (2<<(io_multiplier - 1)));
     172        tfw_max_write_size = TFW_DEF_BUF_SIZE / (128 / (2<<(io_multiplier - 1)));
     173
     174        VERBOSE(VB_RECORD, LOC + QString("Using io multiplier %1, "
     175                                          "min/max = %2/%3")
     176                                                     .arg(io_multiplier)
     177                                                     .arg(tfw_min_write_size)
     178                                                     .arg(tfw_max_write_size));
     179
    167180        pthread_create(&writer, NULL, boot_writer, this);
    168181        pthread_create(&syncer, NULL, boot_syncer, this);
    169182        return true;
     
    427440           buffer is valid, and we try to write all of it at once which
    428441           takes a long time. During this time, the other thread fills up
    429442           the 10% that was free... */
    430         size = (size > TFW_MAX_WRITE_SIZE) ? TFW_MAX_WRITE_SIZE : size;
     443        size = (size > tfw_max_write_size) ? tfw_max_write_size : size;
    431444
    432445        bool write_ok;
    433446        if (ignore_writes)
  • libs/libmythtv/dbcheck.cpp

     
    1818#define MINIMUM_DBMS_VERSION 5,0,15
    1919
    2020/// This is the DB schema version expected by the running MythTV instance.
    21 const QString currentDatabaseVersion = "1228";
     21const QString currentDatabaseVersion = "1229";
    2222
    2323static bool UpdateDBVersionNumber(const QString &newnumber);
    2424static bool performActualUpdate(
     
    937937            return false;
    938938    }
    939939
    940 
    941940    if (dbver == "1050")
    942941    {
    943942        const char *updates[] = {
     
    43964395            return false;
    43974396    }
    43984397
     4398    if (dbver == "1228")
     4399    {
     4400        const char *updates[] = {
     4401"ALTER TABLE storagegroup ADD COLUMN io_multiplier TINYINT(1) NULL;",
     4402NULL
     4403};
     4404        if (!performActualUpdate(updates, "1229", dbver))
     4405            return false;
     4406    }
     4407
    43994408    return true;
    44004409}
    44014410
  • libs/libmythtv/RingBuffer.cpp

     
    4444
    4545const uint RingBuffer::kBufferSize = 3 * 1024 * 1024;
    4646
    47 #define CHUNK 32768 /* readblocksize increments */
     47#define DEF_CHUNK 32768 /* default readblocksize increments */
    4848
    4949#define PNG_MIN_SIZE   20 /* header plus one empty chunk */
    5050#define NUV_MIN_SIZE  204 /* header size? */
     
    106106 */
    107107RingBuffer::RingBuffer(const QString &lfilename,
    108108                       bool write, bool readahead,
    109                        uint read_retries)
     109                       uint read_retries, uint io_multiplier)
    110110    : filename(lfilename),
    111111      tfw(NULL),                fd2(-1),
    112112      writemode(false),
     
    121121      readsallowed(false),      wantseek(false), setswitchtonext(false),
    122122      rawbitrate(4000),         playspeed(1.0f),
    123123      fill_threshold(65536),    fill_min(-1),
    124       readblocksize(CHUNK),    wanttoread(0),
     124      readblocksize(DEF_CHUNK), wanttoread(0),
    125125      numfailures(0),           commserror(false),
    126126      dvdPriv(NULL),            oldfile(false),
    127127      livetvchain(NULL),        ignoreliveeof(false),
     
    130130    filename.detach();
    131131    pthread_rwlock_init(&rwlock, NULL);
    132132
     133    if ((io_multiplier > 5) || (io_multiplier < 2))
     134    {
     135        VERBOSE(VB_IMPORTANT, LOC + QString("Read/Write multiplier value of %1 is "
     136                                  "out of range, setting to the default value %2.")
     137                         .arg(io_multiplier).arg(StorageGroup::DEF_IO_MULTIPLIER));
     138        io_multiplier = StorageGroup::DEF_IO_MULTIPLIER;
     139    }
     140
    133141    if (write)
    134142    {
    135143        tfw = new ThreadedFileWriter(
    136             filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644);
     144            filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644,
     145            io_multiplier);
    137146
    138147        if (!tfw->Open())
    139148        {
     
    144153        return;
    145154    }
    146155
     156    read_chunk_size = (2<<(io_multiplier - 1)) * 1024;
     157    max_read_size = 640 / (32 / (2<<(io_multiplier - 1))) * 1024;
     158
     159    VERBOSE(VB_GENERAL, LOC + QString("Using io multiplier %1, chunk/max = "
     160                                                                     "%2/%3")
     161                                                          .arg(io_multiplier)
     162                                                          .arg(read_chunk_size)
     163                                                          .arg(max_read_size));
     164
    147165    if (read_retries != (uint)-1)
    148166        OpenFile(filename, read_retries);
    149167}
     
    564582
    565583    wantseek       = false;
    566584    readsallowed   = false;
    567     readblocksize  = CHUNK;
     585    readblocksize  = read_chunk_size;
    568586
    569587    // loop without sleeping if the buffered data is less than this
    570     fill_threshold = CHUNK * 2;
     588    fill_threshold = read_chunk_size * 2;
    571589    fill_min       = 1;
    572590
    573591#ifdef USING_FRONTEND
     
    637655void RingBuffer::ResetReadAhead(long long newinternal)
    638656{
    639657    readAheadLock.lock();
    640     readblocksize = CHUNK;
     658    readblocksize = read_chunk_size;
    641659    rbrpos = 0;
    642660    rbwpos = 0;
    643661    internalreadpos = newinternal;
     
    762780
    763781    struct timeval lastread, now;
    764782    gettimeofday(&lastread, NULL);
    765     const int KB640 = 640*1024;
    766783    int readtimeavg = 300;
    767784    int readinterval;
    768785
    769786    pausereadthread = false;
    770787
    771     readAheadBuffer = new char[kBufferSize + KB640];
     788    readAheadBuffer = new char[kBufferSize + max_read_size];
    772789
    773790    pthread_rwlock_wrlock(&rwlock);
    774791    ResetReadAhead(0);
     
    822839
    823840            readtimeavg = (readtimeavg * 9 + readinterval) / 10;
    824841
    825             if (readtimeavg < 200 && readblocksize < KB640)
     842            if (readtimeavg < 200 && readblocksize < max_read_size)
    826843            {
    827                 readblocksize += CHUNK;
     844                readblocksize += read_chunk_size;
    828845                //VERBOSE(VB_PLAYBACK,
    829846                //    QString("Avg read interval was %1 msec. %2K block size")
    830847                //            .arg(readtimeavg).arg(readblocksize/1024));
    831848                readtimeavg = 300;
    832849            }
    833             else if (readtimeavg > 400 && readblocksize > CHUNK)
     850            else if (readtimeavg > 400 && readblocksize > read_chunk_size)
    834851            {
    835                 readblocksize -= CHUNK;
     852                readblocksize -= read_chunk_size;
    836853                //VERBOSE(VB_PLAYBACK,
    837854                //    QString("Avg read interval was %1 msec. %2K block size")
    838855                //            .arg(readtimeavg).arg(readblocksize/1024));
  • libs/libmythtv/tv_play.cpp

     
    4747#include "datadirect.h"
    4848#include "sourceutil.h"
    4949#include "cardutil.h"
     50#include "storagegroup.h"
    5051#include "channelutil.h"
    5152#include "util-osx-cocoa.h"
    5253#include "libmythdb/compat.h"
     
    16681669            QString playbackURL = ctx->playingInfo->GetPlaybackURL();
    16691670            ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    16701671
     1672            StorageGroup sgroup(ctx->playingInfo->storagegroup,
     1673                                ctx->playingInfo->hostname);
     1674
     1675            QString dirname =
     1676              sgroup.FindRecordingDir(ctx->playingInfo->GetRecordBasename());
     1677
     1678            uint io_multiplier = sgroup.ioMultiplier(dirname);
     1679
    16711680            bool opennow = (ctx->tvchain->GetCardType(-1) != "DUMMY");
    16721681
    16731682            VERBOSE(VB_IMPORTANT, QString("We have a playbackURL(%1) & "
     
    16751684                    .arg(playbackURL).arg(ctx->tvchain->GetCardType(-1)));
    16761685
    16771686            ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true,
    1678                                       opennow ? 12 : (uint)-1));
     1687                                      opennow ? 12 : (uint)-1,
     1688                                      io_multiplier));
    16791689            ctx->buffer->SetLiveMode(ctx->tvchain);
    16801690        }
    16811691
     
    17401750                              desiredNextState != kState_WatchingRecording);
    17411751        ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    17421752       
    1743         ctx->SetRingBuffer(new RingBuffer(playbackURL, false));
     1753        StorageGroup sgroup(ctx->playingInfo->storagegroup,
     1754                            ctx->playingInfo->hostname);
     1755
     1756        QString dirname =
     1757          sgroup.FindRecordingDir(ctx->playingInfo->GetRecordBasename());
     1758
     1759        uint io_multiplier = sgroup.ioMultiplier(dirname);
     1760        ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true, 12, io_multiplier));
    17441761       
    17451762        if (ctx->buffer && ctx->buffer->IsOpen())
    17461763        {
     
    60236040        {
    60246041            ctx->LockPlayingInfo(__FILE__, __LINE__);
    60256042            QString playbackURL = ctx->playingInfo->GetPlaybackURL();
    6026             ctx->SetRingBuffer(new RingBuffer(playbackURL, false));
     6043            StorageGroup sgroup(ctx->playingInfo->storagegroup,
     6044                                ctx->playingInfo->hostname);
     6045
     6046            QString dirname =
     6047              sgroup.FindRecordingDir(ctx->playingInfo->GetRecordBasename());
     6048            uint io_multiplier = sgroup.ioMultiplier(dirname);
     6049            ctx->SetRingBuffer(new RingBuffer(playbackURL, false,
     6050                                              true, 12, io_multiplier));
    60276051            ctx->tvchain->SetProgram(*ctx->playingInfo);
    60286052            ctx->buffer->SetLiveMode(ctx->tvchain);
    60296053            ctx->UnlockPlayingInfo(__FILE__, __LINE__);
  • 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;
     
    154159    float          playspeed;
    155160    int            fill_threshold;
    156161    int            fill_min;
    157     int            readblocksize;
     162    uint           readblocksize;
    158163
    159164    QWaitCondition pauseWait;
    160165
  • libs/libmythtv/tv_rec.cpp

     
    1313// Qt headers
    1414#include <qapplication.h>
    1515#include <qsqldatabase.h>
     16#include <qfileinfo.h>
     17#include <qdir.h>
    1618
    1719// MythTV headers
    1820#include "mythconfig.h"
     
    40034005
    40044006    if (lastTuningRequest.flags & kFlagRecording)
    40054007    {
    4006         SetRingBuffer(new RingBuffer(rec->GetFileName(), true));
     4008        StorageGroup sgroup(rec->storagegroup, gContext->GetHostName());
     4009        QString filename = rec->GetFileName();
     4010        QFileInfo fi(filename);
     4011        uint io_multiplier = sgroup.ioMultiplier(fi.absolutePath());
     4012
     4013        SetRingBuffer(new RingBuffer(filename, true, true, 12,
     4014                                     io_multiplier));
    40074015        if (!ringBuffer->IsOpen())
    40084016        {
    40094017            VERBOSE(VB_IMPORTANT, LOC_ERR +
    40104018                    QString("RingBuffer '%1' not open...")
    4011                     .arg(rec->GetFileName()));
     4019                    .arg(filename));
    40124020            SetRingBuffer(NULL);
    40134021            ClearFlags(kFlagPendingActions);
    40144022            goto err_ret;
     
    43734381    MythEvent me(QString("QUERY_NEXT_LIVETV_DIR %1").arg(cardid));
    43744382    gContext->dispatch(me);
    43754383
     4384    StorageGroup sgroup(prog->storagegroup, gContext->GetHostName());
     4385
    43764386    if (WaitForNextLiveTVDir())
    43774387    {
    43784388        QMutexLocker lock(&nextLiveTVDirLock);
    43794389        prog->pathname = nextLiveTVDir;
    43804390    }
    43814391    else
    4382     {
    4383         StorageGroup sgroup("LiveTV", gContext->GetHostName());
    43844392        prog->pathname = sgroup.FindNextDirMostFree();
    4385     }
    43864393
    43874394    StartedRecording(prog);
    43884395
    4389     *rb = new RingBuffer(prog->GetFileName(), true);
     4396    QString filename = prog->GetFileName();
     4397    QFileInfo fi(filename);
     4398    uint io_multiplier = sgroup.ioMultiplier(fi.absolutePath());
     4399
     4400    *rb = new RingBuffer(filename, true, true, 12, io_multiplier);
    43904401    if (!(*rb)->IsOpen())
    43914402    {
    43924403        VERBOSE(VB_IMPORTANT, LOC_ERR +
    43934404                QString("RingBuffer '%1' not open...")
    4394                 .arg(prog->GetFileName()));
     4405                .arg(filename));
    43954406
    43964407        delete *rb;
    43974408        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);
     
    4346    int             flags;
    4447    mode_t          mode;
    4548    int             fd;
     49    uint            io_multiplier;
    4650
    4751    // state
    4852    bool            no_writes;
     
    5155    bool            in_dtor;
    5256    bool            ignore_writes;
    5357    long long       tfw_min_write_size;
     58    long long       tfw_max_write_size;
    5459
    5560    // buffer position state
    5661    uint            rpos;    ///< points to end of data written to disk
  • libs/libmyth/storagegroup.h

     
    22#define _STORAGEGROUP_H
    33
    44#include <QStringList>
     5#include <qmap.h>
    56
    67#include "libmyth/settings.h"
    78#include "libmyth/mythwidgets.h"
    89
     10class MPUBLIC DirectoryPathSetting : public LineEditSetting,
     11                                     public GlobalDBStorage
     12{
     13  public:
     14    DirectoryPathSetting(const QString &name, QString &dir) :
     15        LineEditSetting(this, true), GlobalDBStorage(this, name), 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 MPUBLIC ioMultiplierSetting : public SpinBoxSetting,
     38                                    public GlobalDBStorage
     39{
     40  public:
     41    ioMultiplierSetting(const QString &name, uint &io_multiplier) :
     42        SpinBoxSetting(this, 2, 5, 1), GlobalDBStorage(this, name),
     43        m_io_multiplier(io_multiplier)
     44    {
     45        setLabel(QObject::tr("Read/Write Buffer"));
     46        QString help = QObject::tr("Specify the amount of buffering to "
     47                                   "use for this directory. Default 5. "
     48                                   "Use caution when adjusting this.");
     49        setHelpText(help);
     50    }
     51
     52    virtual void load(void)
     53    {
     54        setValue(m_io_multiplier);
     55    }
     56
     57    virtual void save(void)
     58    {
     59        m_io_multiplier = getValue().toUInt();
     60    }
     61
     62  private:
     63    uint &m_io_multiplier;
     64};
     65
     66class DirectoryConfig : public QObject, public ConfigurationWizard
     67{
     68  public:
     69    DirectoryConfig(QString &dir, uint &io_multiplier);
     70};
     71
    972class MPUBLIC StorageGroup: public ConfigurationWizard
    1073{
    1174  public:
     
    3295
    3396    static QStringList getRecordingsGroups(void);
    3497
     98    uint ioMultiplier(QString dirname);
     99
     100    static const uint DEF_IO_MULTIPLIER = 5;
     101
    35102  private:
    36103    QString      m_groupname;
    37104    QString      m_hostname;
    38105    QStringList  m_dirlist;
     106    uint         io_multiplier;
    39107};
    40108
    41109class MPUBLIC StorageGroupEditor :
     
    56124    void doDelete(void);
    57125
    58126  protected:
     127    void editDirectory(QString &dir, uint &io_multiplier);
     128
    59129    QString         m_group;
    60130    ListBoxSetting *listbox;
    61131    QString         lastValue;
     132    QMap<QString, uint> multiplier_map;
    62133};
    63134
    64135class MPUBLIC StorageGroupListEditor :
  • libs/libmyth/storagegroup.cpp

     
    2020    << "DB Backups"
    2121    ;
    2222
     23DirectoryConfig::DirectoryConfig(QString &dir, uint &io_multiplier)
     24{
     25    ConfigurationGroup* group = new VerticalConfigurationGroup(false, false);
     26
     27    if (dir.isEmpty())
     28        group->setLabel(QObject::tr("Add new directory"));
     29    else
     30        group->setLabel(QObject::tr("Settings for directory: ") + dir);
     31
     32    group->addChild(new DirectoryPathSetting("directoryEdit", dir));
     33    group->addChild(new ioMultiplierSetting("multiplierEdit", io_multiplier));
     34
     35    addChild(group);
     36}
     37
     38
    2339/****************************************************************************/
    2440
    2541/** \brief StorageGroup constructor.
     
    327343    return groups;
    328344}
    329345
     346uint StorageGroup::ioMultiplier(QString dirname)
     347{
     348    if (dirname.isEmpty() || m_groupname.isEmpty() || m_hostname.isEmpty())
     349        return StorageGroup::DEF_IO_MULTIPLIER;
     350
     351    QString dirname_t = dirname;
     352
     353    if (dirname.endsWith("/"))
     354        dirname_t.chop(1);
     355    else
     356        dirname_t.append("/");
     357
     358    uint io_multiplier;
     359    MSqlQuery query(MSqlQuery::InitCon());
     360
     361    query.prepare("SELECT io_multiplier FROM storagegroup "
     362                  "WHERE groupname = :GROUP "
     363                  "AND hostname = :HOSTNAME "
     364                  "AND (dirname = :DIRNAME  "
     365                  "OR dirname = :DIRNAME_T);");
     366    query.bindValue(":GROUP", m_groupname);
     367    query.bindValue(":HOSTNAME", m_hostname);
     368    query.bindValue(":DIRNAME", dirname);
     369    query.bindValue(":DIRNAME_T", dirname_t);
     370
     371    if (!query.exec() || !query.isActive())
     372        MythDB::DBError("StorageGroup::ioMultiplier()", query);
     373    else if (!query.next())
     374    {
     375        VERBOSE(VB_FILE, LOC + QString("Unable to find storage group %1 "
     376                                       "for hostname %2, using default "
     377                                       "io_multiplier of %3.")
     378                                     .arg(m_groupname).arg(m_hostname)
     379                                     .arg(StorageGroup::DEF_IO_MULTIPLIER));
     380
     381        return StorageGroup::DEF_IO_MULTIPLIER;
     382    }
     383
     384    io_multiplier = query.value(0).toUInt();
     385
     386    if (!io_multiplier)
     387        io_multiplier = StorageGroup::DEF_IO_MULTIPLIER;
     388
     389    return io_multiplier;
     390}
     391
    330392/****************************************************************************/
    331393typedef enum {
    332394    SGPopup_OK = 0,
     
    401463
    402464    if (name == "__CREATE_NEW_STORAGE_DIRECTORY__")
    403465    {
     466        uint m_io_multiplier = StorageGroup::DEF_IO_MULTIPLIER;
    404467        name = "";
    405         SGPopupResult result = StorageGroupPopup::showPopup(
    406             gContext->GetMainWindow(),
    407             tr("Add Storage Group Directory"),
    408             tr("Enter directory name or press SELECT to enter text via the "
    409                "On Screen Keyboard"), name);
    410         if (result == SGPopup_CANCEL)
     468           
     469        DirectoryConfig config(name, m_io_multiplier);
     470       
     471        if (config.exec() != MythDialog::Accepted)
    411472            return;
    412473
    413474        if (name.isEmpty())
     
    417478            name.append("/");
    418479
    419480        MSqlQuery query(MSqlQuery::InitCon());
    420         query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) "
    421                       "VALUES (:NAME, :HOSTNAME, :DIRNAME);");
     481        query.prepare("INSERT INTO storagegroup (groupname, hostname, "
     482                      "dirname, io_multiplier) "
     483                      "VALUES (:NAME, :HOSTNAME, :DIRNAME, :IO_MULTIPLIER);");
    422484        query.bindValue(":NAME", m_group);
    423485        query.bindValue(":DIRNAME", name);
     486        query.bindValue(":IO_MULTIPLIER", m_io_multiplier);
    424487        query.bindValue(":HOSTNAME", gContext->GetHostName());
    425488        if (!query.exec())
    426489            MythDB::DBError("StorageGroupEditor::open", query);
    427490        else
    428491            lastValue = name;
    429492    } else {
    430         SGPopupResult result = StorageGroupPopup::showPopup(
    431             gContext->GetMainWindow(),
    432             tr("Edit Storage Group Directory"),
    433             tr("Enter directory name or press SELECT to enter text via the "
    434                "On Screen Keyboard"), name);
    435         if (result == SGPopup_CANCEL)
     493        uint m_io_multiplier = multiplier_map[name];
     494       
     495        if (!m_io_multiplier)
     496            m_io_multiplier = StorageGroup::DEF_IO_MULTIPLIER;
     497       
     498        DirectoryConfig config(name, m_io_multiplier);
     499       
     500        if (config.exec() != MythDialog::Accepted)
    436501            return;
    437502
    438503        if (name.right(1) != "/")
     
    450515        if (!query.exec())
    451516            MythDB::DBError("StorageGroupEditor::open", query);
    452517
    453         query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) "
    454                       "VALUES (:NAME, :HOSTNAME, :DIRNAME);");
     518        query.prepare("INSERT INTO storagegroup (groupname, hostname, "
     519                      "dirname, io_multiplier) "
     520                      "VALUES (:NAME, :HOSTNAME, :DIRNAME, :IO_MULTIPLIER);");
    455521        query.bindValue(":NAME", m_group);
    456522        query.bindValue(":DIRNAME", name);
     523        query.bindValue(":IO_MULTIPLIER", m_io_multiplier);
    457524        query.bindValue(":HOSTNAME", gContext->GetHostName());
    458525        if (!query.exec())
    459526            MythDB::DBError("StorageGroupEditor::open", query);
     
    502569void StorageGroupEditor::Load(void)
    503570{
    504571    listbox->clearSelections();
     572    multiplier_map.clear();
    505573
    506574    MSqlQuery query(MSqlQuery::InitCon());
    507     query.prepare("SELECT dirname, id FROM storagegroup "
     575    query.prepare("SELECT dirname, io_multiplier, id FROM storagegroup "
    508576                  "WHERE groupname = :NAME AND hostname = :HOSTNAME "
    509577                  "ORDER BY id;");
    510578    query.bindValue(":NAME", m_group);
     
    522590                first = false;
    523591            }
    524592            listbox->addSelection(query.value(0).toString());
     593            multiplier_map[query.value(0).toString()] = query.value(1).toUInt();
    525594        }
    526595    }
    527596
     
    548617    return dialog;
    549618}
    550619
     620
    551621/****************************************************************************/
    552622
    553623StorageGroupListEditor::StorageGroupListEditor(void) :
  • programs/mythbackend/mainserver.h

     
    150150    FileTransfer *getFileTransferByID(int id);
    151151    FileTransfer *getFileTransferBySock(MythSocket *socket);
    152152
    153     QString LocalFilePath(const QUrl &url);
     153    QString LocalFilePath(const QUrl &url, uint &io_multiplier);
    154154
    155155    static void *SpawnDeleteThread(void *param);
    156156    void DoDeleteThread(const DeleteStruct *ds);
  • programs/mythbackend/filetransfer.cpp

     
    88#include "mythsocket.h"
    99
    1010FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
    11                            bool usereadahead, int retries) :
     11                           bool usereadahead, int retries, uint io_mult) :
    1212    readthreadlive(true), readsLocked(false),
    13     rbuffer(new RingBuffer(filename, false, usereadahead, retries)),
     13    rbuffer(new RingBuffer(filename, false, usereadahead, retries, io_mult)),
    1414    sock(remote), ateof(false), lock(QMutex::NonRecursive),
    1515    refLock(QMutex::NonRecursive), refCount(0)
    1616{
    1717}
    1818
    19 FileTransfer::FileTransfer(QString &filename, MythSocket *remote) :
     19FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
     20                           uint io_mult) :
    2021    readthreadlive(true), readsLocked(false),
    21     rbuffer(new RingBuffer(filename, false)),
     22    rbuffer(new RingBuffer(filename, false, true, 12, io_mult)),
    2223    sock(remote), ateof(false), lock(QMutex::NonRecursive),
    2324    refLock(QMutex::NonRecursive), refCount(0)
    2425{
  • programs/mythbackend/mainserver.cpp

     
    10541054        VERBOSE(VB_IMPORTANT, QString("adding: %1 as a remote file transfer")
    10551055                               .arg(commands[2]));
    10561056        QUrl qurl = slist[1];
    1057         QString filename = LocalFilePath(qurl);
     1057        uint io_multiplier = 0;
    10581058
     1059        QString filename = LocalFilePath(qurl, io_multiplier);
     1060
    10591061        FileTransfer *ft = NULL;
    10601062        bool usereadahead = true;
    10611063        int retries = -1;
     
    10661068        }
    10671069
    10681070        if (retries >= 0)
    1069             ft = new FileTransfer(filename, socket, usereadahead, retries);
     1071            ft = new FileTransfer(filename, socket, usereadahead, retries,
     1072                                  io_multiplier);
    10701073        else
    1071             ft = new FileTransfer(filename, socket);
     1074            ft = new FileTransfer(filename, socket, io_multiplier);
    10721075
    10731076        sockListLock.lock();
    10741077        fileTransferList.push_back(ft);
     
    43494352        QApplication::exit(m_exitCode);
    43504353}
    43514354
    4352 QString MainServer::LocalFilePath(const QUrl &url)
     4355QString MainServer::LocalFilePath(const QUrl &url, uint &io_multiplier)
    43534356{
    43544357    QString lpath = url.path();
    43554358
     4359    io_multiplier = StorageGroup::DEF_IO_MULTIPLIER;
     4360
    43564361    if (lpath.section('/', -2, -2) == "channels")
    43574362    {
    43584363        // This must be an icon request. Check channel.icon to be safe.
     
    43864391        ProgramInfo *pginfo = ProgramInfo::GetProgramFromBasename(fpath);
    43874392        if (pginfo)
    43884393        {
     4394            StorageGroup sgroup(pginfo->storagegroup, gContext->GetHostName());
     4395            QString dirname =
     4396              sgroup.FindRecordingDir(pginfo->GetRecordBasename());
     4397            io_multiplier = sgroup.ioMultiplier(dirname);
    43894398            QString pburl = GetPlaybackURL(pginfo);
    43904399            if (pburl.left(1) == "/")
    43914400            {
     
    44104419            lpath = QFileInfo(lpath).fileName();
    44114420            StorageGroup sgroup;
    44124421            QString tmpFile = sgroup.FindRecordingFile(lpath);
     4422            QFileInfo fi(tmpFile);
     4423            io_multiplier = sgroup.ioMultiplier(fi.absolutePath());
    44134424            if (!tmpFile.isEmpty())
    44144425            {
    44154426                lpath = tmpFile;
  • programs/mythbackend/filetransfer.h

     
    1313#include <qmutex.h>
    1414#include <qwaitcondition.h>
    1515
     16#include "storagegroup.h"
     17
    1618class RingBuffer;
    1719class MythSocket;
    1820
     
    2123    friend class QObject; // quiet OSX gcc warning
    2224
    2325  public:
    24     FileTransfer(QString &filename, MythSocket *remote);
    2526    FileTransfer(QString &filename, MythSocket *remote,
    26                  bool usereadahead, int retries);
     27                 uint io_mult = StorageGroup::DEF_IO_MULTIPLIER);
     28    FileTransfer(QString &filename, MythSocket *remote, bool usereadahead,
     29                 int retries, uint io_mult = StorageGroup::DEF_IO_MULTIPLIER);
    2730
    2831    MythSocket *getSocket() { return sock; }
    2932