X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/fa321bf3dbf363879cfc799b6c1cc4e5af50ffd8..196fd13629fc0f673b18735d633bdf69a3272590:/methods/mirror.cc diff --git a/methods/mirror.cc b/methods/mirror.cc index bdd783cc7..5a53d3c81 100644 --- a/methods/mirror.cc +++ b/methods/mirror.cc @@ -25,6 +25,8 @@ using namespace std; +#include + #include "mirror.h" #include "http.h" #include "apti18n.h" @@ -104,7 +106,7 @@ bool MirrorMethod::Clean(string Dir) for(I=list.begin(); I != list.end(); I++) { string uri = (*I)->GetURI(); - if(uri.substr(0,strlen("mirror://")) != string("mirror://")) + if(uri.find("mirror://") != 0) continue; string BaseUri = uri.substr(0,uri.size()-1); if (URItoFileName(BaseUri) == Dir->d_name) @@ -123,44 +125,81 @@ bool MirrorMethod::Clean(string Dir) bool MirrorMethod::DownloadMirrorFile(string mirror_uri_str) { - - // check the file, if it is not older than RefreshInterval just use it - // otherwise try to get a new one - if(FileExists(MirrorFile)) - { - struct stat buf; - time_t t,now,refresh; - if(stat(MirrorFile.c_str(), &buf) != 0) - return false; - t = std::max(buf.st_mtime, buf.st_ctime); - now = time(NULL); - refresh = 60*_config->FindI("Acquire::Mirror::RefreshInterval",360); - if(t + refresh > now) - { - if(Debug) - clog << "Mirror file is in RefreshInterval" << endl; - DownloadedMirrorFile = true; - return true; - } - if(Debug) - clog << "Mirror file " << MirrorFile << " older than " << refresh << "min, re-download it" << endl; - } - // not that great to use pkgAcquire here, but we do not have // any other way right now string fetch = BaseUri; fetch.replace(0,strlen("mirror://"),"http://"); + if(Debug) + clog << "MirrorMethod::DownloadMirrorFile(): '" << fetch << "'" + << " to " << MirrorFile << endl; + pkgAcquire Fetcher; new pkgAcqFile(&Fetcher, fetch, "", 0, "", "", "", MirrorFile); bool res = (Fetcher.Run() == pkgAcquire::Continue); if(res) DownloadedMirrorFile = true; Fetcher.Shutdown(); + + if(Debug) + clog << "MirrorMethod::DownloadMirrorFile() success: " << res << endl; + return res; } -bool MirrorMethod::SelectMirror() +/* convert a the Queue->Uri back to the mirror base uri and look + * at all mirrors we have for this, this is needed as queue->uri + * may point to different mirrors (if TryNextMirror() was run) + */ +void MirrorMethod::CurrentQueueUriToMirror() +{ + // already in mirror:// style so nothing to do + if(Queue->Uri.find("mirror://") == 0) + return; + + // find current mirror and select next one + for (vector::const_iterator mirror = AllMirrors.begin(); + mirror != AllMirrors.end(); ++mirror) + { + if (Queue->Uri.find(*mirror) == 0) + { + Queue->Uri.replace(0, mirror->length(), BaseUri); + return; + } + } + _error->Error("Internal error: Failed to convert %s back to %s", + Queue->Uri.c_str(), BaseUri.c_str()); +} + +bool MirrorMethod::TryNextMirror() +{ + // find current mirror and select next one + for (vector::const_iterator mirror = AllMirrors.begin(); + mirror != AllMirrors.end(); ++mirror) + { + if (Queue->Uri.find(*mirror) != 0) + continue; + + vector::const_iterator nextmirror = mirror + 1; + if (nextmirror == AllMirrors.end()) + break; + Queue->Uri.replace(0, mirror->length(), *nextmirror); + if (Debug) + clog << "TryNextMirror: " << Queue->Uri << endl; + + // inform parent + UsedMirror = *nextmirror; + Log("Switching mirror"); + return true; + } + + if (Debug) + clog << "TryNextMirror could not find another mirror to try" << endl; + + return false; +} + +bool MirrorMethod::InitMirrors() { // if we do not have a MirrorFile, fallback if(!FileExists(MirrorFile)) @@ -177,10 +216,14 @@ bool MirrorMethod::SelectMirror() // get into sync issues (got indexfiles from mirror A, // but packages from mirror B - one might be out of date etc) ifstream in(MirrorFile.c_str()); - getline(in, Mirror); - if(Debug) - cerr << "Using mirror: " << Mirror << endl; - + string s; + while (!in.eof()) + { + getline(in, s); + if (s.size() > 0) + AllMirrors.push_back(s); + } + Mirror = AllMirrors[0]; UsedMirror = Mirror; return true; } @@ -251,6 +294,9 @@ string MirrorMethod::GetMirrorFileName(string mirror_uri_str) depth. */ bool MirrorMethod::Fetch(FetchItem *Itm) { + if(Debug) + clog << "MirrorMethod::Fetch()" << endl; + // the http method uses Fetch(0) as a way to update the pipeline, // just let it do its work in this case - Fetch() with a valid // Itm will always run before the first Fetch(0) @@ -269,14 +315,20 @@ bool MirrorMethod::Fetch(FetchItem *Itm) DownloadMirrorFile(Itm->Uri); } - if(Mirror.empty()) - SelectMirror(); - - for (FetchItem *I = Queue; I != 0; I = I->Next) - { - if(I->Uri.find("mirror://") != string::npos) - I->Uri.replace(0,BaseUri.size(), Mirror); + if(AllMirrors.empty()) { + if(!InitMirrors()) { + // no valid mirror selected, something went wrong downloading + // from the master mirror site most likely and there is + // no old mirror file availalbe + return false; + } } + + if(Itm->Uri.find("mirror://") != string::npos) + Itm->Uri.replace(0,BaseUri.size(), Mirror); + + if(Debug) + clog << "Fetch: " << Itm->Uri << endl << endl; // now run the real fetcher return HttpMethod::Fetch(Itm); @@ -284,22 +336,35 @@ bool MirrorMethod::Fetch(FetchItem *Itm) void MirrorMethod::Fail(string Err,bool Transient) { - if(Queue->Uri.find("http://") != string::npos) - Queue->Uri.replace(0,Mirror.size(), BaseUri); + // FIXME: TryNextMirror is not ideal for indexfile as we may + // run into auth issues + + if (Debug) + clog << "Failure to get " << Queue->Uri << endl; + + // try the next mirror on fail (if its not a expected failure, + // e.g. translations are ok to ignore) + if (!Queue->FailIgnore && TryNextMirror()) + return; + + // all mirrors failed, so bail out + string s; + strprintf(s, _("[Mirror: %s]"), Mirror.c_str()); + SetIP(s); + + CurrentQueueUriToMirror(); pkgAcqMethod::Fail(Err, Transient); } void MirrorMethod::URIStart(FetchResult &Res) { - if(Queue->Uri.find("http://") != string::npos) - Queue->Uri.replace(0,Mirror.size(), BaseUri); + CurrentQueueUriToMirror(); pkgAcqMethod::URIStart(Res); } void MirrorMethod::URIDone(FetchResult &Res,FetchResult *Alt) { - if(Queue->Uri.find("http://") != string::npos) - Queue->Uri.replace(0,Mirror.size(), BaseUri); + CurrentQueueUriToMirror(); pkgAcqMethod::URIDone(Res, Alt); }