]>
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>
46 // Acquire::pkgAcquire - Constructor /*{{{*/
47 // ---------------------------------------------------------------------
48 /* We grab some runtime state from the configuration space */
49 pkgAcquire::pkgAcquire() : LockFD(-1), Queues(0), Workers(0), Configs(0), Log(NULL
), ToFetch(0),
50 Debug(_config
->FindB("Debug::pkgAcquire",false)),
53 string
const Mode
= _config
->Find("Acquire::Queue-Mode","host");
54 if (strcasecmp(Mode
.c_str(),"host") == 0)
55 QueueMode
= QueueHost
;
56 if (strcasecmp(Mode
.c_str(),"access") == 0)
57 QueueMode
= QueueAccess
;
59 pkgAcquire::pkgAcquire(pkgAcquireStatus
*Progress
) : LockFD(-1), Queues(0), Workers(0),
60 Configs(0), Log(Progress
), ToFetch(0),
61 Debug(_config
->FindB("Debug::pkgAcquire",false)),
64 string
const Mode
= _config
->Find("Acquire::Queue-Mode","host");
65 if (strcasecmp(Mode
.c_str(),"host") == 0)
66 QueueMode
= QueueHost
;
67 if (strcasecmp(Mode
.c_str(),"access") == 0)
68 QueueMode
= QueueAccess
;
72 // Acquire::Setup - Delayed Constructor /*{{{*/
73 // ---------------------------------------------------------------------
74 /* Do everything needed to be a complete Acquire object and report the
75 success (or failure) back so the user knows that something is wrong… */
76 bool pkgAcquire::Setup(pkgAcquireStatus
*Progress
, string
const &Lock
)
80 // check for existence and possibly create auxiliary directories
81 string
const listDir
= _config
->FindDir("Dir::State::lists");
82 string
const partialListDir
= listDir
+ "partial/";
83 string
const archivesDir
= _config
->FindDir("Dir::Cache::Archives");
84 string
const partialArchivesDir
= archivesDir
+ "partial/";
86 if (CreateAPTDirectoryIfNeeded(_config
->FindDir("Dir::State"), partialListDir
) == false &&
87 CreateAPTDirectoryIfNeeded(listDir
, partialListDir
) == false)
88 return _error
->Errno("Acquire", _("List directory %spartial is missing."), listDir
.c_str());
90 if (CreateAPTDirectoryIfNeeded(_config
->FindDir("Dir::Cache"), partialArchivesDir
) == false &&
91 CreateAPTDirectoryIfNeeded(archivesDir
, partialArchivesDir
) == false)
92 return _error
->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir
.c_str());
94 if (Lock
.empty() == true || _config
->FindB("Debug::NoLocking", false) == true)
97 // Lock the directory this acquire object will work in
98 LockFD
= GetLock(flCombine(Lock
, "lock"));
100 return _error
->Error(_("Unable to lock directory %s"), Lock
.c_str());
105 // Acquire::~pkgAcquire - Destructor /*{{{*/
106 // ---------------------------------------------------------------------
107 /* Free our memory, clean up the queues (destroy the workers) */
108 pkgAcquire::~pkgAcquire()
117 MethodConfig
*Jnk
= Configs
;
118 Configs
= Configs
->Next
;
123 // Acquire::Shutdown - Clean out the acquire object /*{{{*/
124 // ---------------------------------------------------------------------
126 void pkgAcquire::Shutdown()
128 while (Items
.empty() == false)
130 if (Items
[0]->Status
== Item::StatFetching
)
131 Items
[0]->Status
= Item::StatError
;
138 Queues
= Queues
->Next
;
143 // Acquire::Add - Add a new item /*{{{*/
144 // ---------------------------------------------------------------------
145 /* This puts an item on the acquire list. This list is mainly for tracking
147 void pkgAcquire::Add(Item
*Itm
)
149 Items
.push_back(Itm
);
152 // Acquire::Remove - Remove a item /*{{{*/
153 // ---------------------------------------------------------------------
154 /* Remove an item from the acquire list. This is usually not used.. */
155 void pkgAcquire::Remove(Item
*Itm
)
159 for (ItemIterator I
= Items
.begin(); I
!= Items
.end();)
171 // Acquire::Add - Add a worker /*{{{*/
172 // ---------------------------------------------------------------------
173 /* A list of workers is kept so that the select loop can direct their FD
175 void pkgAcquire::Add(Worker
*Work
)
177 Work
->NextAcquire
= Workers
;
181 // Acquire::Remove - Remove a worker /*{{{*/
182 // ---------------------------------------------------------------------
183 /* A worker has died. This can not be done while the select loop is running
184 as it would require that RunFds could handling a changing list state and
186 void pkgAcquire::Remove(Worker
*Work
)
191 Worker
**I
= &Workers
;
195 *I
= (*I
)->NextAcquire
;
197 I
= &(*I
)->NextAcquire
;
201 // Acquire::Enqueue - Queue an URI for fetching /*{{{*/
202 // ---------------------------------------------------------------------
203 /* This is the entry point for an item. An item calls this function when
204 it is constructed which creates a queue (based on the current queue
205 mode) and puts the item in that queue. If the system is running then
206 the queue might be started. */
207 void pkgAcquire::Enqueue(ItemDesc
&Item
)
209 // Determine which queue to put the item in
210 const MethodConfig
*Config
;
211 string Name
= QueueName(Item
.URI
,Config
);
212 if (Name
.empty() == true)
215 // Find the queue structure
217 for (; I
!= 0 && I
->Name
!= Name
; I
= I
->Next
);
220 I
= new Queue(Name
,this);
228 // See if this is a local only URI
229 if (Config
->LocalOnly
== true && Item
.Owner
->Complete
== false)
230 Item
.Owner
->Local
= true;
231 Item
.Owner
->Status
= Item::StatIdle
;
233 // Queue it into the named queue
240 clog
<< "Fetching " << Item
.URI
<< endl
;
241 clog
<< " to " << Item
.Owner
->DestFile
<< endl
;
242 clog
<< " Queue is: " << Name
<< endl
;
246 // Acquire::Dequeue - Remove an item from all queues /*{{{*/
247 // ---------------------------------------------------------------------
248 /* This is called when an item is finished being fetched. It removes it
249 from all the queues */
250 void pkgAcquire::Dequeue(Item
*Itm
)
255 clog
<< "Dequeuing " << Itm
->DestFile
<< endl
;
257 for (; I
!= 0; I
= I
->Next
)
263 clog
<< "Dequeued from " << I
->Name
<< endl
;
271 // Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
272 // ---------------------------------------------------------------------
273 /* The string returned depends on the configuration settings and the
274 method parameters. Given something like http://foo.org/bar it can
275 return http://foo.org or http */
276 string
pkgAcquire::QueueName(string Uri
,MethodConfig
const *&Config
)
280 Config
= GetConfig(U
.Access
);
284 /* Single-Instance methods get exactly one queue per URI. This is
285 also used for the Access queue method */
286 if (Config
->SingleInstance
== true || QueueMode
== QueueAccess
)
289 string AccessSchema
= U
.Access
+ ':',
290 FullQueueName
= AccessSchema
+ U
.Host
;
291 unsigned int Instances
= 0, SchemaLength
= AccessSchema
.length();
294 for (; I
!= 0; I
= I
->Next
) {
295 // if the queue already exists, re-use it
296 if (I
->Name
== FullQueueName
)
297 return FullQueueName
;
299 if (I
->Name
.compare(0, SchemaLength
, AccessSchema
) == 0)
304 clog
<< "Found " << Instances
<< " instances of " << U
.Access
<< endl
;
307 if (Instances
>= (unsigned int)_config
->FindI("Acquire::QueueHost::Limit",10))
310 return FullQueueName
;
313 // Acquire::GetConfig - Fetch the configuration information /*{{{*/
314 // ---------------------------------------------------------------------
315 /* This locates the configuration structure for an access method. If
316 a config structure cannot be found a Worker will be created to
318 pkgAcquire::MethodConfig
*pkgAcquire::GetConfig(string Access
)
320 // Search for an existing config
322 for (Conf
= Configs
; Conf
!= 0; Conf
= Conf
->Next
)
323 if (Conf
->Access
== Access
)
326 // Create the new config class
327 Conf
= new MethodConfig
;
328 Conf
->Access
= Access
;
329 Conf
->Next
= Configs
;
332 // Create the worker to fetch the configuration
334 if (Work
.Start() == false)
337 /* if a method uses DownloadLimit, we switch to SingleInstance mode */
338 if(_config
->FindI("Acquire::"+Access
+"::Dl-Limit",0) > 0)
339 Conf
->SingleInstance
= true;
344 // Acquire::SetFds - Deal with readable FDs /*{{{*/
345 // ---------------------------------------------------------------------
346 /* Collect FDs that have activity monitors into the fd sets */
347 void pkgAcquire::SetFds(int &Fd
,fd_set
*RSet
,fd_set
*WSet
)
349 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
351 if (I
->InReady
== true && I
->InFd
>= 0)
355 FD_SET(I
->InFd
,RSet
);
357 if (I
->OutReady
== true && I
->OutFd
>= 0)
361 FD_SET(I
->OutFd
,WSet
);
366 // Acquire::RunFds - Deal with active FDs /*{{{*/
367 // ---------------------------------------------------------------------
368 /* Dispatch active FDs over to the proper workers. It is very important
369 that a worker never be erased while this is running! The queue class
370 should never erase a worker except during shutdown processing. */
371 void pkgAcquire::RunFds(fd_set
*RSet
,fd_set
*WSet
)
373 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
375 if (I
->InFd
>= 0 && FD_ISSET(I
->InFd
,RSet
) != 0)
377 if (I
->OutFd
>= 0 && FD_ISSET(I
->OutFd
,WSet
) != 0)
382 // Acquire::Run - Run the fetch sequence /*{{{*/
383 // ---------------------------------------------------------------------
384 /* This runs the queues. It manages a select loop for all of the
385 Worker tasks. The workers interact with the queues and items to
386 manage the actual fetch. */
387 pkgAcquire::RunResult
pkgAcquire::Run(int PulseIntervall
)
391 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
397 bool WasCancelled
= false;
399 // Run till all things have been acquired
402 tv
.tv_usec
= PulseIntervall
;
410 SetFds(Highest
,&RFds
,&WFds
);
415 Res
= select(Highest
+1,&RFds
,&WFds
,0,&tv
);
417 while (Res
< 0 && errno
== EINTR
);
421 _error
->Errno("select","Select has failed");
426 if (_error
->PendingError() == true)
429 // Timeout, notify the log class
430 if (Res
== 0 || (Log
!= 0 && Log
->Update
== true))
432 tv
.tv_usec
= PulseIntervall
;
433 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
435 if (Log
!= 0 && Log
->Pulse(this) == false)
446 // Shut down the acquire bits
448 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
451 // Shut down the items
452 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
455 if (_error
->PendingError())
462 // Acquire::Bump - Called when an item is dequeued /*{{{*/
463 // ---------------------------------------------------------------------
464 /* This routine bumps idle queues in hopes that they will be able to fetch
466 void pkgAcquire::Bump()
468 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
472 // Acquire::WorkerStep - Step to the next worker /*{{{*/
473 // ---------------------------------------------------------------------
474 /* Not inlined to advoid including acquire-worker.h */
475 pkgAcquire::Worker
*pkgAcquire::WorkerStep(Worker
*I
)
477 return I
->NextAcquire
;
480 // Acquire::Clean - Cleans a directory /*{{{*/
481 // ---------------------------------------------------------------------
482 /* This is a bit simplistic, it looks at every file in the dir and sees
483 if it is part of the download set. */
484 bool pkgAcquire::Clean(string Dir
)
486 // non-existing directories are by definition clean…
487 if (DirectoryExists(Dir
) == false)
490 DIR *D
= opendir(Dir
.c_str());
492 return _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
494 string StartDir
= SafeGetCWD();
495 if (chdir(Dir
.c_str()) != 0)
498 return _error
->Errno("chdir",_("Unable to change to %s"),Dir
.c_str());
501 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
504 if (strcmp(Dir
->d_name
,"lock") == 0 ||
505 strcmp(Dir
->d_name
,"partial") == 0 ||
506 strcmp(Dir
->d_name
,".") == 0 ||
507 strcmp(Dir
->d_name
,"..") == 0)
510 // Look in the get list
511 ItemCIterator I
= Items
.begin();
512 for (; I
!= Items
.end(); ++I
)
513 if (flNotDir((*I
)->DestFile
) == Dir
->d_name
)
516 // Nothing found, nuke it
517 if (I
== Items
.end())
522 if (chdir(StartDir
.c_str()) != 0)
523 return _error
->Errno("chdir",_("Unable to change to %s"),StartDir
.c_str());
527 // Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/
528 // ---------------------------------------------------------------------
529 /* This is the total number of bytes needed */
530 APT_PURE
unsigned long long pkgAcquire::TotalNeeded()
532 unsigned long long Total
= 0;
533 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
534 Total
+= (*I
)->FileSize
;
538 // Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/
539 // ---------------------------------------------------------------------
540 /* This is the number of bytes that is not local */
541 APT_PURE
unsigned long long pkgAcquire::FetchNeeded()
543 unsigned long long Total
= 0;
544 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
545 if ((*I
)->Local
== false)
546 Total
+= (*I
)->FileSize
;
550 // Acquire::PartialPresent - Number of partial bytes we already have /*{{{*/
551 // ---------------------------------------------------------------------
552 /* This is the number of bytes that is not local */
553 APT_PURE
unsigned long long pkgAcquire::PartialPresent()
555 unsigned long long Total
= 0;
556 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
557 if ((*I
)->Local
== false)
558 Total
+= (*I
)->PartialSize
;
562 // Acquire::UriBegin - Start iterator for the uri list /*{{{*/
563 // ---------------------------------------------------------------------
565 pkgAcquire::UriIterator
pkgAcquire::UriBegin()
567 return UriIterator(Queues
);
570 // Acquire::UriEnd - End iterator for the uri list /*{{{*/
571 // ---------------------------------------------------------------------
573 pkgAcquire::UriIterator
pkgAcquire::UriEnd()
575 return UriIterator(0);
578 // Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
579 // ---------------------------------------------------------------------
581 pkgAcquire::MethodConfig::MethodConfig()
583 SingleInstance
= false;
591 // Queue::Queue - Constructor /*{{{*/
592 // ---------------------------------------------------------------------
594 pkgAcquire::Queue::Queue(string Name
,pkgAcquire
*Owner
) : Name(Name
),
604 // Queue::~Queue - Destructor /*{{{*/
605 // ---------------------------------------------------------------------
607 pkgAcquire::Queue::~Queue()
619 // Queue::Enqueue - Queue an item to the queue /*{{{*/
620 // ---------------------------------------------------------------------
622 bool pkgAcquire::Queue::Enqueue(ItemDesc
&Item
)
625 // move to the end of the queue and check for duplicates here
626 for (; *I
!= 0; I
= &(*I
)->Next
)
627 if (Item
.URI
== (*I
)->URI
)
629 Item
.Owner
->Status
= Item::StatDone
;
634 QItem
*Itm
= new QItem
;
639 Item
.Owner
->QueueCounter
++;
640 if (Items
->Next
== 0)
645 // Queue::Dequeue - Remove an item from the queue /*{{{*/
646 // ---------------------------------------------------------------------
647 /* We return true if we hit something */
648 bool pkgAcquire::Queue::Dequeue(Item
*Owner
)
650 if (Owner
->Status
== pkgAcquire::Item::StatFetching
)
651 return _error
->Error("Tried to dequeue a fetching object");
658 if ((*I
)->Owner
== Owner
)
662 Owner
->QueueCounter
--;
673 // Queue::Startup - Start the worker processes /*{{{*/
674 // ---------------------------------------------------------------------
675 /* It is possible for this to be called with a pre-existing set of
677 bool pkgAcquire::Queue::Startup()
682 pkgAcquire::MethodConfig
*Cnf
= Owner
->GetConfig(U
.Access
);
686 Workers
= new Worker(this,Cnf
,Owner
->Log
);
688 if (Workers
->Start() == false)
691 /* When pipelining we commit 10 items. This needs to change when we
692 added other source retry to have cycle maintain a pipeline depth
694 if (Cnf
->Pipeline
== true)
695 MaxPipeDepth
= _config
->FindI("Acquire::Max-Pipeline-Depth",10);
703 // Queue::Shutdown - Shutdown the worker processes /*{{{*/
704 // ---------------------------------------------------------------------
705 /* If final is true then all workers are eliminated, otherwise only workers
706 that do not need cleanup are removed */
707 bool pkgAcquire::Queue::Shutdown(bool Final
)
709 // Delete all of the workers
710 pkgAcquire::Worker
**Cur
= &Workers
;
713 pkgAcquire::Worker
*Jnk
= *Cur
;
714 if (Final
== true || Jnk
->GetConf()->NeedsCleanup
== false)
716 *Cur
= Jnk
->NextQueue
;
721 Cur
= &(*Cur
)->NextQueue
;
727 // Queue::FindItem - Find a URI in the item list /*{{{*/
728 // ---------------------------------------------------------------------
730 pkgAcquire::Queue::QItem
*pkgAcquire::Queue::FindItem(string URI
,pkgAcquire::Worker
*Owner
)
732 for (QItem
*I
= Items
; I
!= 0; I
= I
->Next
)
733 if (I
->URI
== URI
&& I
->Worker
== Owner
)
738 // Queue::ItemDone - Item has been completed /*{{{*/
739 // ---------------------------------------------------------------------
740 /* The worker signals this which causes the item to be removed from the
741 queue. If this is the last queue instance then it is removed from the
743 bool pkgAcquire::Queue::ItemDone(QItem
*Itm
)
746 if (Itm
->Owner
->Status
== pkgAcquire::Item::StatFetching
)
747 Itm
->Owner
->Status
= pkgAcquire::Item::StatDone
;
749 if (Itm
->Owner
->QueueCounter
<= 1)
750 Owner
->Dequeue(Itm
->Owner
);
760 // Queue::Cycle - Queue new items into the method /*{{{*/
761 // ---------------------------------------------------------------------
762 /* This locates a new idle item and sends it to the worker. If pipelining
763 is enabled then it keeps the pipe full. */
764 bool pkgAcquire::Queue::Cycle()
766 if (Items
== 0 || Workers
== 0)
770 return _error
->Error("Pipedepth failure");
772 // Look for a queable item
774 while (PipeDepth
< (signed)MaxPipeDepth
)
776 for (; I
!= 0; I
= I
->Next
)
777 if (I
->Owner
->Status
== pkgAcquire::Item::StatIdle
)
780 // Nothing to do, queue is idle.
785 I
->Owner
->Status
= pkgAcquire::Item::StatFetching
;
787 if (Workers
->QueueItem(I
) == false)
794 // Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
795 // ---------------------------------------------------------------------
796 /* This is called when an item in multiple queues is dequeued */
797 void pkgAcquire::Queue::Bump()
802 // AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/
803 // ---------------------------------------------------------------------
805 pkgAcquireStatus::pkgAcquireStatus() : d(NULL
), Update(true), MorePulses(false)
810 // AcquireStatus::Pulse - Called periodically /*{{{*/
811 // ---------------------------------------------------------------------
812 /* This computes some internal state variables for the derived classes to
813 use. It generates the current downloaded bytes and total bytes to download
814 as well as the current CPS estimate. */
815 bool pkgAcquireStatus::Pulse(pkgAcquire
*Owner
)
822 // Compute the total number of bytes to fetch
823 unsigned int Unknown
= 0;
824 unsigned int Count
= 0;
825 bool UnfetchedReleaseFiles
= false;
826 for (pkgAcquire::ItemCIterator I
= Owner
->ItemsBegin();
827 I
!= Owner
->ItemsEnd();
831 if ((*I
)->Status
== pkgAcquire::Item::StatDone
)
834 // Totally ignore local items
835 if ((*I
)->Local
== true)
838 // see if the method tells us to expect more
839 TotalItems
+= (*I
)->ExpectedAdditionalItems
;
841 // check if there are unfetched Release files
842 if ((*I
)->Complete
== false && (*I
)->ExpectedAdditionalItems
> 0)
843 UnfetchedReleaseFiles
= true;
845 TotalBytes
+= (*I
)->FileSize
;
846 if ((*I
)->Complete
== true)
847 CurrentBytes
+= (*I
)->FileSize
;
848 if ((*I
)->FileSize
== 0 && (*I
)->Complete
== false)
852 // Compute the current completion
853 unsigned long long ResumeSize
= 0;
854 for (pkgAcquire::Worker
*I
= Owner
->WorkersBegin(); I
!= 0;
855 I
= Owner
->WorkerStep(I
))
857 if (I
->CurrentItem
!= 0 && I
->CurrentItem
->Owner
->Complete
== false)
859 CurrentBytes
+= I
->CurrentSize
;
860 ResumeSize
+= I
->ResumePoint
;
862 // Files with unknown size always have 100% completion
863 if (I
->CurrentItem
->Owner
->FileSize
== 0 &&
864 I
->CurrentItem
->Owner
->Complete
== false)
865 TotalBytes
+= I
->CurrentSize
;
869 // Normalize the figures and account for unknown size downloads
872 if (Unknown
== Count
)
873 TotalBytes
= Unknown
;
875 // Wha?! Is not supposed to happen.
876 if (CurrentBytes
> TotalBytes
)
877 CurrentBytes
= TotalBytes
;
880 if (_config
->FindB("Debug::acquire::progress", false) == true)
881 std::clog
<< " Bytes: "
882 << SizeToStr(CurrentBytes
) << " / " << SizeToStr(TotalBytes
)
886 struct timeval NewTime
;
887 gettimeofday(&NewTime
,0);
888 if ((NewTime
.tv_sec
- Time
.tv_sec
== 6 && NewTime
.tv_usec
> Time
.tv_usec
) ||
889 NewTime
.tv_sec
- Time
.tv_sec
> 6)
891 double Delta
= NewTime
.tv_sec
- Time
.tv_sec
+
892 (NewTime
.tv_usec
- Time
.tv_usec
)/1000000.0;
894 // Compute the CPS value
898 CurrentCPS
= ((CurrentBytes
- ResumeSize
) - LastBytes
)/Delta
;
899 LastBytes
= CurrentBytes
- ResumeSize
;
900 ElapsedTime
= (unsigned long long)Delta
;
904 // calculate the percentage, if we have too little data assume 1%
905 if (TotalBytes
> 0 && UnfetchedReleaseFiles
)
908 // use both files and bytes because bytes can be unreliable
909 Percent
= (0.8 * (CurrentBytes
/float(TotalBytes
)*100.0) +
910 0.2 * (CurrentItems
/float(TotalItems
)*100.0));
912 int fd
= _config
->FindI("APT::Status-Fd",-1);
915 ostringstream status
;
918 long i
= CurrentItems
< TotalItems
? CurrentItems
+ 1 : CurrentItems
;
919 unsigned long long ETA
= 0;
921 ETA
= (TotalBytes
- CurrentBytes
) / CurrentCPS
;
923 // only show the ETA if it makes sense
924 if (ETA
> 0 && ETA
< 172800 /* two days */ )
925 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li (%s remaining)"), i
, TotalItems
, TimeToStr(ETA
).c_str());
927 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li"), i
, TotalItems
);
929 // build the status str
930 status
<< "dlstatus:" << i
931 << ":" << std::setprecision(3) << Percent
935 std::string
const dlstatus
= status
.str();
936 FileFd::Write(fd
, dlstatus
.c_str(), dlstatus
.size());
942 // AcquireStatus::Start - Called when the download is started /*{{{*/
943 // ---------------------------------------------------------------------
944 /* We just reset the counters */
945 void pkgAcquireStatus::Start()
947 gettimeofday(&Time
,0);
948 gettimeofday(&StartTime
,0);
959 // AcquireStatus::Stop - Finished downloading /*{{{*/
960 // ---------------------------------------------------------------------
961 /* This accurately computes the elapsed time and the total overall CPS. */
962 void pkgAcquireStatus::Stop()
964 // Compute the CPS and elapsed time
965 struct timeval NewTime
;
966 gettimeofday(&NewTime
,0);
968 double Delta
= NewTime
.tv_sec
- StartTime
.tv_sec
+
969 (NewTime
.tv_usec
- StartTime
.tv_usec
)/1000000.0;
971 // Compute the CPS value
975 CurrentCPS
= FetchedBytes
/Delta
;
976 LastBytes
= CurrentBytes
;
977 ElapsedTime
= (unsigned long long)Delta
;
980 // AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/
981 // ---------------------------------------------------------------------
982 /* This is used to get accurate final transfer rate reporting. */
983 void pkgAcquireStatus::Fetched(unsigned long long Size
,unsigned long long Resume
)
985 FetchedBytes
+= Size
- Resume
;