diff options
Diffstat (limited to 'methods/mirror.cc')
-rw-r--r-- | methods/mirror.cc | 76 |
1 files changed, 70 insertions, 6 deletions
diff --git a/methods/mirror.cc b/methods/mirror.cc index e8873d97b..2cf5c9ce1 100644 --- a/methods/mirror.cc +++ b/methods/mirror.cc @@ -16,11 +16,15 @@ #include <apt-pkg/hashes.h> #include <apt-pkg/sourcelist.h> + +#include <algorithm> #include <fstream> #include <iostream> + #include <stdarg.h> #include <sys/stat.h> #include <sys/types.h> +#include <sys/utsname.h> #include <dirent.h> using namespace std; @@ -125,23 +129,71 @@ bool MirrorMethod::Clean(string Dir) bool MirrorMethod::DownloadMirrorFile(string mirror_uri_str) { - if(Debug) - clog << "MirrorMethod::DownloadMirrorFile(): " << 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) + if(res) { DownloadedMirrorFile = true; + chmod(MirrorFile.c_str(), 0644); + } Fetcher.Shutdown(); + + if(Debug) + clog << "MirrorMethod::DownloadMirrorFile() success: " << res << endl; + return res; } +// Randomizes the lines in the mirror file, this is used so that +// we spread the load on the mirrors evenly +bool MirrorMethod::RandomizeMirrorFile(string mirror_file) +{ + vector<string> content; + string line; + + if (!FileExists(mirror_file)) + return false; + + // read + ifstream in(mirror_file.c_str()); + while ( !in.eof() ) { + getline(in, line); + content.push_back(line); + } + + // we want the file to be random for each different machine, but also + // "stable" on the same machine. this is to avoid running into out-of-sync + // issues (i.e. Release/Release.gpg different on each mirror) + struct utsname buf; + int seed=1, i; + if(uname(&buf) == 0) { + for(i=0,seed=1; buf.nodename[i] != 0; i++) { + seed = seed * 31 + buf.nodename[i]; + } + } + srand( seed ); + random_shuffle(content.begin(), content.end()); + + // write + ofstream out(mirror_file.c_str()); + while ( !content.empty()) { + line = content.back(); + content.pop_back(); + out << line << "\n"; + } + + return true; +} + /* 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) @@ -176,11 +228,15 @@ bool MirrorMethod::TryNextMirror() continue; vector<string>::const_iterator nextmirror = mirror + 1; - if (nextmirror != AllMirrors.end()) + 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; } @@ -200,6 +256,13 @@ bool MirrorMethod::InitMirrors() return _error->Error(_("No mirror file '%s' found "), MirrorFile.c_str()); } + if (access(MirrorFile.c_str(), R_OK) != 0) + { + // FIXME: fallback to a default mirror here instead + // and provide a config option to define that default + return _error->Error(_("Can not read mirror file '%s'"), MirrorFile.c_str()); + } + // FIXME: make the mirror selection more clever, do not // just use the first one! // BUT: we can not make this random, the mirror has to be @@ -303,7 +366,8 @@ bool MirrorMethod::Fetch(FetchItem *Itm) if(Itm->IndexFile && !DownloadedMirrorFile) { Clean(_config->FindDir("Dir::State::mirrors")); - DownloadMirrorFile(Itm->Uri); + if (DownloadMirrorFile(Itm->Uri)) + RandomizeMirrorFile(MirrorFile); } if(AllMirrors.empty()) { |