X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/7a7fa5f07e59bd17415cb0321d1f98527c2cfea4..c98b1307f0e9c1712b8e36b825724966d9d40eec:/apt-pkg/acquire.cc?ds=sidebyside diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc index 972a466c5..842f2e31a 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.14 1998/11/12 04:10:54 jgg Exp $ +// $Id: acquire.cc,v 1.38 1999/07/30 05:36:52 jgg Exp $ /* ###################################################################### Acquire - File Acquiration @@ -21,10 +21,11 @@ #include #include #include -#include +#include #include #include +#include /*}}}*/ // Acquire::pkgAcquire - Constructor /*{{{*/ @@ -52,15 +53,23 @@ pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log) /* Free our memory, clean up the queues (destroy the workers) */ pkgAcquire::~pkgAcquire() { - while (Items.size() != 0) - delete Items[0]; - while (Configs != 0) { MethodConfig *Jnk = Configs; Configs = Configs->Next; delete Jnk; } + + Shutdown(); +} + /*}}}*/ +// pkgAcquire::Shutdown - Clean out the acquire object /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void pkgAcquire::Shutdown() +{ + while (Items.size() != 0) + delete Items[0]; while (Queues != 0) { @@ -124,13 +133,14 @@ void pkgAcquire::Remove(Worker *Work) // Acquire::Enqueue - Queue an URI for fetching /*{{{*/ // --------------------------------------------------------------------- /* This is the entry point for an item. An item calls this function when - it is construction which creates a queue (based on the current queue + it is constructed 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(ItemDesc &Item) { // Determine which queue to put the item in - string Name = QueueName(Item.URI); + const MethodConfig *Config; + string Name = QueueName(Item.URI,Config); if (Name.empty() == true) return; @@ -147,6 +157,9 @@ void pkgAcquire::Enqueue(ItemDesc &Item) I->Startup(); } + // 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 @@ -158,7 +171,7 @@ void pkgAcquire::Enqueue(ItemDesc &Item) { clog << "Fetching " << Item.URI << endl; clog << " to " << Item.Owner->DestFile << endl; - clog << " Queue is: " << QueueName(Item.URI) << endl; + clog << " Queue is: " << Name << endl; } } /*}}}*/ @@ -184,11 +197,11 @@ 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(); @@ -270,7 +283,7 @@ void pkgAcquire::RunFds(fd_set *RSet,fd_set *WSet) /* This runs the queues. It manages a select loop for all of the Worker tasks. The workers interact with the queues and items to manage the actual fetch. */ -bool pkgAcquire::Run() +pkgAcquire::RunResult pkgAcquire::Run() { Running = true; @@ -280,6 +293,8 @@ bool pkgAcquire::Run() if (Log != 0) Log->Start(); + bool WasCancelled = false; + // Run till all things have been acquired struct timeval tv; tv.tv_sec = 0; @@ -293,7 +308,13 @@ bool pkgAcquire::Run() FD_ZERO(&WFds); SetFds(Highest,&RFds,&WFds); - int Res = select(Highest+1,&RFds,&WFds,0,&tv); + int Res; + do + { + Res = select(Highest+1,&RFds,&WFds,0,&tv); + } + while (Res < 0 && errno == EINTR); + if (Res < 0) { _error->Errno("select","Select has failed"); @@ -310,8 +331,11 @@ bool pkgAcquire::Run() 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->Pulse(this) == false) + { + WasCancelled = true; + break; + } } } @@ -323,7 +347,15 @@ bool pkgAcquire::Run() for (Queue *I = Queues; I != 0; I = I->Next) I->Shutdown(); - return !_error->PendingError(); + // Shut down the items + for (Item **I = Items.begin(); I != Items.end(); I++) + (*I)->Finished(); + + if (_error->PendingError()) + return Failed; + if (WasCancelled) + return Cancelled; + return Continue; } /*}}}*/ // Acquire::Bump - Called when an item is dequeued /*{{{*/ @@ -344,7 +376,7 @@ pkgAcquire::Worker *pkgAcquire::WorkerStep(Worker *I) return I->NextAcquire; }; /*}}}*/ -// pkgAcquire::Clean - Cleans a directory /*{{{*/ +// 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. */ @@ -386,15 +418,67 @@ bool pkgAcquire::Clean(string Dir) 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::PartialPresent - Number of partial bytes we already have /*{{{*/ +// --------------------------------------------------------------------- +/* This is the number of bytes that is not local */ +unsigned long pkgAcquire::PartialPresent() +{ + unsigned long Total = 0; + for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++) + if ((*I)->Local == false) + Total += (*I)->PartialSize; + return Total; +} + /*}}}*/ +// pkgAcquire::UriBegin - Start iterator for the uri list /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgAcquire::UriIterator pkgAcquire::UriBegin() +{ + return UriIterator(Queues); +} + /*}}}*/ +// pkgAcquire::UriEnd - End iterator for the uri list /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgAcquire::UriIterator pkgAcquire::UriEnd() +{ + return UriIterator(0); +} + /*}}}*/ + // Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ pkgAcquire::MethodConfig::MethodConfig() { SingleInstance = false; - PreScan = false; Pipeline = false; SendConfig = false; + LocalOnly = false; Next = 0; } /*}}}*/ @@ -408,6 +492,8 @@ pkgAcquire::Queue::Queue(string Name,pkgAcquire *Owner) : Name(Name), Items = 0; Next = 0; Workers = 0; + MaxPipeDepth = 1; + PipeDepth = 0; } /*}}}*/ // Queue::~Queue - Destructor /*{{{*/ @@ -430,11 +516,14 @@ pkgAcquire::Queue::~Queue() /* */ void pkgAcquire::Queue::Enqueue(ItemDesc &Item) { + QItem **I = &Items; + for (; *I != 0; I = &(*I)->Next); + // Create a new item - QItem *I = new QItem; - I->Next = Items; - Items = I; - *I = Item; + QItem *Itm = new QItem; + *Itm = Item; + Itm->Next = 0; + *I = Itm; Item.Owner->QueueCounter++; if (Items->Next == 0) @@ -443,9 +532,12 @@ void pkgAcquire::Queue::Enqueue(ItemDesc &Item) /*}}}*/ // Queue::Dequeue - Remove an item from the queue /*{{{*/ // --------------------------------------------------------------------- -/* We return true if we hit something*/ +/* We return true if we hit something */ bool pkgAcquire::Queue::Dequeue(Item *Owner) { + if (Owner->Status == pkgAcquire::Item::StatFetching) + return _error->Error("Tried to dequeue a fetching object"); + bool Res = false; QItem **I = &Items; @@ -483,6 +575,14 @@ bool pkgAcquire::Queue::Startup() if (Workers->Start() == false) return false; + /* When pipelining we commit 10 items. This needs to change when we + added other source retry to have cycle maintain a pipeline depth + on its own. */ + if (Cnf->Pipeline == true) + MaxPipeDepth = 10; + else + MaxPipeDepth = 1; + return Cycle(); } /*}}}*/ @@ -503,7 +603,7 @@ bool pkgAcquire::Queue::Shutdown() return true; } /*}}}*/ -// Queue::Finditem - Find a URI in the item list /*{{{*/ +// Queue::FindItem - Find a URI in the item list /*{{{*/ // --------------------------------------------------------------------- /* */ pkgAcquire::Queue::QItem *pkgAcquire::Queue::FindItem(string URI,pkgAcquire::Worker *Owner) @@ -521,6 +621,10 @@ pkgAcquire::Queue::QItem *pkgAcquire::Queue::FindItem(string URI,pkgAcquire::Wor main queue too.*/ bool pkgAcquire::Queue::ItemDone(QItem *Itm) { + PipeDepth--; + if (Itm->Owner->Status == pkgAcquire::Item::StatFetching) + Itm->Owner->Status = pkgAcquire::Item::StatDone; + if (Itm->Owner->QueueCounter <= 1) Owner->Dequeue(Itm->Owner); else @@ -534,32 +638,44 @@ bool pkgAcquire::Queue::ItemDone(QItem *Itm) /*}}}*/ // Queue::Cycle - Queue new items into the method /*{{{*/ // --------------------------------------------------------------------- -/* This locates a new idle item and sends it to the worker */ +/* This locates a new idle item and sends it to the worker. If pipelining + is enabled then it keeps the pipe full. */ bool pkgAcquire::Queue::Cycle() { if (Items == 0 || Workers == 0) return true; + if (PipeDepth < 0) + return _error->Error("Pipedepth failure"); + // Look for a queable item QItem *I = Items; - for (; I != 0; I = I->Next) - if (I->Owner->Status == pkgAcquire::Item::StatIdle) - break; - - // Nothing to do, queue is idle. - if (I == 0) - return true; + while (PipeDepth < (signed)MaxPipeDepth) + { + for (; I != 0; I = I->Next) + if (I->Owner->Status == pkgAcquire::Item::StatIdle) + break; + + // Nothing to do, queue is idle. + if (I == 0) + return true; + + I->Worker = Workers; + I->Owner->Status = pkgAcquire::Item::StatFetching; + PipeDepth++; + if (Workers->QueueItem(I) == false) + return false; + } - I->Worker = Workers; - I->Owner->Status = pkgAcquire::Item::StatFetching; - return Workers->QueueItem(I); + return true; } /*}}}*/ // Queue::Bump - Fetch any pending objects if we are idle /*{{{*/ // --------------------------------------------------------------------- -/* */ +/* This is called when an item in multiple queues is dequeued */ void pkgAcquire::Queue::Bump() { + Cycle(); } /*}}}*/ @@ -576,10 +692,12 @@ pkgAcquireStatus::pkgAcquireStatus() /* 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) +bool pkgAcquireStatus::Pulse(pkgAcquire *Owner) { TotalBytes = 0; CurrentBytes = 0; + TotalItems = 0; + CurrentItems = 0; // Compute the total number of bytes to fetch unsigned int Unknown = 0; @@ -587,6 +705,14 @@ void pkgAcquireStatus::Pulse(pkgAcquire *Owner) 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; @@ -595,18 +721,29 @@ void pkgAcquireStatus::Pulse(pkgAcquire *Owner) } // Compute the current completion + unsigned long ResumeSize = 0; for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0; I = Owner->WorkerStep(I)) if (I->CurrentItem != 0 && I->CurrentItem->Owner->Complete == false) + { CurrentBytes += I->CurrentSize; - + ResumeSize += I->ResumePoint; + + // Files with unknown size always have 100% completion + if (I->CurrentItem->Owner->FileSize == 0 && + I->CurrentItem->Owner->Complete == false) + TotalBytes += 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; + + // Wha?! Is not supposed to happen. + if (CurrentBytes > TotalBytes) + CurrentBytes = TotalBytes; // Compute the CPS struct timeval NewTime; @@ -614,23 +751,20 @@ void pkgAcquireStatus::Pulse(pkgAcquire *Owner) 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; + double Delta = NewTime.tv_sec - Time.tv_sec + + (NewTime.tv_usec - Time.tv_usec)/1000000.0; - // Borrow - if (usdiff < 0) - { - usdiff += 1000000; - sdiff--; - } - // Compute the CPS value - CurrentCPS = (CurrentBytes - LastBytes)/(sdiff + usdiff/1000000.0); - LastBytes = CurrentBytes; - ElapsedTime = NewTime.tv_sec - StartTime.tv_sec; + if (Delta < 0.01) + CurrentCPS = 0; + else + CurrentCPS = ((CurrentBytes - ResumeSize) - LastBytes)/Delta; + LastBytes = CurrentBytes - ResumeSize; + ElapsedTime = (unsigned long)Delta; Time = NewTime; } + + return true; } /*}}}*/ // AcquireStatus::Start - Called when the download is started /*{{{*/ @@ -646,9 +780,11 @@ void pkgAcquireStatus::Start() TotalBytes = 0; FetchedBytes = 0; ElapsedTime = 0; + TotalItems = 0; + CurrentItems = 0; } /*}}}*/ -// pkgAcquireStatus::Stop - Finished downloading /*{{{*/ +// AcquireStatus::Stop - Finished downloading /*{{{*/ // --------------------------------------------------------------------- /* This accurately computes the elapsed time and the total overall CPS. */ void pkgAcquireStatus::Stop() @@ -667,9 +803,12 @@ void pkgAcquireStatus::Stop() usdiff += 1000000; sdiff--; } - + // Compute the CPS value - CurrentCPS = FetchedBytes/(sdiff + usdiff/1000000.0); + if (sdiff == 0 && usdiff == 0) + CurrentCPS = 0; + else + CurrentCPS = FetchedBytes/(sdiff + usdiff/1000000.0); LastBytes = CurrentBytes; ElapsedTime = sdiff; }