Ticket #4242: 4242-v1.patch
| File 4242-v1.patch, 32.3 KB (added by , 17 years ago) |
|---|
-
libs/libmythtv/ThreadedFileWriter.cpp
27 27 #define LOC_ERR QString("TFW, Error: ") 28 28 29 29 const 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; 30 const uint ThreadedFileWriter::TFW_MAX_WRITE_SIZE = TFW_DEF_BUF_SIZE / 31 (128 / (2<<(5-1))); 32 const uint ThreadedFileWriter::TFW_MIN_WRITE_SIZE = TFW_DEF_BUF_SIZE / 33 (1024 / (2<<(5-1))); 32 34 33 35 /** \class ThreadedFileWriter 34 36 * \brief This class supports the writing of recordings to disk. … … 118 120 * \brief Creates a threaded file writer. 119 121 */ 120 122 ThreadedFileWriter::ThreadedFileWriter(const QString &fname, 121 int pflags, mode_t pmode) : 123 int pflags, mode_t pmode, 124 uint io_mult) : 122 125 // file stuff 123 126 filename(fname), flags(pflags), 124 127 mode(pmode), fd(-1), … … 130 133 rpos(0), wpos(0), 131 134 written(0), 132 135 // buffer 136 io_multiplier(io_mult), 133 137 buf(NULL), tfw_buf_size(0) 134 138 { 135 139 filename.detach(); … … 163 167 bzero(buf, TFW_DEF_BUF_SIZE + 64); 164 168 165 169 tfw_buf_size = TFW_DEF_BUF_SIZE; 166 tfw_min_write_size = TFW_MIN_WRITE_SIZE; 170 171 tfw_min_write_size = 172 TFW_DEF_BUF_SIZE / (1024 / (2<<(io_multiplier - 1))); 173 tfw_max_write_size = 174 TFW_DEF_BUF_SIZE / (128 / (2<<(io_multiplier - 1))); 175 176 VERBOSE(VB_RECORD, LOC + QString( 177 "Using io multiplier %1, min/max write = %2/%3") 178 .arg(io_multiplier) 179 .arg(tfw_min_write_size) 180 .arg(tfw_max_write_size)); 181 167 182 pthread_create(&writer, NULL, boot_writer, this); 168 183 pthread_create(&syncer, NULL, boot_syncer, this); 169 184 return true; … … 427 442 buffer is valid, and we try to write all of it at once which 428 443 takes a long time. During this time, the other thread fills up 429 444 the 10% that was free... */ 430 size = (size > TFW_MAX_WRITE_SIZE) ? TFW_MAX_WRITE_SIZE: size;445 size = (size > tfw_max_write_size) ? tfw_max_write_size : size; 431 446 432 447 bool write_ok; 433 448 if (ignore_writes) -
libs/libmythtv/dbcheck.cpp
18 18 #define MINIMUM_DBMS_VERSION 5,0,15 19 19 20 20 /// This is the DB schema version expected by the running MythTV instance. 21 const QString currentDatabaseVersion = "122 8";21 const QString currentDatabaseVersion = "1229"; 22 22 23 23 static bool UpdateDBVersionNumber(const QString &newnumber); 24 24 static bool performActualUpdate( … … 4396 4396 return false; 4397 4397 } 4398 4398 4399 if (dbver == "1228") 4400 { 4401 const char *updates[] = { 4402 "ALTER TABLE storagegroup ADD COLUMN io_multiplier TINYINT(1) " 4403 " NOT NULL default '5';", 4404 NULL 4405 }; 4406 if (!performActualUpdate(updates, "1229", dbver)) 4407 return false; 4408 } 4409 4399 4410 return true; 4400 4411 } 4401 4412 -
libs/libmythtv/RingBuffer.cpp
43 43 #endif 44 44 45 45 const uint RingBuffer::kBufferSize = 3 * 1024 * 1024; 46 const uint RingBuffer::kDefaultReadBlockSize = 8 * 4096; 46 47 47 #define CHUNK 32768 /* readblocksize increments */48 49 48 #define PNG_MIN_SIZE 20 /* header plus one empty chunk */ 50 49 #define NUV_MIN_SIZE 204 /* header size? */ 51 50 #define MPEG_MIN_SIZE 376 /* 2 TS packets */ … … 106 105 */ 107 106 RingBuffer::RingBuffer(const QString &lfilename, 108 107 bool write, bool readahead, 109 uint read_retries )108 uint read_retries, uint io_multiplier) 110 109 : filename(lfilename), 111 110 tfw(NULL), fd2(-1), 112 111 writemode(false), … … 121 120 readsallowed(false), wantseek(false), setswitchtonext(false), 122 121 rawbitrate(4000), playspeed(1.0f), 123 122 fill_threshold(65536), fill_min(-1), 124 readblocksize( CHUNK),wanttoread(0),123 readblocksize(kDefaultReadBlockSize), wanttoread(0), 125 124 numfailures(0), commserror(false), 126 125 dvdPriv(NULL), oldfile(false), 127 126 livetvchain(NULL), ignoreliveeof(false), … … 130 129 filename.detach(); 131 130 pthread_rwlock_init(&rwlock, NULL); 132 131 132 if ((io_multiplier > StorageGroup::kMaximumIOMultiplier) || 133 (io_multiplier < StorageGroup::kMinimumIOMultiplier)) 134 { 135 VERBOSE(VB_IMPORTANT, LOC + 136 QString("Read/Write multiplier value of %1 is " 137 "out of range [%2,%3], " 138 "setting to the default value %4.") 139 .arg(io_multiplier) 140 .arg(StorageGroup::kMinimumIOMultiplier) 141 .arg(StorageGroup::kMaximumIOMultiplier) 142 .arg(StorageGroup::kDefaultIOMultiplier)); 143 144 io_multiplier = StorageGroup::kDefaultIOMultiplier; 145 } 146 133 147 if (write) 134 148 { 135 149 tfw = new ThreadedFileWriter( 136 filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644); 150 filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644, 151 io_multiplier); 137 152 138 153 if (!tfw->Open()) 139 154 { … … 144 159 return; 145 160 } 146 161 162 read_chunk_size = (2<<(io_multiplier - 1)) * 1024; 163 max_read_size = 640 / (32 / (2<<(io_multiplier - 1))) * 1024; 164 165 VERBOSE(VB_GENERAL, LOC + QString( 166 "Using io multiplier %1, chunk/max = %2/%3") 167 .arg(io_multiplier).arg(read_chunk_size).arg(max_read_size)); 168 147 169 if (read_retries != (uint)-1) 148 170 OpenFile(filename, read_retries); 149 171 } … … 564 586 565 587 wantseek = false; 566 588 readsallowed = false; 567 readblocksize = CHUNK;589 readblocksize = read_chunk_size; 568 590 569 591 // loop without sleeping if the buffered data is less than this 570 fill_threshold = CHUNK* 2;592 fill_threshold = read_chunk_size * 2; 571 593 fill_min = 1; 572 594 573 595 #ifdef USING_FRONTEND … … 637 659 void RingBuffer::ResetReadAhead(long long newinternal) 638 660 { 639 661 readAheadLock.lock(); 640 readblocksize = CHUNK;662 readblocksize = read_chunk_size; 641 663 rbrpos = 0; 642 664 rbwpos = 0; 643 665 internalreadpos = newinternal; … … 762 784 763 785 struct timeval lastread, now; 764 786 gettimeofday(&lastread, NULL); 765 const int KB640 = 640*1024;766 787 int readtimeavg = 300; 767 788 int readinterval; 768 789 769 790 pausereadthread = false; 770 791 771 readAheadBuffer = new char[kBufferSize + KB640];792 readAheadBuffer = new char[kBufferSize + max_read_size]; 772 793 773 794 pthread_rwlock_wrlock(&rwlock); 774 795 ResetReadAhead(0); … … 822 843 823 844 readtimeavg = (readtimeavg * 9 + readinterval) / 10; 824 845 825 if (readtimeavg < 200 && readblocksize < KB640)846 if (readtimeavg < 200 && readblocksize < max_read_size) 826 847 { 827 readblocksize += CHUNK;848 readblocksize += read_chunk_size; 828 849 //VERBOSE(VB_PLAYBACK, 829 850 // QString("Avg read interval was %1 msec. %2K block size") 830 851 // .arg(readtimeavg).arg(readblocksize/1024)); 831 852 readtimeavg = 300; 832 853 } 833 else if (readtimeavg > 400 && readblocksize > CHUNK)854 else if (readtimeavg > 400 && readblocksize > read_chunk_size) 834 855 { 835 readblocksize -= CHUNK;856 readblocksize -= read_chunk_size; 836 857 //VERBOSE(VB_PLAYBACK, 837 858 // QString("Avg read interval was %1 msec. %2K block size") 838 859 // .arg(readtimeavg).arg(readblocksize/1024)); -
libs/libmythtv/tv_play.cpp
55 55 #include "mythdialogbox.h" 56 56 #include "mythmainwindow.h" 57 57 #include "mythscreenstack.h" 58 #include "storagegroup.h" 58 59 59 60 #ifndef HAVE_ROUND 60 61 #define round(x) ((int) ((x) + 0.5)) … … 1676 1677 else 1677 1678 { 1678 1679 ctx->LockPlayingInfo(__FILE__, __LINE__); 1679 QString playbackURL = ctx->playingInfo->GetPlaybackURL(); 1680 uint io_multiplier; 1681 QString playbackURL = ctx->playingInfo->GetPlaybackURL( 1682 false, false, &io_multiplier); 1680 1683 ctx->UnlockPlayingInfo(__FILE__, __LINE__); 1681 1684 1682 1685 bool opennow = (ctx->tvchain->GetCardType(-1) != "DUMMY"); … … 1685 1688 "cardtype(%2)") 1686 1689 .arg(playbackURL).arg(ctx->tvchain->GetCardType(-1))); 1687 1690 1688 ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true, 1689 opennow ? 12 : (uint)-1)); 1691 ctx->SetRingBuffer(new RingBuffer( 1692 playbackURL, false, true, 1693 opennow ? 12 : (uint)-1, io_multiplier)); 1690 1694 ctx->buffer->SetLiveMode(ctx->tvchain); 1691 1695 } 1692 1696 … … 1739 1743 TRANSITION(kState_None, kState_WatchingRecording)) 1740 1744 { 1741 1745 ctx->LockPlayingInfo(__FILE__, __LINE__); 1746 uint io_multiplier = StorageGroup::kDefaultIOMultiplier; 1742 1747 QString playbackURL; 1743 1748 if ((ctx->playingInfo->pathname.left(4) == "dvd:") || 1744 1749 (ctx->playingInfo->isVideo)) … … 1747 1752 playbackURL.detach(); 1748 1753 } 1749 1754 else 1755 { 1750 1756 playbackURL = ctx->playingInfo->GetPlaybackURL( 1751 desiredNextState != kState_WatchingRecording); 1757 desiredNextState != kState_WatchingRecording, 1758 false, &io_multiplier); 1759 } 1752 1760 ctx->UnlockPlayingInfo(__FILE__, __LINE__); 1753 1761 1754 ctx->SetRingBuffer(new RingBuffer(playbackURL, false)); 1762 ctx->SetRingBuffer(new RingBuffer( 1763 playbackURL, false, true, 12, io_multiplier)); 1755 1764 1756 1765 if (ctx->buffer && ctx->buffer->IsOpen()) 1757 1766 { … … 6031 6040 else 6032 6041 { 6033 6042 ctx->LockPlayingInfo(__FILE__, __LINE__); 6034 QString playbackURL = ctx->playingInfo->GetPlaybackURL(); 6035 ctx->SetRingBuffer(new RingBuffer(playbackURL, false)); 6043 uint io_multiplier; 6044 QString playbackURL = ctx->playingInfo->GetPlaybackURL( 6045 false, false, &io_multiplier); 6046 ctx->SetRingBuffer( 6047 new RingBuffer(playbackURL, false, true, 12, io_multiplier)); 6036 6048 ctx->tvchain->SetProgram(*ctx->playingInfo); 6037 6049 ctx->buffer->SetLiveMode(ctx->tvchain); 6038 6050 ctx->UnlockPlayingInfo(__FILE__, __LINE__); -
libs/libmythtv/programinfo.h
239 239 bool SetRecordBasename(QString basename); 240 240 QString GetRecordBasename(bool fromDB = false) const; 241 241 QString GetPlaybackURL(bool checkMaster = false, 242 bool forceCheckLocal = false); 242 bool forceCheckLocal = false, 243 uint *p_io_multiplier = NULL); 243 244 QString MakeUniqueKey(void) const; 244 245 int CalculateLength(void) const; 245 246 int SecsTillStart() const; -
libs/libmythtv/RingBuffer.h
13 13 } 14 14 15 15 #include "mythexp.h" 16 #include "storagegroup.h" 16 17 17 18 class RemoteFile; 18 19 class RemoteEncoder; … … 24 25 { 25 26 public: 26 27 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::kDefaultIOMultiplier); 28 30 ~RingBuffer(); 29 31 30 32 // Sets … … 126 128 long long readpos; 127 129 long long writepos; 128 130 131 uint read_chunk_size; 132 uint max_read_size; 133 129 134 bool stopreads; 130 135 131 136 mutable pthread_rwlock_t rwlock; … … 154 159 float playspeed; 155 160 int fill_threshold; 156 161 int fill_min; 157 intreadblocksize;162 uint readblocksize; 158 163 159 164 QWaitCondition pauseWait; 160 165 … … 184 189 185 190 // constants 186 191 static const uint kBufferSize; 192 static const uint kDefaultReadBlockSize; 187 193 static const uint kReadTestSize; 188 194 }; 189 195 -
libs/libmythtv/tv_rec.cpp
11 11 using namespace std; 12 12 13 13 // Qt headers 14 #include <qapplication.h> 15 #include <qsqldatabase.h> 14 #include <QFileInfo> 16 15 17 16 // MythTV headers 18 17 #include "mythconfig.h" … … 33 32 #include "previewgenerator.h" 34 33 #include "storagegroup.h" 35 34 #include "remoteutil.h" 35 #include "storagegroup.h" 36 36 37 37 #include "atscstreamdata.h" 38 38 #include "dvbstreamdata.h" … … 76 76 77 77 static bool is_dishnet_eit(int cardid); 78 78 static QString load_profile(QString,void*,ProgramInfo*,RecordingProfile&); 79 static uint calc_io_mult(const ProgramInfo*); 79 80 80 81 /** \class TVRec 81 82 * \brief This is the coordinating class of the \ref recorder_subsystem. … … 4003 4004 4004 4005 if (lastTuningRequest.flags & kFlagRecording) 4005 4006 { 4006 SetRingBuffer(new RingBuffer(rec->GetFileName(), true)); 4007 uint iom = calc_io_mult(rec); 4008 SetRingBuffer(new RingBuffer(rec->GetFileName(), true, true, 12, iom)); 4007 4009 if (!ringBuffer->IsOpen()) 4008 4010 { 4009 4011 VERBOSE(VB_IMPORTANT, LOC_ERR + … … 4386 4388 4387 4389 StartedRecording(prog); 4388 4390 4389 *rb = new RingBuffer(prog->GetFileName(), true); 4391 uint iom = calc_io_mult(prog); 4392 *rb = new RingBuffer(prog->GetFileName(), true, true, 12, iom); 4390 4393 if (!(*rb)->IsOpen()) 4391 4394 { 4392 4395 VERBOSE(VB_IMPORTANT, LOC_ERR + … … 4500 4503 .arg(TVRec::FlagToString(flags)); 4501 4504 } 4502 4505 4506 static uint calc_io_mult(const ProgramInfo *pginfo) 4507 { 4508 StorageGroup sgroup(pginfo->storagegroup, gContext->GetHostName()); 4509 return sgroup.QueryIOMultiplier( 4510 QFileInfo(pginfo->GetFileName()).absolutePath()); 4511 } 4512 4503 4513 /* vim: set expandtab tabstop=4 shiftwidth=4: */ 4504 4514 -
libs/libmythtv/programinfo.cpp
1621 1621 * If the file is accessible locally, the filename will be returned, 1622 1622 * otherwise a myth:// URL will be returned. 1623 1623 */ 1624 QString ProgramInfo::GetPlaybackURL(bool checkMaster, bool forceCheckLocal) 1624 QString ProgramInfo::GetPlaybackURL( 1625 bool checkMaster, bool forceCheckLocal, uint *p_io_multiplier) 1625 1626 { 1626 1627 QString tmpURL; 1627 1628 QString basename = GetRecordBasename(true); 1628 1629 1629 1630 bool alwaysStream = gContext->GetNumSetting("AlwaysStreamFiles", 0); 1630 1631 1632 if (p_io_multiplier) 1633 *p_io_multiplier = StorageGroup::kDefaultIOMultiplier; 1634 1631 1635 if ((!alwaysStream) || 1632 1636 (forceCheckLocal) || 1633 1637 (hostname == gContext->GetHostName())) 1634 1638 { 1635 1639 // Check to see if the file exists locally 1636 1640 StorageGroup sgroup(storagegroup); 1637 tmpURL = sgroup.FindRecordingFile(basename);1641 QString dirname = sgroup.FindRecordingDir(basename); 1638 1642 1639 if ( tmpURL != "")1643 if (!dirname.isEmpty()) 1640 1644 { 1645 tmpURL = dirname + "/" + basename; 1641 1646 VERBOSE(VB_FILE, LOC + 1642 1647 QString("GetPlaybackURL: File is local: '%1'").arg(tmpURL)); 1648 1649 if (p_io_multiplier) 1650 *p_io_multiplier = sgroup.QueryIOMultiplier(dirname); 1651 1643 1652 return tmpURL; 1644 1653 } 1645 1654 else if (hostname == gContext->GetHostName()) -
libs/libmythtv/ThreadedFileWriter.h
7 7 #include <qwaitcondition.h> 8 8 #include <qstring.h> 9 9 10 #include "storagegroup.h" 11 10 12 class ThreadedFileWriter 11 13 { 12 14 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::kDefaultIOMultiplier); 14 17 ~ThreadedFileWriter(); 15 18 16 19 bool Open(void); … … 43 46 int flags; 44 47 mode_t mode; 45 48 int fd; 49 uint io_multiplier; 46 50 47 51 // state 48 52 bool no_writes; … … 51 55 bool in_dtor; 52 56 bool ignore_writes; 53 57 long long tfw_min_write_size; 58 long long tfw_max_write_size; 54 59 55 60 // buffer position state 56 61 uint rpos; ///< points to end of data written to disk -
libs/libmyth/storagegroup.h
2 2 #define _STORAGEGROUP_H 3 3 4 4 #include <QStringList> 5 #include <QMap> 5 6 6 7 #include "libmyth/settings.h" 7 8 #include "libmyth/mythwidgets.h" … … 32 33 33 34 static QStringList getRecordingsGroups(void); 34 35 36 uint QueryIOMultiplier(const QString &dirname); 37 38 static const uint kSentinelIOMultiplier = 1; 39 static const uint kDefaultIOMultiplier = 5; 40 static const uint kMinimumIOMultiplier = 2; 41 static const uint kMaximumIOMultiplier = 5; 42 35 43 private: 36 44 QString m_groupname; 37 45 QString m_hostname; 38 46 QStringList m_dirlist; 47 uint io_multiplier; 39 48 }; 40 49 50 class DirectoryPathSetting : public TransLineEditSetting 51 { 52 public: 53 DirectoryPathSetting(QString &dir) : 54 TransLineEditSetting(true), m_dir(dir) 55 { 56 setLabel(QObject::tr("Directory Path")); 57 QString help = QObject::tr( 58 "Specify a path to add to this storage group."); 59 setHelpText(help); 60 } 61 62 virtual void Load(void) 63 { 64 setValue(m_dir); 65 } 66 67 virtual void Save(void) 68 { 69 m_dir = getValue(); 70 } 71 72 private: 73 QString &m_dir; 74 }; 75 76 class DirectoryConfig : public ConfigurationWizard 77 { 78 public: 79 DirectoryConfig(QString &dir, uint &io_multiplier); 80 }; 81 82 class IOMultiplierSetting : public TransSpinBoxSetting 83 { 84 public: 85 IOMultiplierSetting(uint &io_multiplier) : 86 TransSpinBoxSetting(StorageGroup::kMinimumIOMultiplier, 87 StorageGroup::kMaximumIOMultiplier, 1), 88 m_io_multiplier(io_multiplier) 89 { 90 setLabel(QObject::tr("Read/Write Buffer")); 91 QString help = QObject::tr( 92 "Specify the amount of buffering to " 93 "use for this directory. Default %1. " 94 "Use caution when adjusting this.") 95 .arg(StorageGroup::kDefaultIOMultiplier); 96 setHelpText(help); 97 } 98 99 virtual void Load(void) 100 { 101 setValue(m_io_multiplier); 102 } 103 104 virtual void Save(void) 105 { 106 m_io_multiplier = getValue().toUInt(); 107 } 108 109 private: 110 uint &m_io_multiplier; 111 }; 112 41 113 class MPUBLIC StorageGroupEditor : 42 114 public QObject, public ConfigurationDialog 43 115 { … … 56 128 void doDelete(void); 57 129 58 130 protected: 131 void editDirectory(QString &dir, uint &io_multiplier); 132 59 133 QString m_group; 60 134 ListBoxSetting *listbox; 61 135 QString lastValue; 136 QMap<QString, uint> multiplier_map; 62 137 }; 63 138 64 139 class MPUBLIC StorageGroupListEditor : -
libs/libmyth/storagegroup.cpp
20 20 << "DB Backups" 21 21 ; 22 22 23 DirectoryConfig::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(dir)); 33 group->addChild(new IOMultiplierSetting(io_multiplier)); 34 35 addChild(group); 36 } 37 23 38 /****************************************************************************/ 24 39 25 40 /** \brief StorageGroup constructor. … … 327 342 return groups; 328 343 } 329 344 345 uint StorageGroup::QueryIOMultiplier(const QString &dirname) 346 { 347 if (dirname.isEmpty() || m_groupname.isEmpty() || m_hostname.isEmpty()) 348 return StorageGroup::kDefaultIOMultiplier; 349 350 QString dirname_t = dirname; 351 352 if (dirname.endsWith("/")) 353 dirname_t.chop(1); 354 else 355 dirname_t.append("/"); 356 357 uint io_multiplier; 358 MSqlQuery query(MSqlQuery::InitCon()); 359 360 query.prepare("SELECT io_multiplier FROM storagegroup " 361 "WHERE groupname = :GROUP " 362 "AND hostname = :HOSTNAME " 363 "AND (dirname = :DIRNAME " 364 "OR dirname = :DIRNAME_T);"); 365 query.bindValue(":GROUP", m_groupname); 366 query.bindValue(":HOSTNAME", m_hostname); 367 query.bindValue(":DIRNAME", dirname); 368 query.bindValue(":DIRNAME_T", dirname_t); 369 370 if (!query.exec()) 371 { 372 MythDB::DBError("StorageGroup::QueryIOMultiplier()", query); 373 374 return StorageGroup::kDefaultIOMultiplier; 375 } 376 else if (!query.next()) 377 { 378 VERBOSE(VB_FILE, LOC + QString( 379 "Unable to find storage group '%1' on host %2, " 380 "using default io_multiplier of %3.") 381 .arg(m_groupname).arg(m_hostname) 382 .arg(StorageGroup::kDefaultIOMultiplier)); 383 384 return StorageGroup::kDefaultIOMultiplier; 385 } 386 387 io_multiplier = query.value(0).toUInt(); 388 389 if ((io_multiplier > kMaximumIOMultiplier) || 390 (io_multiplier < kMinimumIOMultiplier)) 391 { 392 VERBOSE(VB_IMPORTANT, LOC + 393 QString( 394 "Read/Write multiplier value of %1 for storage group " 395 "'%2' on host %3 " 396 "\n\t\t\tis out of range [%4,%5], setting to the " 397 "default value %6.") 398 .arg(io_multiplier).arg(m_groupname).arg(m_hostname) 399 .arg(kMinimumIOMultiplier) 400 .arg(kMaximumIOMultiplier) 401 .arg(kDefaultIOMultiplier)); 402 403 io_multiplier = StorageGroup::kDefaultIOMultiplier; 404 } 405 406 return io_multiplier; 407 } 408 330 409 /****************************************************************************/ 331 410 typedef enum { 332 411 SGPopup_OK = 0, … … 401 480 402 481 if (name == "__CREATE_NEW_STORAGE_DIRECTORY__") 403 482 { 483 uint m_io_multiplier = StorageGroup::kDefaultIOMultiplier; 404 484 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) 485 486 DirectoryConfig config(name, m_io_multiplier); 487 488 if (config.exec() != MythDialog::Accepted) 411 489 return; 412 490 413 491 if (name.isEmpty()) … … 417 495 name.append("/"); 418 496 419 497 MSqlQuery query(MSqlQuery::InitCon()); 420 query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) " 421 "VALUES (:NAME, :HOSTNAME, :DIRNAME);"); 498 query.prepare("INSERT INTO storagegroup (groupname, hostname, " 499 "dirname, io_multiplier) " 500 "VALUES (:NAME, :HOSTNAME, :DIRNAME, :IO_MULTIPLIER);"); 422 501 query.bindValue(":NAME", m_group); 423 502 query.bindValue(":DIRNAME", name); 503 query.bindValue(":IO_MULTIPLIER", m_io_multiplier); 424 504 query.bindValue(":HOSTNAME", gContext->GetHostName()); 425 505 if (!query.exec()) 426 506 MythDB::DBError("StorageGroupEditor::open", query); 427 507 else 428 508 lastValue = name; 429 } 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) 509 } 510 else 511 { 512 uint m_io_multiplier = multiplier_map[name]; 513 if (!m_io_multiplier) 514 m_io_multiplier = StorageGroup::kDefaultIOMultiplier; 515 516 DirectoryConfig config(name, m_io_multiplier); 517 518 if (config.exec() != MythDialog::Accepted) 436 519 return; 437 520 438 521 if (name.right(1) != "/") … … 450 533 if (!query.exec()) 451 534 MythDB::DBError("StorageGroupEditor::open", query); 452 535 453 query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) " 454 "VALUES (:NAME, :HOSTNAME, :DIRNAME);"); 536 query.prepare("INSERT INTO storagegroup (groupname, hostname, " 537 "dirname, io_multiplier) " 538 "VALUES (:NAME, :HOSTNAME, :DIRNAME, :IO_MULTIPLIER)"); 455 539 query.bindValue(":NAME", m_group); 456 540 query.bindValue(":DIRNAME", name); 541 query.bindValue(":IO_MULTIPLIER", m_io_multiplier); 457 542 query.bindValue(":HOSTNAME", gContext->GetHostName()); 458 543 if (!query.exec()) 459 544 MythDB::DBError("StorageGroupEditor::open", query); … … 502 587 void StorageGroupEditor::Load(void) 503 588 { 504 589 listbox->clearSelections(); 590 multiplier_map.clear(); 505 591 506 592 MSqlQuery query(MSqlQuery::InitCon()); 507 query.prepare("SELECT dirname, i d FROM storagegroup "593 query.prepare("SELECT dirname, io_multiplier, id FROM storagegroup " 508 594 "WHERE groupname = :NAME AND hostname = :HOSTNAME " 509 595 "ORDER BY id;"); 510 596 query.bindValue(":NAME", m_group); … … 522 608 first = false; 523 609 } 524 610 listbox->addSelection(query.value(0).toString()); 611 multiplier_map[query.value(0).toString()] = query.value(1).toUInt(); 525 612 } 526 613 } 527 614 -
programs/mythbackend/mainserver.h
150 150 FileTransfer *getFileTransferByID(int id); 151 151 FileTransfer *getFileTransferBySock(MythSocket *socket); 152 152 153 QString LocalFilePath(const QUrl &url );153 QString LocalFilePath(const QUrl &url, uint &io_multiplier); 154 154 155 155 static void *SpawnDeleteThread(void *param); 156 156 void DoDeleteThread(const DeleteStruct *ds); -
programs/mythbackend/filetransfer.cpp
8 8 #include "mythsocket.h" 9 9 10 10 FileTransfer::FileTransfer(QString &filename, MythSocket *remote, 11 bool usereadahead, int retries ) :11 bool usereadahead, int retries, uint io_mult) : 12 12 readthreadlive(true), readsLocked(false), 13 rbuffer(new RingBuffer(filename, false, usereadahead, retries )),13 rbuffer(new RingBuffer(filename, false, usereadahead, retries, io_mult)), 14 14 sock(remote), ateof(false), lock(QMutex::NonRecursive), 15 15 refLock(QMutex::NonRecursive), refCount(0) 16 16 { 17 17 } 18 18 19 FileTransfer::FileTransfer(QString &filename, MythSocket *remote) : 19 FileTransfer::FileTransfer(QString &filename, MythSocket *remote, 20 uint io_mult) : 20 21 readthreadlive(true), readsLocked(false), 21 rbuffer(new RingBuffer(filename, false )),22 rbuffer(new RingBuffer(filename, false, true, 12, io_mult)), 22 23 sock(remote), ateof(false), lock(QMutex::NonRecursive), 23 24 refLock(QMutex::NonRecursive), refCount(0) 24 25 { -
programs/mythbackend/mainserver.cpp
1054 1054 VERBOSE(VB_IMPORTANT, QString("adding: %1 as a remote file transfer") 1055 1055 .arg(commands[2])); 1056 1056 QUrl qurl = slist[1]; 1057 QString filename = LocalFilePath(qurl); 1057 uint io_multiplier; 1058 QString filename = LocalFilePath(qurl, io_multiplier); 1058 1059 1059 1060 FileTransfer *ft = NULL; 1060 1061 bool usereadahead = true; … … 1066 1067 } 1067 1068 1068 1069 if (retries >= 0) 1069 ft = new FileTransfer(filename, socket, usereadahead, retries); 1070 { 1071 ft = new FileTransfer( 1072 filename, socket, usereadahead, retries, io_multiplier); 1073 } 1070 1074 else 1071 ft = new FileTransfer(filename, socket); 1075 { 1076 ft = new FileTransfer(filename, socket, io_multiplier); 1077 } 1072 1078 1073 1079 sockListLock.lock(); 1074 1080 fileTransferList.push_back(ft); … … 4349 4355 QApplication::exit(m_exitCode); 4350 4356 } 4351 4357 4352 QString MainServer::LocalFilePath(const QUrl &url )4358 QString MainServer::LocalFilePath(const QUrl &url, uint &io_multiplier) 4353 4359 { 4354 4360 QString lpath = url.path(); 4355 4361 4362 io_multiplier = StorageGroup::kDefaultIOMultiplier; 4363 4356 4364 if (lpath.section('/', -2, -2) == "channels") 4357 4365 { 4358 4366 // This must be an icon request. Check channel.icon to be safe. … … 4386 4394 ProgramInfo *pginfo = ProgramInfo::GetProgramFromBasename(fpath); 4387 4395 if (pginfo) 4388 4396 { 4389 QString pburl = GetPlaybackURL(pginfo);4397 QString pburl = pginfo->GetPlaybackURL(false, true, &io_multiplier); 4390 4398 if (pburl.left(1) == "/") 4391 4399 { 4392 4400 lpath = pburl.section('/', 0, -2) + "/" + lpath; … … 4410 4418 lpath = QFileInfo(lpath).fileName(); 4411 4419 StorageGroup sgroup; 4412 4420 QString tmpFile = sgroup.FindRecordingFile(lpath); 4421 QFileInfo fi(tmpFile); 4422 io_multiplier = sgroup.QueryIOMultiplier(fi.absolutePath()); 4413 4423 if (!tmpFile.isEmpty()) 4414 4424 { 4415 4425 lpath = tmpFile; -
programs/mythbackend/backendutil.cpp
355 355 QString GetPlaybackURL(ProgramInfo *pginfo, bool storePath) 356 356 { 357 357 QString result = ""; 358 358 359 QMutexLocker locker(&recordingPathLock); 359 360 QString cacheKey = QString("%1:%2").arg(pginfo->chanid) 360 .arg(pginfo->recstartts.toString(Qt::ISODate)); 361 .arg(pginfo->recstartts.toString(Qt::ISODate)); 362 361 363 if ((recordingPathCache.contains(cacheKey)) && 362 364 (QFile::exists(recordingPathCache[cacheKey]))) 363 365 { -
programs/mythbackend/filetransfer.h
9 9 using namespace std; 10 10 11 11 // Qt headers 12 #include < qstring.h>13 #include < qmutex.h>14 #include < qwaitcondition.h>12 #include <QString> 13 #include <QMutex> 14 #include <QWaitCondition> 15 15 16 // MythTV headers 17 #include "storagegroup.h" 18 16 19 class RingBuffer; 17 20 class MythSocket; 18 21 … … 21 24 friend class QObject; // quiet OSX gcc warning 22 25 23 26 public: 24 FileTransfer(QString &filename, MythSocket *remote);25 27 FileTransfer(QString &filename, MythSocket *remote, 26 bool usereadahead, int retries); 28 uint io_mult = StorageGroup::kDefaultIOMultiplier); 29 FileTransfer(QString &filename, MythSocket *remote, 30 bool usereadahead, int retries, 31 uint io_mult = StorageGroup::kDefaultIOMultiplier); 27 32 28 33 MythSocket *getSocket() { return sock; } 29 34
