Ticket #1744: diff16.txt

File diff16.txt, 28.9 KB (added by ltd@…, 18 years ago)

updated patch (as of [11121], have been running this successfully for 5 months with no issues

Line 
1Index: libs/libmythtv/previewgenerator.cpp
2===================================================================
3--- libs/libmythtv/previewgenerator.cpp (revision 11121)
4+++ libs/libmythtv/previewgenerator.cpp (working copy)
5@@ -65,9 +65,23 @@
6     // Try to find a local means to access file...
7     QString baseName = programInfo.GetRecordBasename();
8     QString prefix   = gContext->GetSetting("RecordFilePrefix");
9-    QString localFN  = QString("%1/%2").arg(prefix).arg(baseName);
10-    if (!QFileInfo(localFN).exists())
11+    QString localFN;
12+
13+    // search through all recording directories
14+    bool found = false;
15+    QStringList recording_prefixes = QStringList::split(",",gContext->GetSetting("RecordFilePrefix"));
16+    for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
17     {
18+       if (!found)
19+       {
20+           localFN  = recording_prefixes[index] + "/" + baseName;
21+            if (QFileInfo(localFN).exists())
22+               found = true;
23+       }
24+    }
25+
26+    if (!found)
27+    {
28         // GetPlaybackURL tries to return a local filename if one exists
29         localFN = programInfo.GetPlaybackURL();
30         if (!(localFN.left(1) == "/" && QFileInfo(localFN).exists()))
31Index: libs/libmythtv/RingBuffer.cpp
32===================================================================
33--- libs/libmythtv/RingBuffer.cpp       (revision 11121)
34+++ libs/libmythtv/RingBuffer.cpp       (working copy)
35@@ -163,23 +163,33 @@
36 
37     bool is_local = false;
38     bool is_dvd = false;
39+    bool found = false;
40     (void) is_dvd; // not used when frontend is disabled.
41 
42     if ((filename.left(7) == "myth://") &&
43         (filename.length() > 7 ))
44     {
45-        QString local_pathname = gContext->GetSetting("RecordFilePrefix");
46+        QString local_pathname;
47         int hostlen = filename.find(QRegExp("/"), 7);
48 
49         if (hostlen != -1)
50         {
51-            local_pathname += filename.right(filename.length() - hostlen);
52+           // loop through our recording directories looking for it
53+           QStringList recording_prefixes = QStringList::split(",", gContext->GetSetting("RecordFilePrefix"));
54+           for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
55+           {
56+               if (!found)
57+               {
58+                   local_pathname = recording_prefixes[index] + filename.right(filename.length() - hostlen);
59 
60-            QFile checkFile(local_pathname);
61-            if (checkFile.exists())
62-            {
63-                is_local = true;
64-                filename = local_pathname;
65+                   QFile checkFile(local_pathname);
66+                   if (checkFile.exists())
67+                   {
68+                       found = true;
69+                       is_local = true;
70+                       filename = local_pathname;
71+                   }
72+               }
73             }
74         }
75     }
76Index: libs/libmythtv/tv_rec.cpp
77===================================================================
78--- libs/libmythtv/tv_rec.cpp   (revision 11121)
79+++ libs/libmythtv/tv_rec.cpp   (working copy)
80@@ -638,8 +638,29 @@
81     if (!curRec)
82         return;
83 
84-    curRec->StartedRecording(rbFilePrefix, rbFileExt);
85-    VERBOSE(VB_RECORD, LOC + "StartedRecording("<<curRec<<") fn("
86+    // choose a directory to store our recording into
87+    // if we have multiple directories to choose from, choose
88+    // the one with the most free space
89+    long long total, used;
90+    int chosen_index = -1;
91+    long long cur_free_space = -1, highest_free_space = -1;
92+    QStringList recording_prefixes = QStringList::split(",",rbFilePrefix);
93+    for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
94+    {
95+       cur_free_space = getDiskSpace(recording_prefixes[index], total, used);
96+       if (cur_free_space > highest_free_space)
97+       {
98+           highest_free_space = cur_free_space;
99+           chosen_index = index;
100+       }
101+       VERBOSE(VB_RECORD, LOC + QString("filesystem: (%1)%2, free: %3, total: %4, "
102+                                        "used: %5  (chosen %6)")
103+                                       .arg(index).arg(recording_prefixes[index]).arg(cur_free_space)
104+                                       .arg(total).arg(used).arg(chosen_index));
105+    }
106+
107+    curRec->StartedRecording(recording_prefixes[chosen_index], rbFileExt);
108+    VERBOSE(VB_RECORD, LOC + "StartedRecording LTD("<<curRec<<") fn("
109             <<curRec->GetFileName()<<")");
110 
111     if (curRec->chancommfree != 0)
112Index: libs/libmythtv/programinfo.cpp
113===================================================================
114--- libs/libmythtv/programinfo.cpp      (revision 11121)
115+++ libs/libmythtv/programinfo.cpp      (working copy)
116@@ -1458,6 +1458,23 @@
117  */
118 QString ProgramInfo::GetRecordFilename(const QString &prefix) const
119 {
120+    // since we support multiple recording directories, try to
121+    // find out which one we used for storing this file in ..
122+    // if we cannot find it then just fall back to existing
123+    // behavior
124+
125+    QStringList recording_prefixes = QStringList::split(",",prefix);
126+    QString filename;
127+    QString basename = GetRecordBasename();
128+    for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
129+    {
130+        filename = QString("%1/%2").arg(recording_prefixes[index]).arg(basename);
131+        QFile checkFile(filename);
132+        if (checkFile.exists())
133+            return filename;
134+    }
135+
136+    // bah - just return what we would have done previously
137     return QString("%1/%2").arg(prefix).arg(GetRecordBasename());
138 }               
139 
140Index: programs/mythtv-setup/checksetup.cpp
141===================================================================
142--- programs/mythtv-setup/checksetup.cpp        (revision 11121)
143+++ programs/mythtv-setup/checksetup.cpp        (working copy)
144@@ -60,8 +60,13 @@
145     if (query.size())
146     {
147         query.next();
148-        if (checkPath(query.value(0).toString(), probs))
149-            problemFound = true;
150+
151+       QStringList recording_prefixes = QStringList::split(",", query.value(0).toString());
152+       for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
153+       {
154+           if (checkPath(recording_prefixes[index], probs))
155+               problemFound = true;
156+       }
157     }
158     else
159         VERBOSE(VB_GENERAL, QString("RecordFilePrefix is not set?"));
160Index: programs/mythtv-setup/backendsettings.cpp
161===================================================================
162--- programs/mythtv-setup/backendsettings.cpp   (revision 11121)
163+++ programs/mythtv-setup/backendsettings.cpp   (working copy)
164@@ -70,7 +70,8 @@
165     gc->setLabel(QObject::tr("Directory to hold recordings"));
166     gc->setValue("/mnt/store/");
167     gc->setHelpText(QObject::tr("All recordings get stored in this "
168-                    "directory."));
169+                    "directory (multiple directories can be specified, "
170+                   "seperated by commas)."));
171     return gc;
172 };
173 
174Index: programs/mythbackend/mainserver.cpp
175===================================================================
176--- programs/mythbackend/mainserver.cpp (revision 11121)
177+++ programs/mythbackend/mainserver.cpp (working copy)
178@@ -1176,16 +1176,30 @@
179 
180             proginfo->stars = query.value(31).toDouble();
181 
182-            QString lpath = fileprefix + "/" + basename;
183+            // since we support multiple recording directories,
184+            // be sure to specify actual directory where file is
185+            // stored. if we cannot find it, fallback
186+            QString lpath;
187+            QStringList recording_prefixes = QStringList::split(",",fileprefix);
188+            int found_index = -1;
189+            for (int index = 0; index < (int)recording_prefixes.size() && found_index == -1; ++index)
190+            {
191+                lpath = recording_prefixes[index] + "/" + basename;
192+                QFile checkFile(lpath);
193+                if (checkFile.exists())
194+                    found_index = index;
195+            }
196+            if (found_index == -1)
197+                lpath = fileprefix + "/" + basename;
198+               
199             PlaybackSock *slave = NULL;
200-            QFile checkFile(lpath);
201 
202             if (proginfo->hostname != gContext->GetHostName())
203                 slave = getSlaveByHostname(proginfo->hostname);
204 
205-            if ((masterBackendOverride && checkFile.exists()) ||
206+            if ((masterBackendOverride && (found_index != -1)) ||
207                 (proginfo->hostname == gContext->GetHostName()) ||
208-                (!slave && checkFile.exists()))
209+                (!slave && (found_index != -1)))
210             {
211                 if (islocal)
212                     proginfo->pathname = lpath;
213@@ -1971,7 +1985,16 @@
214 {   
215     QStringList strlist;
216     long long totalKB = -1, usedKB = -1;
217-    getDiskSpace(recordfileprefix, totalKB, usedKB);
218+    long long cur_totalKB = -1, cur_usedKB = -1, cur_availKB = -1;
219+
220+    QStringList recording_prefixes = QStringList::split(",", recordfileprefix);
221+    for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
222+    {
223+        cur_availKB = getDiskSpace(recording_prefixes[index], cur_totalKB, cur_usedKB);
224+        totalKB += cur_totalKB;
225+        usedKB += cur_usedKB;
226+    }
227+
228     if (!allHosts)
229     {
230         encodeLongLong(strlist, totalKB);
231@@ -3814,8 +3837,9 @@
232     }
233     else
234     {
235+        QStringList recording_prefixes = QStringList::split(",", gContext->GetFilePrefix());
236         lpath = lpath.section('/', -1);
237-        lpath = gContext->GetFilePrefix() + "/" + lpath;
238+        lpath = recording_prefixes[0] + "/" + lpath;
239     }
240     VERBOSE(VB_FILE, QString("Local file path: %1").arg(lpath));
241 
242Index: programs/mythbackend/httpstatus.cpp
243===================================================================
244--- programs/mythbackend/httpstatus.cpp (revision 11121)
245+++ programs/mythbackend/httpstatus.cpp (working copy)
246@@ -1283,8 +1283,16 @@
247     // drive space   ---------------------
248 
249     long long iTotal = -1, iUsed = -1, iAvail = -1;
250+    long long cur_iTotal = -1, cur_iUsed = -1, cur_iAvail = -1;
251 
252-    iAvail = getDiskSpace( gContext->GetFilePrefix(), iTotal, iUsed);
253+    QStringList recording_prefixes = QStringList::split(",", gContext->GetFilePrefix());
254+    for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
255+    {
256+        cur_iAvail = getDiskSpace(recording_prefixes[index], cur_iTotal, cur_iUsed);
257+        iAvail += cur_iAvail;
258+        iTotal += cur_iTotal;
259+        iUsed += cur_iUsed;
260+    }
261 
262     storage.setAttribute("_local_total", (int)(iTotal>>10));
263     storage.setAttribute("_local_used" , (int)(iUsed>>10));
264Index: programs/mythbackend/main.cpp
265===================================================================
266--- programs/mythbackend/main.cpp       (revision 11121)
267+++ programs/mythbackend/main.cpp       (working copy)
268@@ -45,7 +45,6 @@
269 Scheduler *sched = NULL;
270 JobQueue *jobqueue = NULL;
271 QString pidfile;
272-QString lockfile_location;
273 HouseKeeper *housekeeping = NULL;
274 QString logfile = "";
275 
276@@ -216,7 +215,12 @@
277     if (pidfile != "")
278         unlink(pidfile.ascii());
279 
280-    unlink(lockfile_location.ascii());
281+    QStringList recording_prefixes = QStringList::split(",", gContext->GetSetting("RecordFilePrefix"));
282+    for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
283+    {
284+        QString lockfile_location = recording_prefixes[index] + "/nfslockfile.lock";
285+        unlink(lockfile_location.ascii());
286+    }
287 
288     signal(SIGHUP, SIG_DFL);
289 }
290@@ -645,8 +649,6 @@
291 
292     VERBOSE(VB_IMPORTANT, QString("Enabled verbose msgs: %1").arg(verboseString));
293 
294-    lockfile_location = gContext->GetSetting("RecordFilePrefix") + "/nfslockfile.lock";
295-
296     if (ismaster)
297 // Create a file in the recording directory.  A slave encoder will
298 // look for this file and return 0 bytes free if it finds it when it's
299@@ -655,14 +657,19 @@
300 // If the slave doesn't find this file then it will assume that it has
301 // a seperate store.
302     {
303-        if (creat(lockfile_location.ascii(), 0664) == -1)
304+        QStringList recording_prefixes = QStringList::split(",", gContext->GetSetting("RecordFilePrefix"));
305+        for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
306         {
307-            perror(lockfile_location.ascii());
308-            cerr << "Unable to open lockfile!\n"
309-                 << "Be sure that \'" << gContext->GetSetting("RecordFilePrefix")
310-                 << "\' exists and that both \nthe directory and that "
311-                 << "file are writeable by this user.\n";
312-            return BACKEND_EXIT_OPENING_VLOCKFILE_ERROR;
313+            QString lockfile_location = recording_prefixes[index] + "/nfslockfile.lock";
314+            if (creat(lockfile_location.ascii(), 0664) == -1)
315+            {
316+                perror(lockfile_location.ascii());
317+                cerr << "Unable to open lockfile!\n"
318+                    << "Be sure that \'" << gContext->GetSetting("RecordFilePrefix")
319+                    << "\' exists and that both \nthe directory and that "
320+                    << "file are writeable by this user.\n";
321+                return BACKEND_EXIT_OPENING_VLOCKFILE_ERROR;
322+            }
323         }
324     }
325 
326Index: programs/mythbackend/autoexpire.cpp
327===================================================================
328--- programs/mythbackend/autoexpire.cpp (revision 11121)
329+++ programs/mythbackend/autoexpire.cpp (working copy)
330@@ -115,10 +115,32 @@
331             sharing = true;
332         else if (enc->IsConnected())
333         {
334+
335+            // to support multiple recording directories, we need to base
336+            // the expiry interval based on the SMALLEST filesystem we have
337+            // to accomplish this, iterate over all our disks & use only
338+            // the one with the least free space
339             long long total, used;
340-            beginSize  = getDiskSpace(recordFilePrefix, total, used);
341+
342+            int chosen_index = -1;
343+            long long cur_free_space = -1, lowest_free_space = -1;
344+            QStringList recording_prefixes = QStringList::split(",",recordFilePrefix);
345+            for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
346+            {
347+                cur_free_space = getDiskSpace(recording_prefixes[index], total, used);
348+                if ((cur_free_space < lowest_free_space) || (chosen_index == -1))
349+                {
350+                    lowest_free_space = cur_free_space;
351+                    chosen_index = index;
352+                }
353+                DBG_CALC_PARAM(QString("filesystem: (%1)%2, free: %3, total: %4, used: %5  (chosen %6)")
354+                               .arg(index).arg(recording_prefixes[index]).arg(cur_free_space)
355+                               .arg(total).arg(used).arg(chosen_index));
356+            }
357+
358+            beginSize  = getDiskSpace(recording_prefixes[chosen_index], total, used);
359             remoteSize = enc->GetFreeDiskSpace();
360-            endSize    = getDiskSpace(recordFilePrefix, total, used);
361+            endSize    = getDiskSpace(recording_prefixes[chosen_index], total, used);
362 
363             DBG_CALC_PARAM("CalcParams() -- A 2");
364             if (beginSize<0 || remoteSize<0 || endSize<0)
365@@ -221,7 +243,7 @@
366  *
367  *   Every "AutoExpireFrequency" minutes this will delete as many
368  *   files as needed to free "AutoExpireDiskThreshold" gigabytes of
369- *   space on the filesystem containing "RecordFilePrefix".
370+ *   space on the filesystems containing "RecordFilePrefix".
371  *
372  *   If this is run on the master backend this will also delete
373  *   programs exceeding the maximum number of episodes of that
374@@ -330,10 +352,12 @@
375     long long availFreeKB = 0;
376     long long tKB, uKB;
377 
378-    if ((availFreeKB = getDiskSpace(record_file_prefix, tKB, uKB)) < 0)
379+    QStringList recording_prefixes = QStringList::split(",",record_file_prefix);
380+    // only ever store live tv on first recording directory ..
381+    if ((availFreeKB = getDiskSpace(recording_prefixes[0], tKB, uKB)) < 0)
382     {
383         QString msg = QString("ERROR: Could not calculate free space for %1.")
384-                              .arg(record_file_prefix);
385+                              .arg(recording_prefixes[0]);
386         VERBOSE(VB_IMPORTANT, LOC + msg);
387         gContext->LogEntry("mythbackend", LP_WARNING,
388                            "Autoexpire Recording", msg);
389@@ -343,7 +367,7 @@
390         VERBOSE(VB_FILE, LOC + QString("ExpireLiveTV(%1)").arg(type));
391         ClearExpireList();
392         FillDBOrdered(type);
393-        SendDeleteMessages(availFreeKB, 0, true);
394+        SendDeleteMessages(availFreeKB, 0, recording_prefixes[0], true);
395     }
396 }
397 
398@@ -356,39 +380,47 @@
399     long long availFreeKB = 0;
400     long long tKB, uKB;
401 
402-    if ((availFreeKB = getDiskSpace(record_file_prefix, tKB, uKB)) < 0)
403+    // loop through all our recording directories, checking for minimum
404+    // space on each.  trigger deletions if below that threshold..
405+    QStringList recording_prefixes = QStringList::split(",",record_file_prefix);
406+    for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
407     {
408-        QString msg = QString("ERROR: Could not calculate free space.");
409-        VERBOSE(VB_IMPORTANT, LOC + msg);
410-        gContext->LogEntry("mythbackend", LP_WARNING,
411-                           "Autoexpire Recording", msg);
412-    }
413-    else if (((size_t)availFreeKB) < desired_space)
414-    {
415-        VERBOSE(VB_FILE, LOC +
416-                QString("Running autoexpire, we want %1 MB free, "
417-                        "but only have %2 MB.")
418-                .arg(desired_space/1024).arg(availFreeKB/1024));
419+        if ((availFreeKB = getDiskSpace(recording_prefixes[index], tKB, uKB)) < 0)
420+        {
421+            QString msg = QString("ERROR: Could not calculate free space for %1.")
422+                                  .arg(recording_prefixes[index]);
423+            VERBOSE(VB_IMPORTANT, LOC + msg);
424+            gContext->LogEntry("mythbackend", LP_WARNING,
425+                               "Autoexpire Recording", msg);
426+        }
427+        else if (((size_t)availFreeKB) < desired_space)
428+        {
429+            VERBOSE(VB_FILE, LOC +
430+                    QString("Running autoexpire in %1, we want %2 MB free, "
431+                            "but only have %3 MB.")
432+                    .arg(recording_prefixes[index])
433+                    .arg(desired_space/1024).arg(availFreeKB/1024));
434         
435-        FillExpireList();
436-        SendDeleteMessages(availFreeKB, desired_space);
437+            FillExpireList();
438+            SendDeleteMessages(availFreeKB, desired_space, recording_prefixes[index]);
439+        }
440     }
441 }
442 
443-/** \fn CheckFile(const ProgramInfo*, const QString&, const fsid_t&)
444+/** \fn CheckFile(const ProgramInfo*, QString&, const fsid_t&)
445  *  \brief Returns true iff file can be deleted.
446  *
447  *   CheckFile makes sure the file exists and is stored on the same file
448  *   system as the recordfileprefix.
449  *  \param pginfo           ProgramInfo for the program we wish to delete.
450- *  \param recordfileprefix Path where new recordings are stored.
451+ *  \param dir              Path where we are looking for files to remove from.
452  *  \param fsid             Unique ID of recordfileprefix's filesystem.
453  */
454 static bool CheckFile(const ProgramInfo *pginfo,
455-                      const QString &recordfileprefix,
456+                      QString &dir,
457                       const fsid_t& fsid)
458 {
459-    QString filename = pginfo->GetRecordFilename(recordfileprefix);
460+    QString filename = pginfo->GetRecordFilename(dir);
461     QFileInfo checkFile(filename);
462     if (!checkFile.exists())
463     {
464@@ -402,7 +434,8 @@
465             gContext->LogEntry("mythbackend", LP_WARNING,
466                                "Autoexpire Recording", msg);
467         }
468-        else if (pginfo->hostname == gContext->GetHostName())
469+        else if ((pginfo->hostname == gContext->GetHostName()) &&
470+                 (dir == gContext->GetSetting("RecordFilePrefix")))
471         {
472             QString msg =
473                 QString("ERROR when trying to autoexpire file: %1. "
474@@ -427,36 +460,46 @@
475     return true;
476 }
477 
478-/** \fn AutoExpire::SendDeleteMessages(size_t, size_t, bool)
479+/** \fn AutoExpire::SendDeleteMessages(size_t, size_t, QString&, bool)
480  *  \brief This sends delete message to main event thread.
481  */
482 void AutoExpire::SendDeleteMessages(size_t availFreeKB, size_t desiredFreeKB,
483-                                    bool deleteAll)
484+                                    QString &dir, bool deleteAll)
485 {
486     QString msg;
487-    fsid_t fsid = UniqueFileSystemID(record_file_prefix);
488+    fsid_t fsid = UniqueFileSystemID(dir);
489 
490     if (expire_list.size() == 0)
491     {
492         if ((!deleteAll) &&
493             (desiredFreeKB > 0) &&
494             (availFreeKB < desiredFreeKB))
495-            VERBOSE(VB_FILE, LOC + "SendDeleteMessages. WARNING: below free "
496-                    "disk space threshold, but nothing to expire~");
497+        {
498+            QString msg =
499+                QString("SendDeleteMessages. WARNING: below free "
500+                        "disk space threshold, but nothing to expire~ "
501+                        "(%1, %2 available, %3 desired)")
502+                        .arg(dir).arg(availFreeKB).arg(desiredFreeKB);
503+            VERBOSE(VB_FILE, LOC + msg);
504+        }
505         else
506-            VERBOSE(VB_FILE, LOC + "SendDeleteMessages. Nothing to expire.");
507-
508+        {
509+            QString msg =
510+                QString("SendDeleteMessages. Nothing to expire. (%1)").arg(dir);
511+            VERBOSE(VB_FILE, LOC + msg);
512+        }
513         return;
514     }
515 
516-    VERBOSE(VB_FILE, LOC + "SendDeleteMessages, cycling through expire list.");
517+    VERBOSE(VB_FILE, LOC + QString("SendDeleteMessages, cycling through "
518+                                   "expire list (%1).").arg(dir));
519     pginfolist_t::iterator it = expire_list.begin();
520     while (it != expire_list.end() &&
521            (deleteAll || availFreeKB < desiredFreeKB))
522     {
523         VERBOSE(VB_FILE, QString("    Checking %1 @ %2")
524                          .arg((*it)->chanid).arg((*it)->startts.toString()));
525-        if (CheckFile(*it, record_file_prefix, fsid))
526+        if (CheckFile(*it, dir, fsid))
527         {
528             // Print informative message
529             QString titlestr = (*it)->title;
530@@ -475,9 +518,10 @@
531             }
532             else
533                 msg += QString(", free space is too low (have %1 MBytes free "
534-                               ", but want %2 MBytes)")
535+                               ", but want %2 MBytes on %3)")
536                                .arg(availFreeKB/1024)
537-                               .arg(desiredFreeKB/1024);
538+                               .arg(desiredFreeKB/1024)
539+                               .arg(dir);
540 
541             if (print_verbose_messages & VB_IMPORTANT)
542                 VERBOSE(VB_IMPORTANT, msg);
543@@ -510,7 +554,7 @@
544     if (!deleteAll && availFreeKB < desiredFreeKB)
545     {
546         msg = QString("ERROR when trying to autoexpire files.  "
547-                      "No recordings available to expire.");
548+                      "No recordings available to expire on %1.").arg(dir);
549         VERBOSE(VB_IMPORTANT, LOC + msg);
550         gContext->LogEntry("mythbackend", LP_WARNING,
551                            "Autoexpire Recording", msg);
552Index: programs/mythbackend/autoexpire.h
553===================================================================
554--- programs/mythbackend/autoexpire.h   (revision 11121)
555+++ programs/mythbackend/autoexpire.h   (working copy)
556@@ -60,7 +60,7 @@
557 
558     void FillDBOrdered(int expMethod, bool allHosts = false);
559     void SendDeleteMessages(size_t availFreeKB, size_t desiredFreeKB,
560-                            bool deleteAll = false);
561+                            QString &dir, bool deleteAll = false);
562     void ClearExpireList(void);
563     void Sleep(int sleepTime);
564     void WaitForPendingTruncates(void);
565Index: programs/mythbackend/encoderlink.cpp
566===================================================================
567--- programs/mythbackend/encoderlink.cpp        (revision 11121)
568+++ programs/mythbackend/encoderlink.cpp        (working copy)
569@@ -243,7 +243,21 @@
570     if (!use_cache)
571     {
572         if (local)
573-            freeDiskSpaceKB = getDiskSpace(recordfileprefix, totalKB, usedKB);
574+       {
575+           // since we can record to multiple mount points and always choose
576+           // the directory with the most free space, return just the space
577+           // for that one mount point
578+           long long cur_free_space;
579+           freeDiskSpaceKB = -1;
580+           QStringList recording_prefixes = QStringList::split(",",recordfileprefix);
581+           for (unsigned int index = 0; index < recording_prefixes.size(); ++index)
582+           {
583+               cur_free_space = getDiskSpace(recording_prefixes[index], totalKB, usedKB);
584+
585+               if (cur_free_space > freeDiskSpaceKB)
586+                   freeDiskSpaceKB = cur_free_space;
587+           }
588+       }
589         else if (sock)
590         {
591             sock->GetFreeDiskSpace(totalKB, usedKB);
592Index: contrib/mythrename.pl
593===================================================================
594--- contrib/mythrename.pl       (revision 11121)
595+++ contrib/mythrename.pl       (working copy)
596@@ -26,7 +26,7 @@
597 # Some variables we'll use here
598     our ($dest, $format, $usage, $underscores, $live);
599     our ($dformat, $dseparator, $dreplacement, $separator, $replacement);
600-    our ($db_host, $db_user, $db_name, $db_pass, $video_dir, $verbose);
601+    our ($db_host, $db_user, $db_name, $db_pass, $video_dirs, $verbose);
602     our ($hostname, $dbh, $sh, $sh2, $q, $q2, $count);
603 
604 # Default filename format
605@@ -233,16 +233,19 @@
606     $q = 'SELECT data FROM settings WHERE value="RecordFilePrefix" AND hostname=?';
607     $sh = $dbh->prepare($q);
608         $sh->execute($hostname) or die "Could not execute ($q):  $!\n\n";
609-    ($video_dir) = $sh->fetchrow_array;
610+    ($video_dirs) = $sh->fetchrow_array;
611     $sh->finish;
612-    die "This host not configured for myth.\n(No RecordFilePrefix defined for $hostname in the settings table.)\n\n" unless ($video_dir);
613-    die "Recordings directory $video_dir doesn't exist!\n\n" unless (-d $video_dir);
614-    $video_dir =~ s/\/+$//;
615+    die "This host not configured for myth.\n(No RecordFilePrefix defined for $hostname in the settings table.)\n\n" unless ($video_dirs);
616+    $video_dirs =~ s/\/+$//;
617+    @video_dir = split(/,/,$video_dirs);
618+    foreach $dir (@video_dir) {
619+        die "Recordings directory $dir doesn't exist!\n\n" unless (-d $dir);
620+    }
621 
622 # Link destination
623     if (defined($dest)) {
624     # Double-check the destination
625-        $dest ||= "$video_dir/show_names";
626+        $dest ||= $video_dir[0]."/show_names";
627     # Alert the user
628         vprint("Link destination directory:  $dest");
629     # Create nonexistent paths
630@@ -280,7 +283,15 @@
631     while (my $ref = $sh->fetchrow_hashref()) {
632         my %info = %{$ref};
633         die "This script requires mythtv >= 0.19\n" unless ($info{'basename'});
634-        next unless (-e "$video_dir/".$info{'basename'});
635+
636+        $found_dir = "";
637+        foreach $dir (@video_dir) {
638+            if (-e $dir."/".$info{'basename'}) {
639+                $found_dir = $dir;
640+            }
641+        }
642+        next unless ($found_dir ne "");
643+
644     # Default times
645         my ($syear, $smonth, $sday, $shour, $sminute, $ssecond) = $info{'starttime'} =~ /(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)/;
646         my ($eyear, $emonth, $eday, $ehour, $eminute, $esecond) = $info{'endtime'}   =~ /(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)/;
647@@ -400,17 +411,17 @@
648                 mkpath($directory, 0, 0755)
649                     or die "Failed to create $directory:  $!\n";
650             }
651-            symlink "$video_dir/".$info{'basename'}, "$dest/$name"
652+            symlink "$found_dir/".$info{'basename'}, "$dest/$name"
653                 or die "Can't create symlink $dest/$name:  $!\n";
654             vprint("$dest/$name");
655         }
656     # Rename the file, but only if it's a real file
657-        elsif (-f "$video_dir/".$info{'basename'}) {
658+        elsif (-f "$found_dir/".$info{'basename'}) {
659             if ($info{'basename'} ne $name.$suffix) {
660             # Check for duplicates
661-                if (-e "$video_dir/$name$suffix") {
662+                if (-e "$found_dir/$name$suffix") {
663                     $count = 2;
664-                    while (-e "$video_dir/$name.$count$suffix") {
665+                    while (-e "$found_dir/$name.$count$suffix") {
666                         $count++;
667                     }
668                     $name .= ".$count";
669@@ -419,7 +430,7 @@
670             # Update the database
671                 my $rows = $sh2->execute($name, $info{'chanid'}, $info{'starttime'});
672                 die "Couldn't update basename in database for ".$info{'basename'}.":  ($q2)\n" unless ($rows == 1);
673-                my $ret = rename "$video_dir/".$info{'basename'}, "$video_dir/$name";
674+                my $ret = rename "$found_dir/".$info{'basename'}, "$found_dir/$name";
675             # Rename failed -- Move the database back to how it was (man, do I miss transactions)
676                 if (!$ret) {
677                     $rows = $sh2->execute($info{'basename'}, $info{'chanid'}, $info{'starttime'});
678Index: contrib/myth.rebuilddatabase.pl
679===================================================================
680--- contrib/myth.rebuilddatabase.pl     (revision 11121)
681+++ contrib/myth.rebuilddatabase.pl     (working copy)
682@@ -210,7 +210,7 @@
683 }
684 
685 # remove trailing slash
686-$dir =~ s/\/$//;
687+# $dir =~ s/\/$//;
688 
689 if ($show_existing) {
690        $q = "select title, subtitle, starttime, endtime, chanid from recorded order by starttime";
691@@ -250,7 +250,7 @@
692 print "your database to see if the exist.  If they do not, you will be prompted\n";
693 print "for a title and subtitle of the entry, and a record will be created.\n\n";
694 
695-my @files = $file ? ($dir . "/" . $file) : glob("$dir/*.$ext");
696+my @files = $file ? ($dir . "/" . $file) : glob("{$dir}/*.$ext");
697 print "@files\n";
698 
699 foreach my $show (@files) {