| 1 | Index: 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())) |
|---|
| 31 | Index: 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 | } |
|---|
| 76 | Index: 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) |
|---|
| 112 | Index: 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 | |
|---|
| 140 | Index: 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?")); |
|---|
| 160 | Index: 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 | |
|---|
| 174 | Index: 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 | |
|---|
| 242 | Index: 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)); |
|---|
| 264 | Index: 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 | |
|---|
| 326 | Index: 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); |
|---|
| 552 | Index: 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); |
|---|
| 565 | Index: 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); |
|---|
| 592 | Index: 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'}); |
|---|
| 678 | Index: 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) { |
|---|