]>
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
;
189 (*I
)->Status
= pkgAcquire::Item::StatError
;
193 bool pkgAcquire::TransactionHasError(unsigned long TransactionID
)
195 std::vector
<Item
*> Transaction
;
196 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
197 if((*I
)->TransactionID
== TransactionID
)
198 if((*I
)->Status
== pkgAcquire::Item::StatError
||
199 (*I
)->Status
== pkgAcquire::Item::StatAuthError
)
204 // Acquire::CommitTransaction - Commit a transaction /*{{{*/
205 void pkgAcquire::CommitTransaction(unsigned long TransactionID
)
207 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
208 std::clog
<< "CommitTransaction: " << TransactionID
<< std::endl
;
210 std::vector
<Item
*> Transaction
;
211 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
212 if((*I
)->TransactionID
== TransactionID
)
213 Transaction
.push_back(*I
);
215 // move new files into place *and* remove files that are not
216 // part of the transaction but are still on disk
217 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
218 I
!= Transaction
.end(); ++I
)
220 if((*I
)->PartialFile
!= "")
222 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
224 << (*I
)->PartialFile
<< " -> "
225 << (*I
)->DestFile
<< std::endl
;
226 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
227 chmod((*I
)->DestFile
.c_str(),0644);
229 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
231 << (*I
)->DestFile
<< std::endl
;
232 unlink((*I
)->DestFile
.c_str());
234 // mark that this transaction is finished
235 (*I
)->TransactionID
= 0;
240 // Acquire::Add - Add a worker /*{{{*/
241 // ---------------------------------------------------------------------
242 /* A list of workers is kept so that the select loop can direct their FD
244 void pkgAcquire::Add(Worker
*Work
)
246 Work
->NextAcquire
= Workers
;
250 // Acquire::Remove - Remove a worker /*{{{*/
251 // ---------------------------------------------------------------------
252 /* A worker has died. This can not be done while the select loop is running
253 as it would require that RunFds could handling a changing list state and
255 void pkgAcquire::Remove(Worker
*Work
)
260 Worker
**I
= &Workers
;
264 *I
= (*I
)->NextAcquire
;
266 I
= &(*I
)->NextAcquire
;
270 // Acquire::Enqueue - Queue an URI for fetching /*{{{*/
271 // ---------------------------------------------------------------------
272 /* This is the entry point for an item. An item calls this function when
273 it is constructed which creates a queue (based on the current queue
274 mode) and puts the item in that queue. If the system is running then
275 the queue might be started. */
276 void pkgAcquire::Enqueue(ItemDesc
&Item
)
278 // Determine which queue to put the item in
279 const MethodConfig
*Config
;
280 string Name
= QueueName(Item
.URI
,Config
);
281 if (Name
.empty() == true)
284 // Find the queue structure
286 for (; I
!= 0 && I
->Name
!= Name
; I
= I
->Next
);
289 I
= new Queue(Name
,this);
297 // See if this is a local only URI
298 if (Config
->LocalOnly
== true && Item
.Owner
->Complete
== false)
299 Item
.Owner
->Local
= true;
300 Item
.Owner
->Status
= Item::StatIdle
;
302 // Queue it into the named queue
309 clog
<< "Fetching " << Item
.URI
<< endl
;
310 clog
<< " to " << Item
.Owner
->DestFile
<< endl
;
311 clog
<< " Queue is: " << Name
<< endl
;
315 // Acquire::Dequeue - Remove an item from all queues /*{{{*/
316 // ---------------------------------------------------------------------
317 /* This is called when an item is finished being fetched. It removes it
318 from all the queues */
319 void pkgAcquire::Dequeue(Item
*Itm
)
324 clog
<< "Dequeuing " << Itm
->DestFile
<< endl
;
326 for (; I
!= 0; I
= I
->Next
)
332 clog
<< "Dequeued from " << I
->Name
<< endl
;
340 // Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
341 // ---------------------------------------------------------------------
342 /* The string returned depends on the configuration settings and the
343 method parameters. Given something like http://foo.org/bar it can
344 return http://foo.org or http */
345 string
pkgAcquire::QueueName(string Uri
,MethodConfig
const *&Config
)
349 Config
= GetConfig(U
.Access
);
353 /* Single-Instance methods get exactly one queue per URI. This is
354 also used for the Access queue method */
355 if (Config
->SingleInstance
== true || QueueMode
== QueueAccess
)
358 string AccessSchema
= U
.Access
+ ':',
359 FullQueueName
= AccessSchema
+ U
.Host
;
360 unsigned int Instances
= 0, SchemaLength
= AccessSchema
.length();
363 for (; I
!= 0; I
= I
->Next
) {
364 // if the queue already exists, re-use it
365 if (I
->Name
== FullQueueName
)
366 return FullQueueName
;
368 if (I
->Name
.compare(0, SchemaLength
, AccessSchema
) == 0)
373 clog
<< "Found " << Instances
<< " instances of " << U
.Access
<< endl
;
376 if (Instances
>= (unsigned int)_config
->FindI("Acquire::QueueHost::Limit",10))
379 return FullQueueName
;
382 // Acquire::GetConfig - Fetch the configuration information /*{{{*/
383 // ---------------------------------------------------------------------
384 /* This locates the configuration structure for an access method. If
385 a config structure cannot be found a Worker will be created to
387 pkgAcquire::MethodConfig
*pkgAcquire::GetConfig(string Access
)
389 // Search for an existing config
391 for (Conf
= Configs
; Conf
!= 0; Conf
= Conf
->Next
)
392 if (Conf
->Access
== Access
)
395 // Create the new config class
396 Conf
= new MethodConfig
;
397 Conf
->Access
= Access
;
398 Conf
->Next
= Configs
;
401 // Create the worker to fetch the configuration
403 if (Work
.Start() == false)
406 /* if a method uses DownloadLimit, we switch to SingleInstance mode */
407 if(_config
->FindI("Acquire::"+Access
+"::Dl-Limit",0) > 0)
408 Conf
->SingleInstance
= true;
413 // Acquire::SetFds - Deal with readable FDs /*{{{*/
414 // ---------------------------------------------------------------------
415 /* Collect FDs that have activity monitors into the fd sets */
416 void pkgAcquire::SetFds(int &Fd
,fd_set
*RSet
,fd_set
*WSet
)
418 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
420 if (I
->InReady
== true && I
->InFd
>= 0)
424 FD_SET(I
->InFd
,RSet
);
426 if (I
->OutReady
== true && I
->OutFd
>= 0)
430 FD_SET(I
->OutFd
,WSet
);
435 // Acquire::RunFds - Deal with active FDs /*{{{*/
436 // ---------------------------------------------------------------------
437 /* Dispatch active FDs over to the proper workers. It is very important
438 that a worker never be erased while this is running! The queue class
439 should never erase a worker except during shutdown processing. */
440 void pkgAcquire::RunFds(fd_set
*RSet
,fd_set
*WSet
)
442 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
444 if (I
->InFd
>= 0 && FD_ISSET(I
->InFd
,RSet
) != 0)
446 if (I
->OutFd
>= 0 && FD_ISSET(I
->OutFd
,WSet
) != 0)
451 // Acquire::Run - Run the fetch sequence /*{{{*/
452 // ---------------------------------------------------------------------
453 /* This runs the queues. It manages a select loop for all of the
454 Worker tasks. The workers interact with the queues and items to
455 manage the actual fetch. */
456 pkgAcquire::RunResult
pkgAcquire::Run(int PulseIntervall
)
460 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
466 bool WasCancelled
= false;
468 // Run till all things have been acquired
471 tv
.tv_usec
= PulseIntervall
;
479 SetFds(Highest
,&RFds
,&WFds
);
484 Res
= select(Highest
+1,&RFds
,&WFds
,0,&tv
);
486 while (Res
< 0 && errno
== EINTR
);
490 _error
->Errno("select","Select has failed");
495 if (_error
->PendingError() == true)
498 // Timeout, notify the log class
499 if (Res
== 0 || (Log
!= 0 && Log
->Update
== true))
501 tv
.tv_usec
= PulseIntervall
;
502 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
504 if (Log
!= 0 && Log
->Pulse(this) == false)
515 // Shut down the acquire bits
517 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
520 // Shut down the items
521 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
524 if (_error
->PendingError())
531 // Acquire::Bump - Called when an item is dequeued /*{{{*/
532 // ---------------------------------------------------------------------
533 /* This routine bumps idle queues in hopes that they will be able to fetch
535 void pkgAcquire::Bump()
537 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
541 // Acquire::WorkerStep - Step to the next worker /*{{{*/
542 // ---------------------------------------------------------------------
543 /* Not inlined to advoid including acquire-worker.h */
544 pkgAcquire::Worker
*pkgAcquire::WorkerStep(Worker
*I
)
546 return I
->NextAcquire
;
549 // Acquire::Clean - Cleans a directory /*{{{*/
550 // ---------------------------------------------------------------------
551 /* This is a bit simplistic, it looks at every file in the dir and sees
552 if it is part of the download set. */
553 bool pkgAcquire::Clean(string Dir
)
555 // non-existing directories are by definition clean…
556 if (DirectoryExists(Dir
) == false)
560 return _error
->Error(_("Clean of %s is not supported"), Dir
.c_str());
562 DIR *D
= opendir(Dir
.c_str());
564 return _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
566 string StartDir
= SafeGetCWD();
567 if (chdir(Dir
.c_str()) != 0)
570 return _error
->Errno("chdir",_("Unable to change to %s"),Dir
.c_str());
573 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
576 if (strcmp(Dir
->d_name
,"lock") == 0 ||
577 strcmp(Dir
->d_name
,"partial") == 0 ||
578 strcmp(Dir
->d_name
,".") == 0 ||
579 strcmp(Dir
->d_name
,"..") == 0)
582 // Look in the get list
583 ItemCIterator I
= Items
.begin();
584 for (; I
!= Items
.end(); ++I
)
585 if (flNotDir((*I
)->DestFile
) == Dir
->d_name
)
588 // Nothing found, nuke it
589 if (I
== Items
.end())
594 if (chdir(StartDir
.c_str()) != 0)
595 return _error
->Errno("chdir",_("Unable to change to %s"),StartDir
.c_str());
599 // Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/
600 // ---------------------------------------------------------------------
601 /* This is the total number of bytes needed */
602 APT_PURE
unsigned long long pkgAcquire::TotalNeeded()
604 unsigned long long Total
= 0;
605 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
606 Total
+= (*I
)->FileSize
;
610 // Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/
611 // ---------------------------------------------------------------------
612 /* This is the number of bytes that is not local */
613 APT_PURE
unsigned long long pkgAcquire::FetchNeeded()
615 unsigned long long Total
= 0;
616 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
617 if ((*I
)->Local
== false)
618 Total
+= (*I
)->FileSize
;
622 // Acquire::PartialPresent - Number of partial bytes we already have /*{{{*/
623 // ---------------------------------------------------------------------
624 /* This is the number of bytes that is not local */
625 APT_PURE
unsigned long long pkgAcquire::PartialPresent()
627 unsigned long long Total
= 0;
628 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
629 if ((*I
)->Local
== false)
630 Total
+= (*I
)->PartialSize
;
634 // Acquire::UriBegin - Start iterator for the uri list /*{{{*/
635 // ---------------------------------------------------------------------
637 pkgAcquire::UriIterator
pkgAcquire::UriBegin()
639 return UriIterator(Queues
);
642 // Acquire::UriEnd - End iterator for the uri list /*{{{*/
643 // ---------------------------------------------------------------------
645 pkgAcquire::UriIterator
pkgAcquire::UriEnd()
647 return UriIterator(0);
650 // Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
651 // ---------------------------------------------------------------------
653 pkgAcquire::MethodConfig::MethodConfig()
655 SingleInstance
= false;
663 // Queue::Queue - Constructor /*{{{*/
664 // ---------------------------------------------------------------------
666 pkgAcquire::Queue::Queue(string Name
,pkgAcquire
*Owner
) : Name(Name
),
676 // Queue::~Queue - Destructor /*{{{*/
677 // ---------------------------------------------------------------------
679 pkgAcquire::Queue::~Queue()
691 // Queue::Enqueue - Queue an item to the queue /*{{{*/
692 // ---------------------------------------------------------------------
694 bool pkgAcquire::Queue::Enqueue(ItemDesc
&Item
)
697 // move to the end of the queue and check for duplicates here
698 for (; *I
!= 0; I
= &(*I
)->Next
)
699 if (Item
.URI
== (*I
)->URI
)
701 Item
.Owner
->Status
= Item::StatDone
;
706 QItem
*Itm
= new QItem
;
711 Item
.Owner
->QueueCounter
++;
712 if (Items
->Next
== 0)
717 // Queue::Dequeue - Remove an item from the queue /*{{{*/
718 // ---------------------------------------------------------------------
719 /* We return true if we hit something */
720 bool pkgAcquire::Queue::Dequeue(Item
*Owner
)
722 if (Owner
->Status
== pkgAcquire::Item::StatFetching
)
723 return _error
->Error("Tried to dequeue a fetching object");
730 if ((*I
)->Owner
== Owner
)
734 Owner
->QueueCounter
--;
745 // Queue::Startup - Start the worker processes /*{{{*/
746 // ---------------------------------------------------------------------
747 /* It is possible for this to be called with a pre-existing set of
749 bool pkgAcquire::Queue::Startup()
754 pkgAcquire::MethodConfig
*Cnf
= Owner
->GetConfig(U
.Access
);
758 Workers
= new Worker(this,Cnf
,Owner
->Log
);
760 if (Workers
->Start() == false)
763 /* When pipelining we commit 10 items. This needs to change when we
764 added other source retry to have cycle maintain a pipeline depth
766 if (Cnf
->Pipeline
== true)
767 MaxPipeDepth
= _config
->FindI("Acquire::Max-Pipeline-Depth",10);
775 // Queue::Shutdown - Shutdown the worker processes /*{{{*/
776 // ---------------------------------------------------------------------
777 /* If final is true then all workers are eliminated, otherwise only workers
778 that do not need cleanup are removed */
779 bool pkgAcquire::Queue::Shutdown(bool Final
)
781 // Delete all of the workers
782 pkgAcquire::Worker
**Cur
= &Workers
;
785 pkgAcquire::Worker
*Jnk
= *Cur
;
786 if (Final
== true || Jnk
->GetConf()->NeedsCleanup
== false)
788 *Cur
= Jnk
->NextQueue
;
793 Cur
= &(*Cur
)->NextQueue
;
799 // Queue::FindItem - Find a URI in the item list /*{{{*/
800 // ---------------------------------------------------------------------
802 pkgAcquire::Queue::QItem
*pkgAcquire::Queue::FindItem(string URI
,pkgAcquire::Worker
*Owner
)
804 for (QItem
*I
= Items
; I
!= 0; I
= I
->Next
)
805 if (I
->URI
== URI
&& I
->Worker
== Owner
)
810 // Queue::ItemDone - Item has been completed /*{{{*/
811 // ---------------------------------------------------------------------
812 /* The worker signals this which causes the item to be removed from the
813 queue. If this is the last queue instance then it is removed from the
815 bool pkgAcquire::Queue::ItemDone(QItem
*Itm
)
818 if (Itm
->Owner
->Status
== pkgAcquire::Item::StatFetching
)
819 Itm
->Owner
->Status
= pkgAcquire::Item::StatDone
;
821 if (Itm
->Owner
->QueueCounter
<= 1)
822 Owner
->Dequeue(Itm
->Owner
);
832 // Queue::Cycle - Queue new items into the method /*{{{*/
833 // ---------------------------------------------------------------------
834 /* This locates a new idle item and sends it to the worker. If pipelining
835 is enabled then it keeps the pipe full. */
836 bool pkgAcquire::Queue::Cycle()
838 if (Items
== 0 || Workers
== 0)
842 return _error
->Error("Pipedepth failure");
844 // Look for a queable item
846 while (PipeDepth
< (signed)MaxPipeDepth
)
848 for (; I
!= 0; I
= I
->Next
)
849 if (I
->Owner
->Status
== pkgAcquire::Item::StatIdle
)
852 // Nothing to do, queue is idle.
857 I
->Owner
->Status
= pkgAcquire::Item::StatFetching
;
859 if (Workers
->QueueItem(I
) == false)
866 // Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
867 // ---------------------------------------------------------------------
868 /* This is called when an item in multiple queues is dequeued */
869 void pkgAcquire::Queue::Bump()
874 // AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/
875 // ---------------------------------------------------------------------
877 pkgAcquireStatus::pkgAcquireStatus() : d(NULL
), Update(true), MorePulses(false)
882 // AcquireStatus::Pulse - Called periodically /*{{{*/
883 // ---------------------------------------------------------------------
884 /* This computes some internal state variables for the derived classes to
885 use. It generates the current downloaded bytes and total bytes to download
886 as well as the current CPS estimate. */
887 bool pkgAcquireStatus::Pulse(pkgAcquire
*Owner
)
894 // Compute the total number of bytes to fetch
895 unsigned int Unknown
= 0;
896 unsigned int Count
= 0;
897 bool UnfetchedReleaseFiles
= false;
898 for (pkgAcquire::ItemCIterator I
= Owner
->ItemsBegin();
899 I
!= Owner
->ItemsEnd();
903 if ((*I
)->Status
== pkgAcquire::Item::StatDone
)
906 // Totally ignore local items
907 if ((*I
)->Local
== true)
910 // see if the method tells us to expect more
911 TotalItems
+= (*I
)->ExpectedAdditionalItems
;
913 // check if there are unfetched Release files
914 if ((*I
)->Complete
== false && (*I
)->ExpectedAdditionalItems
> 0)
915 UnfetchedReleaseFiles
= true;
917 TotalBytes
+= (*I
)->FileSize
;
918 if ((*I
)->Complete
== true)
919 CurrentBytes
+= (*I
)->FileSize
;
920 if ((*I
)->FileSize
== 0 && (*I
)->Complete
== false)
924 // Compute the current completion
925 unsigned long long ResumeSize
= 0;
926 for (pkgAcquire::Worker
*I
= Owner
->WorkersBegin(); I
!= 0;
927 I
= Owner
->WorkerStep(I
))
929 if (I
->CurrentItem
!= 0 && I
->CurrentItem
->Owner
->Complete
== false)
931 CurrentBytes
+= I
->CurrentSize
;
932 ResumeSize
+= I
->ResumePoint
;
934 // Files with unknown size always have 100% completion
935 if (I
->CurrentItem
->Owner
->FileSize
== 0 &&
936 I
->CurrentItem
->Owner
->Complete
== false)
937 TotalBytes
+= I
->CurrentSize
;
941 // Normalize the figures and account for unknown size downloads
944 if (Unknown
== Count
)
945 TotalBytes
= Unknown
;
947 // Wha?! Is not supposed to happen.
948 if (CurrentBytes
> TotalBytes
)
949 CurrentBytes
= TotalBytes
;
952 if (_config
->FindB("Debug::acquire::progress", false) == true)
953 std::clog
<< " Bytes: "
954 << SizeToStr(CurrentBytes
) << " / " << SizeToStr(TotalBytes
)
958 struct timeval NewTime
;
959 gettimeofday(&NewTime
,0);
960 if ((NewTime
.tv_sec
- Time
.tv_sec
== 6 && NewTime
.tv_usec
> Time
.tv_usec
) ||
961 NewTime
.tv_sec
- Time
.tv_sec
> 6)
963 double Delta
= NewTime
.tv_sec
- Time
.tv_sec
+
964 (NewTime
.tv_usec
- Time
.tv_usec
)/1000000.0;
966 // Compute the CPS value
970 CurrentCPS
= ((CurrentBytes
- ResumeSize
) - LastBytes
)/Delta
;
971 LastBytes
= CurrentBytes
- ResumeSize
;
972 ElapsedTime
= (unsigned long long)Delta
;
976 // calculate the percentage, if we have too little data assume 1%
977 if (TotalBytes
> 0 && UnfetchedReleaseFiles
)
980 // use both files and bytes because bytes can be unreliable
981 Percent
= (0.8 * (CurrentBytes
/float(TotalBytes
)*100.0) +
982 0.2 * (CurrentItems
/float(TotalItems
)*100.0));
984 int fd
= _config
->FindI("APT::Status-Fd",-1);
987 ostringstream status
;
990 long i
= CurrentItems
< TotalItems
? CurrentItems
+ 1 : CurrentItems
;
991 unsigned long long ETA
= 0;
993 ETA
= (TotalBytes
- CurrentBytes
) / CurrentCPS
;
995 // only show the ETA if it makes sense
996 if (ETA
> 0 && ETA
< 172800 /* two days */ )
997 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li (%s remaining)"), i
, TotalItems
, TimeToStr(ETA
).c_str());
999 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li"), i
, TotalItems
);
1001 // build the status str
1002 status
<< "dlstatus:" << i
1003 << ":" << std::setprecision(3) << Percent
1007 std::string
const dlstatus
= status
.str();
1008 FileFd::Write(fd
, dlstatus
.c_str(), dlstatus
.size());
1014 // AcquireStatus::Start - Called when the download is started /*{{{*/
1015 // ---------------------------------------------------------------------
1016 /* We just reset the counters */
1017 void pkgAcquireStatus::Start()
1019 gettimeofday(&Time
,0);
1020 gettimeofday(&StartTime
,0);
1031 // AcquireStatus::Stop - Finished downloading /*{{{*/
1032 // ---------------------------------------------------------------------
1033 /* This accurately computes the elapsed time and the total overall CPS. */
1034 void pkgAcquireStatus::Stop()
1036 // Compute the CPS and elapsed time
1037 struct timeval NewTime
;
1038 gettimeofday(&NewTime
,0);
1040 double Delta
= NewTime
.tv_sec
- StartTime
.tv_sec
+
1041 (NewTime
.tv_usec
- StartTime
.tv_usec
)/1000000.0;
1043 // Compute the CPS value
1047 CurrentCPS
= FetchedBytes
/Delta
;
1048 LastBytes
= CurrentBytes
;
1049 ElapsedTime
= (unsigned long long)Delta
;
1052 // AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/
1053 // ---------------------------------------------------------------------
1054 /* This is used to get accurate final transfer rate reporting. */
1055 void pkgAcquireStatus::Fetched(unsigned long long Size
,unsigned long long Resume
)
1057 FetchedBytes
+= Size
- Resume
;