]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire.cc,v 1.13 1998/11/11 23:45:08 jgg Exp $
4 /* ######################################################################
6 Acquire - File Acquiration
8 The core element for the schedual system is the concept of a named
9 queue. Each queue is unique and each queue has a name derived from the
10 URI. The degree of paralization can be controled by how the queue
11 name is derived from the URI.
13 ##################################################################### */
15 // Include Files /*{{{*/
17 #pragma implementation "apt-pkg/acquire.h"
19 #include <apt-pkg/acquire.h>
20 #include <apt-pkg/acquire-item.h>
21 #include <apt-pkg/acquire-worker.h>
22 #include <apt-pkg/configuration.h>
23 #include <apt-pkg/error.h>
29 // Acquire::pkgAcquire - Constructor /*{{{*/
30 // ---------------------------------------------------------------------
31 /* We grab some runtime state from the configuration space */
32 pkgAcquire::pkgAcquire(pkgAcquireStatus
*Log
) : Log(Log
)
40 string Mode
= _config
->Find("Acquire::Queue-Mode","host");
41 if (strcasecmp(Mode
.c_str(),"host") == 0)
42 QueueMode
= QueueHost
;
43 if (strcasecmp(Mode
.c_str(),"access") == 0)
44 QueueMode
= QueueAccess
;
46 Debug
= _config
->FindB("Debug::pkgAcquire",false);
49 // Acquire::~pkgAcquire - Destructor /*{{{*/
50 // ---------------------------------------------------------------------
51 /* Free our memory, clean up the queues (destroy the workers) */
52 pkgAcquire::~pkgAcquire()
54 while (Items
.size() != 0)
59 MethodConfig
*Jnk
= Configs
;
60 Configs
= Configs
->Next
;
67 Queues
= Queues
->Next
;
72 // Acquire::Add - Add a new item /*{{{*/
73 // ---------------------------------------------------------------------
74 /* This puts an item on the acquire list. This list is mainly for tracking
76 void pkgAcquire::Add(Item
*Itm
)
81 // Acquire::Remove - Remove a item /*{{{*/
82 // ---------------------------------------------------------------------
83 /* Remove an item from the acquire list. This is usually not used.. */
84 void pkgAcquire::Remove(Item
*Itm
)
86 for (vector
<Item
*>::iterator I
= Items
.begin(); I
< Items
.end(); I
++)
93 // Acquire::Add - Add a worker /*{{{*/
94 // ---------------------------------------------------------------------
95 /* A list of workers is kept so that the select loop can direct their FD
97 void pkgAcquire::Add(Worker
*Work
)
99 Work
->NextAcquire
= Workers
;
103 // Acquire::Remove - Remove a worker /*{{{*/
104 // ---------------------------------------------------------------------
105 /* A worker has died. This can not be done while the select loop is running
106 as it would require that RunFds could handling a changing list state and
108 void pkgAcquire::Remove(Worker
*Work
)
113 Worker
**I
= &Workers
;
117 *I
= (*I
)->NextAcquire
;
119 I
= &(*I
)->NextAcquire
;
123 // Acquire::Enqueue - Queue an URI for fetching /*{{{*/
124 // ---------------------------------------------------------------------
125 /* This is the entry point for an item. An item calls this function when
126 it is construction which creates a queue (based on the current queue
127 mode) and puts the item in that queue. If the system is running then
128 the queue might be started. */
129 void pkgAcquire::Enqueue(ItemDesc
&Item
)
131 // Determine which queue to put the item in
132 string Name
= QueueName(Item
.URI
);
133 if (Name
.empty() == true)
136 // Find the queue structure
138 for (; I
!= 0 && I
->Name
!= Name
; I
= I
->Next
);
141 I
= new Queue(Name
,this);
149 Item
.Owner
->Status
= Item::StatIdle
;
151 // Queue it into the named queue
158 clog
<< "Fetching " << Item
.URI
<< endl
;
159 clog
<< " to " << Item
.Owner
->DestFile
<< endl
;
160 clog
<< " Queue is: " << QueueName(Item
.URI
) << endl
;
164 // Acquire::Dequeue - Remove an item from all queues /*{{{*/
165 // ---------------------------------------------------------------------
166 /* This is called when an item is finished being fetched. It removes it
167 from all the queues */
168 void pkgAcquire::Dequeue(Item
*Itm
)
172 for (; I
!= 0; I
= I
->Next
)
173 Res
|= I
->Dequeue(Itm
);
176 clog
<< "Dequeuing " << Itm
->DestFile
<< endl
;
181 // Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
182 // ---------------------------------------------------------------------
183 /* The string returned depends on the configuration settings and the
184 method parameters. Given something like http://foo.org/bar it can
185 return http://foo.org or http */
186 string
pkgAcquire::QueueName(string Uri
)
190 const MethodConfig
*Config
= GetConfig(U
.Access
);
194 /* Single-Instance methods get exactly one queue per URI. This is
195 also used for the Access queue method */
196 if (Config
->SingleInstance
== true || QueueMode
== QueueAccess
)
199 return U
.Access
+ ':' + U
.Host
;
202 // Acquire::GetConfig - Fetch the configuration information /*{{{*/
203 // ---------------------------------------------------------------------
204 /* This locates the configuration structure for an access method. If
205 a config structure cannot be found a Worker will be created to
207 pkgAcquire::MethodConfig
*pkgAcquire::GetConfig(string Access
)
209 // Search for an existing config
211 for (Conf
= Configs
; Conf
!= 0; Conf
= Conf
->Next
)
212 if (Conf
->Access
== Access
)
215 // Create the new config class
216 Conf
= new MethodConfig
;
217 Conf
->Access
= Access
;
218 Conf
->Next
= Configs
;
221 // Create the worker to fetch the configuration
223 if (Work
.Start() == false)
229 // Acquire::SetFds - Deal with readable FDs /*{{{*/
230 // ---------------------------------------------------------------------
231 /* Collect FDs that have activity monitors into the fd sets */
232 void pkgAcquire::SetFds(int &Fd
,fd_set
*RSet
,fd_set
*WSet
)
234 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
236 if (I
->InReady
== true && I
->InFd
>= 0)
240 FD_SET(I
->InFd
,RSet
);
242 if (I
->OutReady
== true && I
->OutFd
>= 0)
246 FD_SET(I
->OutFd
,WSet
);
251 // Acquire::RunFds - Deal with active FDs /*{{{*/
252 // ---------------------------------------------------------------------
253 /* Dispatch active FDs over to the proper workers. It is very important
254 that a worker never be erased while this is running! The queue class
255 should never erase a worker except during shutdown processing. */
256 void pkgAcquire::RunFds(fd_set
*RSet
,fd_set
*WSet
)
258 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
260 if (I
->InFd
>= 0 && FD_ISSET(I
->InFd
,RSet
) != 0)
262 if (I
->OutFd
>= 0 && FD_ISSET(I
->OutFd
,WSet
) != 0)
267 // Acquire::Run - Run the fetch sequence /*{{{*/
268 // ---------------------------------------------------------------------
269 /* This runs the queues. It manages a select loop for all of the
270 Worker tasks. The workers interact with the queues and items to
271 manage the actual fetch. */
272 bool pkgAcquire::Run()
276 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
282 // Run till all things have been acquired
293 SetFds(Highest
,&RFds
,&WFds
);
295 int Res
= select(Highest
+1,&RFds
,&WFds
,0,&tv
);
298 _error
->Errno("select","Select has failed");
303 if (_error
->PendingError() == true)
306 // Timeout, notify the log class
307 if (Res
== 0 || (Log
!= 0 && Log
->Update
== true))
310 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
320 // Shut down the acquire bits
322 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
325 return !_error
->PendingError();
328 // Acquire::Bump - Called when an item is dequeued /*{{{*/
329 // ---------------------------------------------------------------------
330 /* This routine bumps idle queues in hopes that they will be able to fetch
332 void pkgAcquire::Bump()
334 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
338 // Acquire::WorkerStep - Step to the next worker /*{{{*/
339 // ---------------------------------------------------------------------
340 /* Not inlined to advoid including acquire-worker.h */
341 pkgAcquire::Worker
*pkgAcquire::WorkerStep(Worker
*I
)
343 return I
->NextAcquire
;
347 // Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
348 // ---------------------------------------------------------------------
350 pkgAcquire::MethodConfig::MethodConfig()
352 SingleInstance
= false;
360 // Queue::Queue - Constructor /*{{{*/
361 // ---------------------------------------------------------------------
363 pkgAcquire::Queue::Queue(string Name
,pkgAcquire
*Owner
) : Name(Name
),
371 // Queue::~Queue - Destructor /*{{{*/
372 // ---------------------------------------------------------------------
374 pkgAcquire::Queue::~Queue()
386 // Queue::Enqueue - Queue an item to the queue /*{{{*/
387 // ---------------------------------------------------------------------
389 void pkgAcquire::Queue::Enqueue(ItemDesc
&Item
)
392 QItem
*I
= new QItem
;
397 Item
.Owner
->QueueCounter
++;
398 if (Items
->Next
== 0)
402 // Queue::Dequeue - Remove an item from the queue /*{{{*/
403 // ---------------------------------------------------------------------
404 /* We return true if we hit something*/
405 bool pkgAcquire::Queue::Dequeue(Item
*Owner
)
412 if ((*I
)->Owner
== Owner
)
416 Owner
->QueueCounter
--;
427 // Queue::Startup - Start the worker processes /*{{{*/
428 // ---------------------------------------------------------------------
430 bool pkgAcquire::Queue::Startup()
435 pkgAcquire::MethodConfig
*Cnf
= Owner
->GetConfig(U
.Access
);
439 Workers
= new Worker(this,Cnf
,Owner
->Log
);
441 if (Workers
->Start() == false)
447 // Queue::Shutdown - Shutdown the worker processes /*{{{*/
448 // ---------------------------------------------------------------------
450 bool pkgAcquire::Queue::Shutdown()
452 // Delete all of the workers
455 pkgAcquire::Worker
*Jnk
= Workers
;
456 Workers
= Workers
->NextQueue
;
464 // Queue::Finditem - Find a URI in the item list /*{{{*/
465 // ---------------------------------------------------------------------
467 pkgAcquire::Queue::QItem
*pkgAcquire::Queue::FindItem(string URI
,pkgAcquire::Worker
*Owner
)
469 for (QItem
*I
= Items
; I
!= 0; I
= I
->Next
)
470 if (I
->URI
== URI
&& I
->Worker
== Owner
)
475 // Queue::ItemDone - Item has been completed /*{{{*/
476 // ---------------------------------------------------------------------
477 /* The worker signals this which causes the item to be removed from the
478 queue. If this is the last queue instance then it is removed from the
480 bool pkgAcquire::Queue::ItemDone(QItem
*Itm
)
482 if (Itm
->Owner
->QueueCounter
<= 1)
483 Owner
->Dequeue(Itm
->Owner
);
493 // Queue::Cycle - Queue new items into the method /*{{{*/
494 // ---------------------------------------------------------------------
495 /* This locates a new idle item and sends it to the worker */
496 bool pkgAcquire::Queue::Cycle()
498 if (Items
== 0 || Workers
== 0)
501 // Look for a queable item
503 for (; I
!= 0; I
= I
->Next
)
504 if (I
->Owner
->Status
== pkgAcquire::Item::StatIdle
)
507 // Nothing to do, queue is idle.
512 I
->Owner
->Status
= pkgAcquire::Item::StatFetching
;
513 return Workers
->QueueItem(I
);
516 // Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
517 // ---------------------------------------------------------------------
519 void pkgAcquire::Queue::Bump()
524 // AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/
525 // ---------------------------------------------------------------------
527 pkgAcquireStatus::pkgAcquireStatus()
532 // AcquireStatus::Pulse - Called periodically /*{{{*/
533 // ---------------------------------------------------------------------
534 /* This computes some internal state variables for the derived classes to
535 use. It generates the current downloaded bytes and total bytes to download
536 as well as the current CPS estimate. */
537 void pkgAcquireStatus::Pulse(pkgAcquire
*Owner
)
542 // Compute the total number of bytes to fetch
543 unsigned int Unknown
= 0;
544 unsigned int Count
= 0;
545 for (pkgAcquire::Item
**I
= Owner
->ItemsBegin(); I
!= Owner
->ItemsEnd();
548 TotalBytes
+= (*I
)->FileSize
;
549 if ((*I
)->Complete
== true)
550 CurrentBytes
+= (*I
)->FileSize
;
551 if ((*I
)->FileSize
== 0 && (*I
)->Complete
== false)
555 // Compute the current completion
556 for (pkgAcquire::Worker
*I
= Owner
->WorkersBegin(); I
!= 0;
557 I
= Owner
->WorkerStep(I
))
558 if (I
->CurrentItem
!= 0 && I
->CurrentItem
->Owner
->Complete
== false)
559 CurrentBytes
+= I
->CurrentSize
;
561 // Normalize the figures and account for unknown size downloads
564 if (Unknown
== Count
)
565 TotalBytes
= Unknown
;
567 TotalBytes
+= TotalBytes
/(Count
- Unknown
)*Unknown
;
570 struct timeval NewTime
;
571 gettimeofday(&NewTime
,0);
572 if (NewTime
.tv_sec
- Time
.tv_sec
== 6 && NewTime
.tv_usec
> Time
.tv_usec
||
573 NewTime
.tv_sec
- Time
.tv_sec
> 6)
575 // Compute the delta time with full accuracy
576 long usdiff
= NewTime
.tv_usec
- Time
.tv_usec
;
577 long sdiff
= NewTime
.tv_sec
- Time
.tv_sec
;
586 // Compute the CPS value
587 CurrentCPS
= (CurrentBytes
- LastBytes
)/(sdiff
+ usdiff
/1000000.0);
588 LastBytes
= CurrentBytes
;
589 ElapsedTime
= NewTime
.tv_sec
- StartTime
.tv_sec
;
594 // AcquireStatus::Start - Called when the download is started /*{{{*/
595 // ---------------------------------------------------------------------
596 /* We just reset the counters */
597 void pkgAcquireStatus::Start()
599 gettimeofday(&Time
,0);
600 gettimeofday(&StartTime
,0);
609 // pkgAcquireStatus::Stop - Finished downloading /*{{{*/
610 // ---------------------------------------------------------------------
611 /* This accurately computes the elapsed time and the total overall CPS. */
612 void pkgAcquireStatus::Stop()
614 // Compute the CPS and elapsed time
615 struct timeval NewTime
;
616 gettimeofday(&NewTime
,0);
618 // Compute the delta time with full accuracy
619 long usdiff
= NewTime
.tv_usec
- StartTime
.tv_usec
;
620 long sdiff
= NewTime
.tv_sec
- StartTime
.tv_sec
;
629 // Compute the CPS value
630 CurrentCPS
= FetchedBytes
/(sdiff
+ usdiff
/1000000.0);
631 LastBytes
= CurrentBytes
;
635 // AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/
636 // ---------------------------------------------------------------------
637 /* This is used to get accurate final transfer rate reporting. */
638 void pkgAcquireStatus::Fetched(unsigned long Size
,unsigned long Resume
)
640 FetchedBytes
+= Size
- Resume
;