X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/bfd22fc0ac2632c6196f5149dc3b3671d9ff15e0..f9fe12bbb59aa3ba53f04d94fd924b4424a9d233:/apt-pkg/acquire.cc?ds=sidebyside diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc index 16adf3ae2..f9691df9c 100644 --- a/apt-pkg/acquire.cc +++ b/apt-pkg/acquire.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: acquire.cc,v 1.8 1998/11/05 07:21:40 jgg Exp $ +// $Id: acquire.cc,v 1.18 1998/11/23 07:32:19 jgg Exp $ /* ###################################################################### Acquire - File Acquiration @@ -22,12 +22,15 @@ #include #include #include + +#include +#include /*}}}*/ // Acquire::pkgAcquire - Constructor /*{{{*/ // --------------------------------------------------------------------- /* We grab some runtime state from the configuration space */ -pkgAcquire::pkgAcquire() +pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log) { Queues = 0; Configs = 0; @@ -85,7 +88,7 @@ void pkgAcquire::Remove(Item *Itm) { if (*I == Itm) Items.erase(I); - } + } } /*}}}*/ // Acquire::Add - Add a worker /*{{{*/ @@ -124,10 +127,11 @@ void pkgAcquire::Remove(Worker *Work) it is construction which creates a queue (based on the current queue mode) and puts the item in that queue. If the system is running then the queue might be started. */ -void pkgAcquire::Enqueue(Item *Itm,string URI,string Description) +void pkgAcquire::Enqueue(ItemDesc &Item) { // Determine which queue to put the item in - string Name = QueueName(URI); + const MethodConfig *Config; + string Name = QueueName(Item.URI,Config); if (Name.empty() == true) return; @@ -144,18 +148,21 @@ void pkgAcquire::Enqueue(Item *Itm,string URI,string Description) I->Startup(); } - Itm->Status = Item::StatIdle; + // See if this is a local only URI + if (Config->LocalOnly == true && Item.Owner->Complete == false) + Item.Owner->Local = true; + Item.Owner->Status = Item::StatIdle; // Queue it into the named queue - I->Enqueue(Itm,URI,Description); + I->Enqueue(Item); ToFetch++; // Some trace stuff if (Debug == true) { - clog << "Fetching " << URI << endl; - clog << " to " << Itm->DestFile << endl; - clog << " Queue is: " << QueueName(URI) << endl; + clog << "Fetching " << Item.URI << endl; + clog << " to " << Item.Owner->DestFile << endl; + clog << " Queue is: " << Name << endl; } } /*}}}*/ @@ -181,18 +188,18 @@ void pkgAcquire::Dequeue(Item *Itm) /* The string returned depends on the configuration settings and the method parameters. Given something like http://foo.org/bar it can return http://foo.org or http */ -string pkgAcquire::QueueName(string Uri) +string pkgAcquire::QueueName(string Uri,MethodConfig const *&Config) { URI U(Uri); - const MethodConfig *Config = GetConfig(U.Access); + Config = GetConfig(U.Access); if (Config == 0) return string(); /* Single-Instance methods get exactly one queue per URI. This is also used for the Access queue method */ if (Config->SingleInstance == true || QueueMode == QueueAccess) - return U.Access; + return U.Access; return U.Access + ':' + U.Host; } @@ -274,7 +281,13 @@ bool pkgAcquire::Run() for (Queue *I = Queues; I != 0; I = I->Next) I->Startup(); + if (Log != 0) + Log->Start(); + // Run till all things have been acquired + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 500000; while (ToFetch > 0) { fd_set RFds; @@ -284,23 +297,37 @@ bool pkgAcquire::Run() FD_ZERO(&WFds); SetFds(Highest,&RFds,&WFds); - if (select(Highest+1,&RFds,&WFds,0,0) <= 0) + int Res = select(Highest+1,&RFds,&WFds,0,&tv); + if (Res < 0) { - Running = false; - return _error->Errno("select","Select has failed"); + _error->Errno("select","Select has failed"); + break; } RunFds(&RFds,&WFds); if (_error->PendingError() == true) break; + + // Timeout, notify the log class + if (Res == 0 || (Log != 0 && Log->Update == true)) + { + tv.tv_usec = 500000; + for (Worker *I = Workers; I != 0; I = I->NextAcquire) + I->Pulse(); + if (Log != 0) + Log->Pulse(this); + } } + if (Log != 0) + Log->Stop(); + // Shut down the acquire bits Running = false; for (Queue *I = Queues; I != 0; I = I->Next) I->Shutdown(); - return _error->PendingError(); + return !_error->PendingError(); } /*}}}*/ // Acquire::Bump - Called when an item is dequeued /*{{{*/ @@ -313,6 +340,79 @@ void pkgAcquire::Bump() I->Bump(); } /*}}}*/ +// Acquire::WorkerStep - Step to the next worker /*{{{*/ +// --------------------------------------------------------------------- +/* Not inlined to advoid including acquire-worker.h */ +pkgAcquire::Worker *pkgAcquire::WorkerStep(Worker *I) +{ + return I->NextAcquire; +}; + /*}}}*/ +// Acquire::Clean - Cleans a directory /*{{{*/ +// --------------------------------------------------------------------- +/* This is a bit simplistic, it looks at every file in the dir and sees + if it is part of the download set. */ +bool pkgAcquire::Clean(string Dir) +{ + DIR *D = opendir(Dir.c_str()); + if (D == 0) + return _error->Errno("opendir","Unable to read %s",Dir.c_str()); + + string StartDir = SafeGetCWD(); + if (chdir(Dir.c_str()) != 0) + { + closedir(D); + return _error->Errno("chdir","Unable to change to ",Dir.c_str()); + } + + for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D)) + { + // Skip some files.. + if (strcmp(Dir->d_name,"lock") == 0 || + strcmp(Dir->d_name,"partial") == 0 || + strcmp(Dir->d_name,".") == 0 || + strcmp(Dir->d_name,"..") == 0) + continue; + + // Look in the get list + vector::iterator I = Items.begin(); + for (; I != Items.end(); I++) + if (flNotDir((*I)->DestFile) == Dir->d_name) + break; + + // Nothing found, nuke it + if (I == Items.end()) + unlink(Dir->d_name); + }; + + chdir(StartDir.c_str()); + closedir(D); + return true; +} + /*}}}*/ +// Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/ +// --------------------------------------------------------------------- +/* This is the total number of bytes needed */ +unsigned long pkgAcquire::TotalNeeded() +{ + unsigned long Total = 0; + for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++) + Total += (*I)->FileSize; + return Total; +} + /*}}}*/ +// Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/ +// --------------------------------------------------------------------- +/* This is the number of bytes that is not local */ +unsigned long pkgAcquire::FetchNeeded() +{ + unsigned long Total = 0; + for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++) + if ((*I)->Local == false) + Total += (*I)->FileSize; + return Total; +} + /*}}}*/ // Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/ // --------------------------------------------------------------------- @@ -323,6 +423,7 @@ pkgAcquire::MethodConfig::MethodConfig() PreScan = false; Pipeline = false; SendConfig = false; + LocalOnly = false; Next = 0; } /*}}}*/ @@ -356,19 +457,18 @@ pkgAcquire::Queue::~Queue() // Queue::Enqueue - Queue an item to the queue /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgAcquire::Queue::Enqueue(Item *Owner,string URI,string Description) +void pkgAcquire::Queue::Enqueue(ItemDesc &Item) { - // Create a new item - QItem *I = new QItem; - I->Next = Items; - Items = I; + QItem **I = &Items; + for (; *I != 0; I = &(*I)->Next); - // Fill it in - Items->Owner = Owner; - Items->URI = URI; - Items->Description = Description; - Owner->QueueCounter++; + // Create a new item + QItem *Itm = new QItem; + *Itm = Item; + Itm->Next = 0; + *I = Itm; + Item.Owner->QueueCounter++; if (Items->Next == 0) Cycle(); } @@ -410,7 +510,7 @@ bool pkgAcquire::Queue::Startup() if (Cnf == 0) return false; - Workers = new Worker(this,Cnf); + Workers = new Worker(this,Cnf,Owner->Log); Owner->Add(Workers); if (Workers->Start() == false) return false; @@ -472,8 +572,6 @@ bool pkgAcquire::Queue::Cycle() if (Items == 0 || Workers == 0) return true; - cout << "Cylce for " << Name << endl; - // Look for a queable item QItem *I = Items; for (; I != 0; I = I->Next) @@ -486,7 +584,6 @@ bool pkgAcquire::Queue::Cycle() I->Worker = Workers; I->Owner->Status = pkgAcquire::Item::StatFetching; - cout << "Item has been queued!" << endl; return Workers->QueueItem(I); } /*}}}*/ @@ -497,3 +594,141 @@ void pkgAcquire::Queue::Bump() { } /*}}}*/ + +// AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgAcquireStatus::pkgAcquireStatus() +{ + Start(); +} + /*}}}*/ +// AcquireStatus::Pulse - Called periodically /*{{{*/ +// --------------------------------------------------------------------- +/* This computes some internal state variables for the derived classes to + use. It generates the current downloaded bytes and total bytes to download + as well as the current CPS estimate. */ +void pkgAcquireStatus::Pulse(pkgAcquire *Owner) +{ + TotalBytes = 0; + CurrentBytes = 0; + TotalItems = 0; + CurrentItems = 0; + + // Compute the total number of bytes to fetch + unsigned int Unknown = 0; + unsigned int Count = 0; + for (pkgAcquire::Item **I = Owner->ItemsBegin(); I != Owner->ItemsEnd(); + I++, Count++) + { + TotalItems++; + if ((*I)->Status == pkgAcquire::Item::StatDone) + CurrentItems++; + + // Totally ignore local items + if ((*I)->Local == true) + continue; + + TotalBytes += (*I)->FileSize; + if ((*I)->Complete == true) + CurrentBytes += (*I)->FileSize; + if ((*I)->FileSize == 0 && (*I)->Complete == false) + Unknown++; + } + + // Compute the current completion + for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0; + I = Owner->WorkerStep(I)) + if (I->CurrentItem != 0 && I->CurrentItem->Owner->Complete == false) + CurrentBytes += I->CurrentSize; + + // Normalize the figures and account for unknown size downloads + if (TotalBytes <= 0) + TotalBytes = 1; + if (Unknown == Count) + TotalBytes = Unknown; + else + TotalBytes += TotalBytes/(Count - Unknown)*Unknown; + + // Compute the CPS + struct timeval NewTime; + gettimeofday(&NewTime,0); + if (NewTime.tv_sec - Time.tv_sec == 6 && NewTime.tv_usec > Time.tv_usec || + NewTime.tv_sec - Time.tv_sec > 6) + { + // Compute the delta time with full accuracy + long usdiff = NewTime.tv_usec - Time.tv_usec; + long sdiff = NewTime.tv_sec - Time.tv_sec; + + // Borrow + if (usdiff < 0) + { + usdiff += 1000000; + sdiff--; + } + + // Compute the CPS value + if (sdiff == 0 && usdiff == 0) + CurrentCPS = 0; + else + CurrentCPS = (CurrentBytes - LastBytes)/(sdiff + usdiff/1000000.0); + LastBytes = CurrentBytes; + ElapsedTime = NewTime.tv_sec - StartTime.tv_sec; + Time = NewTime; + } +} + /*}}}*/ +// AcquireStatus::Start - Called when the download is started /*{{{*/ +// --------------------------------------------------------------------- +/* We just reset the counters */ +void pkgAcquireStatus::Start() +{ + gettimeofday(&Time,0); + gettimeofday(&StartTime,0); + LastBytes = 0; + CurrentCPS = 0; + CurrentBytes = 0; + TotalBytes = 0; + FetchedBytes = 0; + ElapsedTime = 0; + TotalItems = 0; + CurrentItems = 0; +} + /*}}}*/ +// AcquireStatus::Stop - Finished downloading /*{{{*/ +// --------------------------------------------------------------------- +/* This accurately computes the elapsed time and the total overall CPS. */ +void pkgAcquireStatus::Stop() +{ + // Compute the CPS and elapsed time + struct timeval NewTime; + gettimeofday(&NewTime,0); + + // Compute the delta time with full accuracy + long usdiff = NewTime.tv_usec - StartTime.tv_usec; + long sdiff = NewTime.tv_sec - StartTime.tv_sec; + + // Borrow + if (usdiff < 0) + { + usdiff += 1000000; + sdiff--; + } + + // Compute the CPS value + if (sdiff == 0 && usdiff == 0) + CurrentCPS = 0; + else + CurrentCPS = FetchedBytes/(sdiff + usdiff/1000000.0); + LastBytes = CurrentBytes; + ElapsedTime = sdiff; +} + /*}}}*/ +// AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/ +// --------------------------------------------------------------------- +/* This is used to get accurate final transfer rate reporting. */ +void pkgAcquireStatus::Fetched(unsigned long Size,unsigned long Resume) +{ + FetchedBytes += Size - Resume; +} + /*}}}*/