Ticket #4242: myth_IOMultiplierV4_r19570.diff
File myth_IOMultiplierV4_r19570.diff, 29.3 KB (added by , 15 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 = 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 167 180 pthread_create(&writer, NULL, boot_writer, this); 168 181 pthread_create(&syncer, NULL, boot_syncer, this); 169 182 return true; … … 427 440 buffer is valid, and we try to write all of it at once which 428 441 takes a long time. During this time, the other thread fills up 429 442 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; 431 444 432 445 bool write_ok; 433 446 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( … … 937 937 return false; 938 938 } 939 939 940 941 940 if (dbver == "1050") 942 941 { 943 942 const char *updates[] = { … … 4396 4395 return false; 4397 4396 } 4398 4397 4398 if (dbver == "1228") 4399 { 4400 const char *updates[] = { 4401 "ALTER TABLE storagegroup ADD COLUMN io_multiplier TINYINT(1) NULL;", 4402 NULL 4403 }; 4404 if (!performActualUpdate(updates, "1229", dbver)) 4405 return false; 4406 } 4407 4399 4408 return true; 4400 4409 } 4401 4410 -
libs/libmythtv/RingBuffer.cpp
44 44 45 45 const uint RingBuffer::kBufferSize = 3 * 1024 * 1024; 46 46 47 #define CHUNK 32768 /*readblocksize increments */47 #define DEF_CHUNK 32768 /* default readblocksize increments */ 48 48 49 49 #define PNG_MIN_SIZE 20 /* header plus one empty chunk */ 50 50 #define NUV_MIN_SIZE 204 /* header size? */ … … 106 106 */ 107 107 RingBuffer::RingBuffer(const QString &lfilename, 108 108 bool write, bool readahead, 109 uint read_retries )109 uint read_retries, uint io_multiplier) 110 110 : filename(lfilename), 111 111 tfw(NULL), fd2(-1), 112 112 writemode(false), … … 121 121 readsallowed(false), wantseek(false), setswitchtonext(false), 122 122 rawbitrate(4000), playspeed(1.0f), 123 123 fill_threshold(65536), fill_min(-1), 124 readblocksize( CHUNK),wanttoread(0),124 readblocksize(DEF_CHUNK), wanttoread(0), 125 125 numfailures(0), commserror(false), 126 126 dvdPriv(NULL), oldfile(false), 127 127 livetvchain(NULL), ignoreliveeof(false), … … 130 130 filename.detach(); 131 131 pthread_rwlock_init(&rwlock, NULL); 132 132 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 133 141 if (write) 134 142 { 135 143 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); 137 146 138 147 if (!tfw->Open()) 139 148 { … … 144 153 return; 145 154 } 146 155 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 147 165 if (read_retries != (uint)-1) 148 166 OpenFile(filename, read_retries); 149 167 } … … 564 582 565 583 wantseek = false; 566 584 readsallowed = false; 567 readblocksize = CHUNK;585 readblocksize = read_chunk_size; 568 586 569 587 // loop without sleeping if the buffered data is less than this 570 fill_threshold = CHUNK* 2;588 fill_threshold = read_chunk_size * 2; 571 589 fill_min = 1; 572 590 573 591 #ifdef USING_FRONTEND … … 637 655 void RingBuffer::ResetReadAhead(long long newinternal) 638 656 { 639 657 readAheadLock.lock(); 640 readblocksize = CHUNK;658 readblocksize = read_chunk_size; 641 659 rbrpos = 0; 642 660 rbwpos = 0; 643 661 internalreadpos = newinternal; … … 762 780 763 781 struct timeval lastread, now; 764 782 gettimeofday(&lastread, NULL); 765 const int KB640 = 640*1024;766 783 int readtimeavg = 300; 767 784 int readinterval; 768 785 769 786 pausereadthread = false; 770 787 771 readAheadBuffer = new char[kBufferSize + KB640];788 readAheadBuffer = new char[kBufferSize + max_read_size]; 772 789 773 790 pthread_rwlock_wrlock(&rwlock); 774 791 ResetReadAhead(0); … … 822 839 823 840 readtimeavg = (readtimeavg * 9 + readinterval) / 10; 824 841 825 if (readtimeavg < 200 && readblocksize < KB640)842 if (readtimeavg < 200 && readblocksize < max_read_size) 826 843 { 827 readblocksize += CHUNK;844 readblocksize += read_chunk_size; 828 845 //VERBOSE(VB_PLAYBACK, 829 846 // QString("Avg read interval was %1 msec. %2K block size") 830 847 // .arg(readtimeavg).arg(readblocksize/1024)); 831 848 readtimeavg = 300; 832 849 } 833 else if (readtimeavg > 400 && readblocksize > CHUNK)850 else if (readtimeavg > 400 && readblocksize > read_chunk_size) 834 851 { 835 readblocksize -= CHUNK;852 readblocksize -= read_chunk_size; 836 853 //VERBOSE(VB_PLAYBACK, 837 854 // QString("Avg read interval was %1 msec. %2K block size") 838 855 // .arg(readtimeavg).arg(readblocksize/1024)); -
libs/libmythtv/tv_play.cpp
47 47 #include "datadirect.h" 48 48 #include "sourceutil.h" 49 49 #include "cardutil.h" 50 #include "storagegroup.h" 50 51 #include "channelutil.h" 51 52 #include "util-osx-cocoa.h" 52 53 #include "libmythdb/compat.h" … … 1668 1669 QString playbackURL = ctx->playingInfo->GetPlaybackURL(); 1669 1670 ctx->UnlockPlayingInfo(__FILE__, __LINE__); 1670 1671 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 1671 1680 bool opennow = (ctx->tvchain->GetCardType(-1) != "DUMMY"); 1672 1681 1673 1682 VERBOSE(VB_IMPORTANT, QString("We have a playbackURL(%1) & " … … 1675 1684 .arg(playbackURL).arg(ctx->tvchain->GetCardType(-1))); 1676 1685 1677 1686 ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true, 1678 opennow ? 12 : (uint)-1)); 1687 opennow ? 12 : (uint)-1, 1688 io_multiplier)); 1679 1689 ctx->buffer->SetLiveMode(ctx->tvchain); 1680 1690 } 1681 1691 … … 1740 1750 desiredNextState != kState_WatchingRecording); 1741 1751 ctx->UnlockPlayingInfo(__FILE__, __LINE__); 1742 1752 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)); 1744 1761 1745 1762 if (ctx->buffer && ctx->buffer->IsOpen()) 1746 1763 { … … 6023 6040 { 6024 6041 ctx->LockPlayingInfo(__FILE__, __LINE__); 6025 6042 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)); 6027 6051 ctx->tvchain->SetProgram(*ctx->playingInfo); 6028 6052 ctx->buffer->SetLiveMode(ctx->tvchain); 6029 6053 ctx->UnlockPlayingInfo(__FILE__, __LINE__); -
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::DEF_IO_MULTIPLIER); 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 -
libs/libmythtv/tv_rec.cpp
13 13 // Qt headers 14 14 #include <qapplication.h> 15 15 #include <qsqldatabase.h> 16 #include <qfileinfo.h> 17 #include <qdir.h> 16 18 17 19 // MythTV headers 18 20 #include "mythconfig.h" … … 4003 4005 4004 4006 if (lastTuningRequest.flags & kFlagRecording) 4005 4007 { 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)); 4007 4015 if (!ringBuffer->IsOpen()) 4008 4016 { 4009 4017 VERBOSE(VB_IMPORTANT, LOC_ERR + 4010 4018 QString("RingBuffer '%1' not open...") 4011 .arg( rec->GetFileName()));4019 .arg(filename)); 4012 4020 SetRingBuffer(NULL); 4013 4021 ClearFlags(kFlagPendingActions); 4014 4022 goto err_ret; … … 4373 4381 MythEvent me(QString("QUERY_NEXT_LIVETV_DIR %1").arg(cardid)); 4374 4382 gContext->dispatch(me); 4375 4383 4384 StorageGroup sgroup(prog->storagegroup, gContext->GetHostName()); 4385 4376 4386 if (WaitForNextLiveTVDir()) 4377 4387 { 4378 4388 QMutexLocker lock(&nextLiveTVDirLock); 4379 4389 prog->pathname = nextLiveTVDir; 4380 4390 } 4381 4391 else 4382 {4383 StorageGroup sgroup("LiveTV", gContext->GetHostName());4384 4392 prog->pathname = sgroup.FindNextDirMostFree(); 4385 }4386 4393 4387 4394 StartedRecording(prog); 4388 4395 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); 4390 4401 if (!(*rb)->IsOpen()) 4391 4402 { 4392 4403 VERBOSE(VB_IMPORTANT, LOC_ERR + 4393 4404 QString("RingBuffer '%1' not open...") 4394 .arg( prog->GetFileName()));4405 .arg(filename)); 4395 4406 4396 4407 delete *rb; 4397 4408 delete prog; -
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::DEF_IO_MULTIPLIER); 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.h> 5 6 6 7 #include "libmyth/settings.h" 7 8 #include "libmyth/mythwidgets.h" 8 9 10 class 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 37 class 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 66 class DirectoryConfig : public QObject, public ConfigurationWizard 67 { 68 public: 69 DirectoryConfig(QString &dir, uint &io_multiplier); 70 }; 71 9 72 class MPUBLIC StorageGroup: public ConfigurationWizard 10 73 { 11 74 public: … … 32 95 33 96 static QStringList getRecordingsGroups(void); 34 97 98 uint ioMultiplier(QString dirname); 99 100 static const uint DEF_IO_MULTIPLIER = 5; 101 35 102 private: 36 103 QString m_groupname; 37 104 QString m_hostname; 38 105 QStringList m_dirlist; 106 uint io_multiplier; 39 107 }; 40 108 41 109 class MPUBLIC StorageGroupEditor : … … 56 124 void doDelete(void); 57 125 58 126 protected: 127 void editDirectory(QString &dir, uint &io_multiplier); 128 59 129 QString m_group; 60 130 ListBoxSetting *listbox; 61 131 QString lastValue; 132 QMap<QString, uint> multiplier_map; 62 133 }; 63 134 64 135 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("directoryEdit", dir)); 33 group->addChild(new ioMultiplierSetting("multiplierEdit", io_multiplier)); 34 35 addChild(group); 36 } 37 38 23 39 /****************************************************************************/ 24 40 25 41 /** \brief StorageGroup constructor. … … 327 343 return groups; 328 344 } 329 345 346 uint 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 330 392 /****************************************************************************/ 331 393 typedef enum { 332 394 SGPopup_OK = 0, … … 401 463 402 464 if (name == "__CREATE_NEW_STORAGE_DIRECTORY__") 403 465 { 466 uint m_io_multiplier = StorageGroup::DEF_IO_MULTIPLIER; 404 467 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) 411 472 return; 412 473 413 474 if (name.isEmpty()) … … 417 478 name.append("/"); 418 479 419 480 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);"); 422 484 query.bindValue(":NAME", m_group); 423 485 query.bindValue(":DIRNAME", name); 486 query.bindValue(":IO_MULTIPLIER", m_io_multiplier); 424 487 query.bindValue(":HOSTNAME", gContext->GetHostName()); 425 488 if (!query.exec()) 426 489 MythDB::DBError("StorageGroupEditor::open", query); 427 490 else 428 491 lastValue = name; 429 492 } 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) 436 501 return; 437 502 438 503 if (name.right(1) != "/") … … 450 515 if (!query.exec()) 451 516 MythDB::DBError("StorageGroupEditor::open", query); 452 517 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);"); 455 521 query.bindValue(":NAME", m_group); 456 522 query.bindValue(":DIRNAME", name); 523 query.bindValue(":IO_MULTIPLIER", m_io_multiplier); 457 524 query.bindValue(":HOSTNAME", gContext->GetHostName()); 458 525 if (!query.exec()) 459 526 MythDB::DBError("StorageGroupEditor::open", query); … … 502 569 void StorageGroupEditor::Load(void) 503 570 { 504 571 listbox->clearSelections(); 572 multiplier_map.clear(); 505 573 506 574 MSqlQuery query(MSqlQuery::InitCon()); 507 query.prepare("SELECT dirname, i d FROM storagegroup "575 query.prepare("SELECT dirname, io_multiplier, id FROM storagegroup " 508 576 "WHERE groupname = :NAME AND hostname = :HOSTNAME " 509 577 "ORDER BY id;"); 510 578 query.bindValue(":NAME", m_group); … … 522 590 first = false; 523 591 } 524 592 listbox->addSelection(query.value(0).toString()); 593 multiplier_map[query.value(0).toString()] = query.value(1).toUInt(); 525 594 } 526 595 } 527 596 … … 548 617 return dialog; 549 618 } 550 619 620 551 621 /****************************************************************************/ 552 622 553 623 StorageGroupListEditor::StorageGroupListEditor(void) : -
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 = 0; 1058 1058 1059 QString filename = LocalFilePath(qurl, io_multiplier); 1060 1059 1061 FileTransfer *ft = NULL; 1060 1062 bool usereadahead = true; 1061 1063 int retries = -1; … … 1066 1068 } 1067 1069 1068 1070 if (retries >= 0) 1069 ft = new FileTransfer(filename, socket, usereadahead, retries); 1071 ft = new FileTransfer(filename, socket, usereadahead, retries, 1072 io_multiplier); 1070 1073 else 1071 ft = new FileTransfer(filename, socket );1074 ft = new FileTransfer(filename, socket, io_multiplier); 1072 1075 1073 1076 sockListLock.lock(); 1074 1077 fileTransferList.push_back(ft); … … 4349 4352 QApplication::exit(m_exitCode); 4350 4353 } 4351 4354 4352 QString MainServer::LocalFilePath(const QUrl &url )4355 QString MainServer::LocalFilePath(const QUrl &url, uint &io_multiplier) 4353 4356 { 4354 4357 QString lpath = url.path(); 4355 4358 4359 io_multiplier = StorageGroup::DEF_IO_MULTIPLIER; 4360 4356 4361 if (lpath.section('/', -2, -2) == "channels") 4357 4362 { 4358 4363 // This must be an icon request. Check channel.icon to be safe. … … 4386 4391 ProgramInfo *pginfo = ProgramInfo::GetProgramFromBasename(fpath); 4387 4392 if (pginfo) 4388 4393 { 4394 StorageGroup sgroup(pginfo->storagegroup, gContext->GetHostName()); 4395 QString dirname = 4396 sgroup.FindRecordingDir(pginfo->GetRecordBasename()); 4397 io_multiplier = sgroup.ioMultiplier(dirname); 4389 4398 QString pburl = GetPlaybackURL(pginfo); 4390 4399 if (pburl.left(1) == "/") 4391 4400 { … … 4410 4419 lpath = QFileInfo(lpath).fileName(); 4411 4420 StorageGroup sgroup; 4412 4421 QString tmpFile = sgroup.FindRecordingFile(lpath); 4422 QFileInfo fi(tmpFile); 4423 io_multiplier = sgroup.ioMultiplier(fi.absolutePath()); 4413 4424 if (!tmpFile.isEmpty()) 4414 4425 { 4415 4426 lpath = tmpFile; -
programs/mythbackend/filetransfer.h
13 13 #include <qmutex.h> 14 14 #include <qwaitcondition.h> 15 15 16 #include "storagegroup.h" 17 16 18 class RingBuffer; 17 19 class MythSocket; 18 20 … … 21 23 friend class QObject; // quiet OSX gcc warning 22 24 23 25 public: 24 FileTransfer(QString &filename, MythSocket *remote);25 26 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); 27 30 28 31 MythSocket *getSocket() { return sock; } 29 32