// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: acquire.cc,v 1.7 1998/11/01 05:27:34 jgg Exp $
+// $Id: acquire.cc,v 1.11 1998/11/11 06:54:16 jgg Exp $
/* ######################################################################
Acquire - File Acquiration
#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>
#include <strutl.h>
+
+#include <sys/time.h>
/*}}}*/
// Acquire::pkgAcquire - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* We grab some runtime state from the configuration space */
-pkgAcquire::pkgAcquire()
+pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log)
{
Queues = 0;
Configs = 0;
{
if (*I == Itm)
Items.erase(I);
- }
+ }
}
/*}}}*/
// Acquire::Add - Add a worker /*{{{*/
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);
+ string Name = QueueName(Item.URI);
if (Name.empty() == true)
return;
if (Running == true)
I->Startup();
}
+
+ 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: " << QueueName(Item.URI) << endl;
}
}
/*}}}*/
void pkgAcquire::Dequeue(Item *Itm)
{
Queue *I = Queues;
+ bool Res = false;
for (; I != 0; I = I->Next)
- I->Dequeue(Itm);
+ Res |= I->Dequeue(Itm);
if (Debug == true)
clog << "Dequeuing " << Itm->DestFile << endl;
- ToFetch--;
+ if (Res == true)
+ ToFetch--;
}
/*}}}*/
// Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
/* 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;
}
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;
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->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::MethodConfig::MethodConfig - Constructor /*{{{*/
// ---------------------------------------------------------------------
// 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;
+ QItem *I = new QItem;
I->Next = Items;
Items = I;
+ *I = Item;
- // Fill it in
- Items->Owner = Owner;
- Items->URI = URI;
- Items->Description = Description;
- Owner->QueueCounter++;
-
+ Item.Owner->QueueCounter++;
if (Items->Next == 0)
Cycle();
}
/*}}}*/
// Queue::Dequeue - Remove an item from the queue /*{{{*/
// ---------------------------------------------------------------------
-/* */
-void pkgAcquire::Queue::Dequeue(Item *Owner)
+/* We return true if we hit something*/
+bool pkgAcquire::Queue::Dequeue(Item *Owner)
{
+ bool Res = false;
+
QItem **I = &Items;
for (; *I != 0;)
{
*I = (*I)->Next;
Owner->QueueCounter--;
delete Jnk;
+ Res = true;
}
else
I = &(*I)->Next;
}
+
+ return Res;
}
/*}}}*/
// Queue::Startup - Start the worker processes /*{{{*/
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;
{
}
/*}}}*/
+
+// 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;
+
+ // 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++)
+ {
+ 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
+ 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;
+}
+ /*}}}*/
+// pkgAcquireStatus::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
+ 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;
+}
+ /*}}}*/