]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire.cc,v 1.50 2004/03/17 05:17:11 mdz Exp $
4 /* ######################################################################
6 Acquire - File Acquiration
8 The core element for the schedule 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 controlled by how the queue
11 name is derived from the URI.
13 ##################################################################### */
15 // Include Files /*{{{*/
18 #include <apt-pkg/acquire.h>
19 #include <apt-pkg/acquire-item.h>
20 #include <apt-pkg/acquire-worker.h>
21 #include <apt-pkg/configuration.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/fileutl.h>
38 #include <sys/select.h>
47 // Acquire::pkgAcquire - Constructor /*{{{*/
48 // ---------------------------------------------------------------------
49 /* We grab some runtime state from the configuration space */
50 pkgAcquire::pkgAcquire() : LockFD(-1), Queues(0), Workers(0), Configs(0), Log(NULL
), ToFetch(0),
51 Debug(_config
->FindB("Debug::pkgAcquire",false)),
54 string
const Mode
= _config
->Find("Acquire::Queue-Mode","host");
55 if (strcasecmp(Mode
.c_str(),"host") == 0)
56 QueueMode
= QueueHost
;
57 if (strcasecmp(Mode
.c_str(),"access") == 0)
58 QueueMode
= QueueAccess
;
60 pkgAcquire::pkgAcquire(pkgAcquireStatus
*Progress
) : LockFD(-1), Queues(0), Workers(0),
61 Configs(0), Log(Progress
), ToFetch(0),
62 Debug(_config
->FindB("Debug::pkgAcquire",false)),
65 string
const Mode
= _config
->Find("Acquire::Queue-Mode","host");
66 if (strcasecmp(Mode
.c_str(),"host") == 0)
67 QueueMode
= QueueHost
;
68 if (strcasecmp(Mode
.c_str(),"access") == 0)
69 QueueMode
= QueueAccess
;
73 // Acquire::Setup - Delayed Constructor /*{{{*/
74 // ---------------------------------------------------------------------
75 /* Do everything needed to be a complete Acquire object and report the
76 success (or failure) back so the user knows that something is wrong… */
77 bool pkgAcquire::Setup(pkgAcquireStatus
*Progress
, string
const &Lock
)
81 // check for existence and possibly create auxiliary directories
82 string
const listDir
= _config
->FindDir("Dir::State::lists");
83 string
const partialListDir
= listDir
+ "partial/";
84 string
const archivesDir
= _config
->FindDir("Dir::Cache::Archives");
85 string
const partialArchivesDir
= archivesDir
+ "partial/";
87 if (CreateAPTDirectoryIfNeeded(_config
->FindDir("Dir::State"), partialListDir
) == false &&
88 CreateAPTDirectoryIfNeeded(listDir
, partialListDir
) == false)
89 return _error
->Errno("Acquire", _("List directory %spartial is missing."), listDir
.c_str());
91 if (CreateAPTDirectoryIfNeeded(_config
->FindDir("Dir::Cache"), partialArchivesDir
) == false &&
92 CreateAPTDirectoryIfNeeded(archivesDir
, partialArchivesDir
) == false)
93 return _error
->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir
.c_str());
95 if (Lock
.empty() == true || _config
->FindB("Debug::NoLocking", false) == true)
98 // Lock the directory this acquire object will work in
99 LockFD
= GetLock(flCombine(Lock
, "lock"));
101 return _error
->Error(_("Unable to lock directory %s"), Lock
.c_str());
106 // Acquire::~pkgAcquire - Destructor /*{{{*/
107 // ---------------------------------------------------------------------
108 /* Free our memory, clean up the queues (destroy the workers) */
109 pkgAcquire::~pkgAcquire()
118 MethodConfig
*Jnk
= Configs
;
119 Configs
= Configs
->Next
;
124 // Acquire::Shutdown - Clean out the acquire object /*{{{*/
125 // ---------------------------------------------------------------------
127 void pkgAcquire::Shutdown()
129 while (Items
.empty() == false)
131 if (Items
[0]->Status
== Item::StatFetching
)
132 Items
[0]->Status
= Item::StatError
;
139 Queues
= Queues
->Next
;
144 // Acquire::Add - Add a new item /*{{{*/
145 // ---------------------------------------------------------------------
146 /* This puts an item on the acquire list. This list is mainly for tracking
148 void pkgAcquire::Add(Item
*Itm
)
150 Items
.push_back(Itm
);
153 // Acquire::Remove - Remove a item /*{{{*/
154 // ---------------------------------------------------------------------
155 /* Remove an item from the acquire list. This is usually not used.. */
156 void pkgAcquire::Remove(Item
*Itm
)
160 for (ItemIterator I
= Items
.begin(); I
!= Items
.end();)
172 // Acquire::AbortTransaction - Remove a transaction /*{{{*/
173 void pkgAcquire::AbortTransaction(unsigned long TransactionID
)
175 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
176 std::clog
<< "AbortTransaction: " << TransactionID
<< std::endl
;
178 std::vector
<Item
*> Transaction
;
179 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
180 if((*I
)->TransactionID
== TransactionID
)
181 Transaction
.push_back(*I
);
183 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
184 I
!= Transaction
.end(); ++I
)
186 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
187 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
188 // the transaction will abort, so stop anything that is idle
189 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
190 (*I
)->Status
= pkgAcquire::Item::StatDone
;
194 bool pkgAcquire::TransactionHasError(unsigned long TransactionID
)
196 std::vector
<Item
*> Transaction
;
197 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
198 if((*I
)->TransactionID
== TransactionID
)
199 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
200 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
205 // Acquire::CommitTransaction - Commit a transaction /*{{{*/
206 void pkgAcquire::CommitTransaction(unsigned long TransactionID
)
208 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
209 std::clog
<< "CommitTransaction: " << TransactionID
<< std::endl
;
211 std::vector
<Item
*> Transaction
;
212 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
213 if((*I
)->TransactionID
== TransactionID
)
214 Transaction
.push_back(*I
);
216 // move new files into place *and* remove files that are not
217 // part of the transaction but are still on disk
218 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
219 I
!= Transaction
.end(); ++I
)
221 if((*I
)->PartialFile
!= "")
223 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
225 << (*I
)->PartialFile
<< " -> "
226 << (*I
)->DestFile
<< std::endl
;
227 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
228 chmod((*I
)->DestFile
.c_str(),0644);
230 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
232 << (*I
)->DestFile
<< std::endl
;
233 unlink((*I
)->DestFile
.c_str());
235 // mark that this transaction is finished
236 (*I
)->TransactionID
= 0;
241 // Acquire::Add - Add a worker /*{{{*/
242 // ---------------------------------------------------------------------
243 /* A list of workers is kept so that the select loop can direct their FD
245 void pkgAcquire::Add(Worker
*Work
)
247 Work
->NextAcquire
= Workers
;
251 // Acquire::Remove - Remove a worker /*{{{*/
252 // ---------------------------------------------------------------------
253 /* A worker has died. This can not be done while the select loop is running
254 as it would require that RunFds could handling a changing list state and
256 void pkgAcquire::Remove(Worker
*Work
)
261 Worker
**I
= &Workers
;
265 *I
= (*I
)->NextAcquire
;
267 I
= &(*I
)->NextAcquire
;
271 // Acquire::Enqueue - Queue an URI for fetching /*{{{*/
272 // ---------------------------------------------------------------------
273 /* This is the entry point for an item. An item calls this function when
274 it is constructed which creates a queue (based on the current queue
275 mode) and puts the item in that queue. If the system is running then
276 the queue might be started. */
277 void pkgAcquire::Enqueue(ItemDesc
&Item
)
279 // Determine which queue to put the item in
280 const MethodConfig
*Config
;
281 string Name
= QueueName(Item
.URI
,Config
);
282 if (Name
.empty() == true)
285 // Find the queue structure
287 for (; I
!= 0 && I
->Name
!= Name
; I
= I
->Next
);
290 I
= new Queue(Name
,this);
298 // See if this is a local only URI
299 if (Config
->LocalOnly
== true && Item
.Owner
->Complete
== false)
300 Item
.Owner
->Local
= true;
301 Item
.Owner
->Status
= Item::StatIdle
;
303 // Queue it into the named queue
310 clog
<< "Fetching " << Item
.URI
<< endl
;
311 clog
<< " to " << Item
.Owner
->DestFile
<< endl
;
312 clog
<< " Queue is: " << Name
<< endl
;
316 // Acquire::Dequeue - Remove an item from all queues /*{{{*/
317 // ---------------------------------------------------------------------
318 /* This is called when an item is finished being fetched. It removes it
319 from all the queues */
320 void pkgAcquire::Dequeue(Item
*Itm
)
325 clog
<< "Dequeuing " << Itm
->DestFile
<< endl
;
327 for (; I
!= 0; I
= I
->Next
)
333 clog
<< "Dequeued from " << I
->Name
<< endl
;
341 // Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
342 // ---------------------------------------------------------------------
343 /* The string returned depends on the configuration settings and the
344 method parameters. Given something like http://foo.org/bar it can
345 return http://foo.org or http */
346 string
pkgAcquire::QueueName(string Uri
,MethodConfig
const *&Config
)
350 Config
= GetConfig(U
.Access
);
354 /* Single-Instance methods get exactly one queue per URI. This is
355 also used for the Access queue method */
356 if (Config
->SingleInstance
== true || QueueMode
== QueueAccess
)
359 string AccessSchema
= U
.Access
+ ':',
360 FullQueueName
= AccessSchema
+ U
.Host
;
361 unsigned int Instances
= 0, SchemaLength
= AccessSchema
.length();
364 for (; I
!= 0; I
= I
->Next
) {
365 // if the queue already exists, re-use it
366 if (I
->Name
== FullQueueName
)
367 return FullQueueName
;
369 if (I
->Name
.compare(0, SchemaLength
, AccessSchema
) == 0)
374 clog
<< "Found " << Instances
<< " instances of " << U
.Access
<< endl
;
377 if (Instances
>= (unsigned int)_config
->FindI("Acquire::QueueHost::Limit",10))
380 return FullQueueName
;
383 // Acquire::GetConfig - Fetch the configuration information /*{{{*/
384 // ---------------------------------------------------------------------
385 /* This locates the configuration structure for an access method. If
386 a config structure cannot be found a Worker will be created to
388 pkgAcquire::MethodConfig
*pkgAcquire::GetConfig(string Access
)
390 // Search for an existing config
392 for (Conf
= Configs
; Conf
!= 0; Conf
= Conf
->Next
)
393 if (Conf
->Access
== Access
)
396 // Create the new config class
397 Conf
= new MethodConfig
;
398 Conf
->Access
= Access
;
399 Conf
->Next
= Configs
;
402 // Create the worker to fetch the configuration
404 if (Work
.Start() == false)
407 /* if a method uses DownloadLimit, we switch to SingleInstance mode */
408 if(_config
->FindI("Acquire::"+Access
+"::Dl-Limit",0) > 0)
409 Conf
->SingleInstance
= true;
414 // Acquire::SetFds - Deal with readable FDs /*{{{*/
415 // ---------------------------------------------------------------------
416 /* Collect FDs that have activity monitors into the fd sets */
417 void pkgAcquire::SetFds(int &Fd
,fd_set
*RSet
,fd_set
*WSet
)
419 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
421 if (I
->InReady
== true && I
->InFd
>= 0)
425 FD_SET(I
->InFd
,RSet
);
427 if (I
->OutReady
== true && I
->OutFd
>= 0)
431 FD_SET(I
->OutFd
,WSet
);
436 // Acquire::RunFds - Deal with active FDs /*{{{*/
437 // ---------------------------------------------------------------------
438 /* Dispatch active FDs over to the proper workers. It is very important
439 that a worker never be erased while this is running! The queue class
440 should never erase a worker except during shutdown processing. */
441 void pkgAcquire::RunFds(fd_set
*RSet
,fd_set
*WSet
)
443 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
445 if (I
->InFd
>= 0 && FD_ISSET(I
->InFd
,RSet
) != 0)
447 if (I
->OutFd
>= 0 && FD_ISSET(I
->OutFd
,WSet
) != 0)
452 // Acquire::Run - Run the fetch sequence /*{{{*/
453 // ---------------------------------------------------------------------
454 /* This runs the queues. It manages a select loop for all of the
455 Worker tasks. The workers interact with the queues and items to
456 manage the actual fetch. */
457 pkgAcquire::RunResult
pkgAcquire::Run(int PulseIntervall
)
461 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
467 bool WasCancelled
= false;
469 // Run till all things have been acquired
472 tv
.tv_usec
= PulseIntervall
;
480 SetFds(Highest
,&RFds
,&WFds
);
485 Res
= select(Highest
+1,&RFds
,&WFds
,0,&tv
);
487 while (Res
< 0 && errno
== EINTR
);
491 _error
->Errno("select","Select has failed");
496 if (_error
->PendingError() == true)
499 // Timeout, notify the log class
500 if (Res
== 0 || (Log
!= 0 && Log
->Update
== true))
502 tv
.tv_usec
= PulseIntervall
;
503 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
505 if (Log
!= 0 && Log
->Pulse(this) == false)
516 // Shut down the acquire bits
518 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
521 // Shut down the items
522 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
525 if (_error
->PendingError())
532 // Acquire::Bump - Called when an item is dequeued /*{{{*/
533 // ---------------------------------------------------------------------
534 /* This routine bumps idle queues in hopes that they will be able to fetch
536 void pkgAcquire::Bump()
538 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
542 // Acquire::WorkerStep - Step to the next worker /*{{{*/
543 // ---------------------------------------------------------------------
544 /* Not inlined to advoid including acquire-worker.h */
545 pkgAcquire::Worker
*pkgAcquire::WorkerStep(Worker
*I
)
547 return I
->NextAcquire
;
550 // Acquire::Clean - Cleans a directory /*{{{*/
551 // ---------------------------------------------------------------------
552 /* This is a bit simplistic, it looks at every file in the dir and sees
553 if it is part of the download set. */
554 bool pkgAcquire::Clean(string Dir
)
556 // non-existing directories are by definition clean…
557 if (DirectoryExists(Dir
) == false)
561 return _error
->Error(_("Clean of %s is not supported"), Dir
.c_str());
563 DIR *D
= opendir(Dir
.c_str());
565 return _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
567 string StartDir
= SafeGetCWD();
568 if (chdir(Dir
.c_str()) != 0)
571 return _error
->Errno("chdir",_("Unable to change to %s"),Dir
.c_str());
574 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
577 if (strcmp(Dir
->d_name
,"lock") == 0 ||
578 strcmp(Dir
->d_name
,"partial") == 0 ||
579 strcmp(Dir
->d_name
,".") == 0 ||
580 strcmp(Dir
->d_name
,"..") == 0)
583 // Look in the get list
584 ItemCIterator I
= Items
.begin();
585 for (; I
!= Items
.end(); ++I
)
586 if (flNotDir((*I
)->DestFile
) == Dir
->d_name
)
589 // Nothing found, nuke it
590 if (I
== Items
.end())
595 if (chdir(StartDir
.c_str()) != 0)
596 return _error
->Errno("chdir",_("Unable to change to %s"),StartDir
.c_str());
600 // Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/
601 // ---------------------------------------------------------------------
602 /* This is the total number of bytes needed */
603 APT_PURE
unsigned long long pkgAcquire::TotalNeeded()
605 unsigned long long Total
= 0;
606 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
607 Total
+= (*I
)->FileSize
;
611 // Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/
612 // ---------------------------------------------------------------------
613 /* This is the number of bytes that is not local */
614 APT_PURE
unsigned long long pkgAcquire::FetchNeeded()
616 unsigned long long Total
= 0;
617 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
618 if ((*I
)->Local
== false)
619 Total
+= (*I
)->FileSize
;
623 // Acquire::PartialPresent - Number of partial bytes we already have /*{{{*/
624 // ---------------------------------------------------------------------
625 /* This is the number of bytes that is not local */
626 APT_PURE
unsigned long long pkgAcquire::PartialPresent()
628 unsigned long long Total
= 0;
629 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
630 if ((*I
)->Local
== false)
631 Total
+= (*I
)->PartialSize
;
635 // Acquire::UriBegin - Start iterator for the uri list /*{{{*/
636 // ---------------------------------------------------------------------
638 pkgAcquire::UriIterator
pkgAcquire::UriBegin()
640 return UriIterator(Queues
);
643 // Acquire::UriEnd - End iterator for the uri list /*{{{*/
644 // ---------------------------------------------------------------------
646 pkgAcquire::UriIterator
pkgAcquire::UriEnd()
648 return UriIterator(0);
651 // Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
652 // ---------------------------------------------------------------------
654 pkgAcquire::MethodConfig::MethodConfig()
656 SingleInstance
= false;
664 // Queue::Queue - Constructor /*{{{*/
665 // ---------------------------------------------------------------------
667 pkgAcquire::Queue::Queue(string Name
,pkgAcquire
*Owner
) : Name(Name
),
677 // Queue::~Queue - Destructor /*{{{*/
678 // ---------------------------------------------------------------------
680 pkgAcquire::Queue::~Queue()
692 // Queue::Enqueue - Queue an item to the queue /*{{{*/
693 // ---------------------------------------------------------------------
695 bool pkgAcquire::Queue::Enqueue(ItemDesc
&Item
)
698 // move to the end of the queue and check for duplicates here
699 for (; *I
!= 0; I
= &(*I
)->Next
)
700 if (Item
.URI
== (*I
)->URI
)
702 Item
.Owner
->Status
= Item::StatDone
;
707 QItem
*Itm
= new QItem
;
712 Item
.Owner
->QueueCounter
++;
713 if (Items
->Next
== 0)
718 // Queue::Dequeue - Remove an item from the queue /*{{{*/
719 // ---------------------------------------------------------------------
720 /* We return true if we hit something */
721 bool pkgAcquire::Queue::Dequeue(Item
*Owner
)
723 if (Owner
->Status
== pkgAcquire::Item::StatFetching
)
724 return _error
->Error("Tried to dequeue a fetching object");
731 if ((*I
)->Owner
== Owner
)
735 Owner
->QueueCounter
--;
746 // Queue::Startup - Start the worker processes /*{{{*/
747 // ---------------------------------------------------------------------
748 /* It is possible for this to be called with a pre-existing set of
750 bool pkgAcquire::Queue::Startup()
755 pkgAcquire::MethodConfig
*Cnf
= Owner
->GetConfig(U
.Access
);
759 Workers
= new Worker(this,Cnf
,Owner
->Log
);
761 if (Workers
->Start() == false)
764 /* When pipelining we commit 10 items. This needs to change when we
765 added other source retry to have cycle maintain a pipeline depth
767 if (Cnf
->Pipeline
== true)
768 MaxPipeDepth
= _config
->FindI("Acquire::Max-Pipeline-Depth",10);
776 // Queue::Shutdown - Shutdown the worker processes /*{{{*/
777 // ---------------------------------------------------------------------
778 /* If final is true then all workers are eliminated, otherwise only workers
779 that do not need cleanup are removed */
780 bool pkgAcquire::Queue::Shutdown(bool Final
)
782 // Delete all of the workers
783 pkgAcquire::Worker
**Cur
= &Workers
;
786 pkgAcquire::Worker
*Jnk
= *Cur
;
787 if (Final
== true || Jnk
->GetConf()->NeedsCleanup
== false)
789 *Cur
= Jnk
->NextQueue
;
794 Cur
= &(*Cur
)->NextQueue
;
800 // Queue::FindItem - Find a URI in the item list /*{{{*/
801 // ---------------------------------------------------------------------
803 pkgAcquire::Queue::QItem
*pkgAcquire::Queue::FindItem(string URI
,pkgAcquire::Worker
*Owner
)
805 for (QItem
*I
= Items
; I
!= 0; I
= I
->Next
)
806 if (I
->URI
== URI
&& I
->Worker
== Owner
)
811 // Queue::ItemDone - Item has been completed /*{{{*/
812 // ---------------------------------------------------------------------
813 /* The worker signals this which causes the item to be removed from the
814 queue. If this is the last queue instance then it is removed from the
816 bool pkgAcquire::Queue::ItemDone(QItem
*Itm
)
819 if (Itm
->Owner
->Status
== pkgAcquire::Item::StatFetching
)
820 Itm
->Owner
->Status
= pkgAcquire::Item::StatDone
;
822 if (Itm
->Owner
->QueueCounter
<= 1)
823 Owner
->Dequeue(Itm
->Owner
);
833 // Queue::Cycle - Queue new items into the method /*{{{*/
834 // ---------------------------------------------------------------------
835 /* This locates a new idle item and sends it to the worker. If pipelining
836 is enabled then it keeps the pipe full. */
837 bool pkgAcquire::Queue::Cycle()
839 if (Items
== 0 || Workers
== 0)
843 return _error
->Error("Pipedepth failure");
845 // Look for a queable item
847 while (PipeDepth
< (signed)MaxPipeDepth
)
849 for (; I
!= 0; I
= I
->Next
)
850 if (I
->Owner
->Status
== pkgAcquire::Item::StatIdle
)
853 // Nothing to do, queue is idle.
858 I
->Owner
->Status
= pkgAcquire::Item::StatFetching
;
860 if (Workers
->QueueItem(I
) == false)
867 // Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
868 // ---------------------------------------------------------------------
869 /* This is called when an item in multiple queues is dequeued */
870 void pkgAcquire::Queue::Bump()
875 // AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/
876 // ---------------------------------------------------------------------
878 pkgAcquireStatus::pkgAcquireStatus() : d(NULL
), Update(true), MorePulses(false)
883 // AcquireStatus::Pulse - Called periodically /*{{{*/
884 // ---------------------------------------------------------------------
885 /* This computes some internal state variables for the derived classes to
886 use. It generates the current downloaded bytes and total bytes to download
887 as well as the current CPS estimate. */
888 bool pkgAcquireStatus::Pulse(pkgAcquire
*Owner
)
895 // Compute the total number of bytes to fetch
896 unsigned int Unknown
= 0;
897 unsigned int Count
= 0;
898 bool UnfetchedReleaseFiles
= false;
899 for (pkgAcquire::ItemCIterator I
= Owner
->ItemsBegin();
900 I
!= Owner
->ItemsEnd();
904 if ((*I
)->Status
== pkgAcquire::Item::StatDone
)
907 // Totally ignore local items
908 if ((*I
)->Local
== true)
911 // see if the method tells us to expect more
912 TotalItems
+= (*I
)->ExpectedAdditionalItems
;
914 // check if there are unfetched Release files
915 if ((*I
)->Complete
== false && (*I
)->ExpectedAdditionalItems
> 0)
916 UnfetchedReleaseFiles
= true;
918 TotalBytes
+= (*I
)->FileSize
;
919 if ((*I
)->Complete
== true)
920 CurrentBytes
+= (*I
)->FileSize
;
921 if ((*I
)->FileSize
== 0 && (*I
)->Complete
== false)
925 // Compute the current completion
926 unsigned long long ResumeSize
= 0;
927 for (pkgAcquire::Worker
*I
= Owner
->WorkersBegin(); I
!= 0;
928 I
= Owner
->WorkerStep(I
))
930 if (I
->CurrentItem
!= 0 && I
->CurrentItem
->Owner
->Complete
== false)
932 CurrentBytes
+= I
->CurrentSize
;
933 ResumeSize
+= I
->ResumePoint
;
935 // Files with unknown size always have 100% completion
936 if (I
->CurrentItem
->Owner
->FileSize
== 0 &&
937 I
->CurrentItem
->Owner
->Complete
== false)
938 TotalBytes
+= I
->CurrentSize
;
942 // Normalize the figures and account for unknown size downloads
945 if (Unknown
== Count
)
946 TotalBytes
= Unknown
;
948 // Wha?! Is not supposed to happen.
949 if (CurrentBytes
> TotalBytes
)
950 CurrentBytes
= TotalBytes
;
953 if (_config
->FindB("Debug::acquire::progress", false) == true)
954 std::clog
<< " Bytes: "
955 << SizeToStr(CurrentBytes
) << " / " << SizeToStr(TotalBytes
)
959 struct timeval NewTime
;
960 gettimeofday(&NewTime
,0);
961 if ((NewTime
.tv_sec
- Time
.tv_sec
== 6 && NewTime
.tv_usec
> Time
.tv_usec
) ||
962 NewTime
.tv_sec
- Time
.tv_sec
> 6)
964 double Delta
= NewTime
.tv_sec
- Time
.tv_sec
+
965 (NewTime
.tv_usec
- Time
.tv_usec
)/1000000.0;
967 // Compute the CPS value
971 CurrentCPS
= ((CurrentBytes
- ResumeSize
) - LastBytes
)/Delta
;
972 LastBytes
= CurrentBytes
- ResumeSize
;
973 ElapsedTime
= (unsigned long long)Delta
;
977 // calculate the percentage, if we have too little data assume 1%
978 if (TotalBytes
> 0 && UnfetchedReleaseFiles
)
981 // use both files and bytes because bytes can be unreliable
982 Percent
= (0.8 * (CurrentBytes
/float(TotalBytes
)*100.0) +
983 0.2 * (CurrentItems
/float(TotalItems
)*100.0));
985 int fd
= _config
->FindI("APT::Status-Fd",-1);
988 ostringstream status
;
991 long i
= CurrentItems
< TotalItems
? CurrentItems
+ 1 : CurrentItems
;
992 unsigned long long ETA
= 0;
994 ETA
= (TotalBytes
- CurrentBytes
) / CurrentCPS
;
996 // only show the ETA if it makes sense
997 if (ETA
> 0 && ETA
< 172800 /* two days */ )
998 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li (%s remaining)"), i
, TotalItems
, TimeToStr(ETA
).c_str());
1000 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li"), i
, TotalItems
);
1002 // build the status str
1003 status
<< "dlstatus:" << i
1004 << ":" << std::setprecision(3) << Percent
1008 std::string
const dlstatus
= status
.str();
1009 FileFd::Write(fd
, dlstatus
.c_str(), dlstatus
.size());
1015 // AcquireStatus::Start - Called when the download is started /*{{{*/
1016 // ---------------------------------------------------------------------
1017 /* We just reset the counters */
1018 void pkgAcquireStatus::Start()
1020 gettimeofday(&Time
,0);
1021 gettimeofday(&StartTime
,0);
1032 // AcquireStatus::Stop - Finished downloading /*{{{*/
1033 // ---------------------------------------------------------------------
1034 /* This accurately computes the elapsed time and the total overall CPS. */
1035 void pkgAcquireStatus::Stop()
1037 // Compute the CPS and elapsed time
1038 struct timeval NewTime
;
1039 gettimeofday(&NewTime
,0);
1041 double Delta
= NewTime
.tv_sec
- StartTime
.tv_sec
+
1042 (NewTime
.tv_usec
- StartTime
.tv_usec
)/1000000.0;
1044 // Compute the CPS value
1048 CurrentCPS
= FetchedBytes
/Delta
;
1049 LastBytes
= CurrentBytes
;
1050 ElapsedTime
= (unsigned long long)Delta
;
1053 // AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/
1054 // ---------------------------------------------------------------------
1055 /* This is used to get accurate final transfer rate reporting. */
1056 void pkgAcquireStatus::Fetched(unsigned long long Size
,unsigned long long Resume
)
1058 FetchedBytes
+= Size
- Resume
;