]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire.cc
120e809e1b06a5b368558a636a56941429fa629b
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>
39 // Acquire::pkgAcquire - Constructor /*{{{*/
40 // ---------------------------------------------------------------------
41 /* We grab some runtime state from the configuration space */
42 pkgAcquire::pkgAcquire() : LockFD(-1), Queues(0), Workers(0), Configs(0), Log(NULL
), ToFetch(0),
43 Debug(_config
->FindB("Debug::pkgAcquire",false)),
46 string
const Mode
= _config
->Find("Acquire::Queue-Mode","host");
47 if (strcasecmp(Mode
.c_str(),"host") == 0)
48 QueueMode
= QueueHost
;
49 if (strcasecmp(Mode
.c_str(),"access") == 0)
50 QueueMode
= QueueAccess
;
52 pkgAcquire::pkgAcquire(pkgAcquireStatus
*Progress
) : LockFD(-1), Queues(0), Workers(0),
53 Configs(0), Log(Progress
), ToFetch(0),
54 Debug(_config
->FindB("Debug::pkgAcquire",false)),
57 string
const Mode
= _config
->Find("Acquire::Queue-Mode","host");
58 if (strcasecmp(Mode
.c_str(),"host") == 0)
59 QueueMode
= QueueHost
;
60 if (strcasecmp(Mode
.c_str(),"access") == 0)
61 QueueMode
= QueueAccess
;
65 // Acquire::Setup - Delayed Constructor /*{{{*/
66 // ---------------------------------------------------------------------
67 /* Do everything needed to be a complete Acquire object and report the
68 success (or failure) back so the user knows that something is wrong… */
69 bool pkgAcquire::Setup(pkgAcquireStatus
*Progress
, string
const &Lock
)
73 // check for existence and possibly create auxiliary directories
74 string
const listDir
= _config
->FindDir("Dir::State::lists");
75 string
const partialListDir
= listDir
+ "partial/";
76 string
const archivesDir
= _config
->FindDir("Dir::Cache::Archives");
77 string
const partialArchivesDir
= archivesDir
+ "partial/";
79 if (CreateAPTDirectoryIfNeeded(_config
->FindDir("Dir::State"), partialListDir
) == false &&
80 CreateAPTDirectoryIfNeeded(listDir
, partialListDir
) == false)
81 return _error
->Errno("Acquire", _("List directory %spartial is missing."), listDir
.c_str());
83 if (CreateAPTDirectoryIfNeeded(_config
->FindDir("Dir::Cache"), partialArchivesDir
) == false &&
84 CreateAPTDirectoryIfNeeded(archivesDir
, partialArchivesDir
) == false)
85 return _error
->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir
.c_str());
87 if (Lock
.empty() == true || _config
->FindB("Debug::NoLocking", false) == true)
90 // Lock the directory this acquire object will work in
91 LockFD
= GetLock(flCombine(Lock
, "lock"));
93 return _error
->Error(_("Unable to lock directory %s"), Lock
.c_str());
98 // Acquire::~pkgAcquire - Destructor /*{{{*/
99 // ---------------------------------------------------------------------
100 /* Free our memory, clean up the queues (destroy the workers) */
101 pkgAcquire::~pkgAcquire()
110 MethodConfig
*Jnk
= Configs
;
111 Configs
= Configs
->Next
;
116 // Acquire::Shutdown - Clean out the acquire object /*{{{*/
117 // ---------------------------------------------------------------------
119 void pkgAcquire::Shutdown()
121 while (Items
.empty() == false)
123 if (Items
[0]->Status
== Item::StatFetching
)
124 Items
[0]->Status
= Item::StatError
;
131 Queues
= Queues
->Next
;
136 // Acquire::Add - Add a new item /*{{{*/
137 // ---------------------------------------------------------------------
138 /* This puts an item on the acquire list. This list is mainly for tracking
140 void pkgAcquire::Add(Item
*Itm
)
142 Items
.push_back(Itm
);
145 // Acquire::Remove - Remove a item /*{{{*/
146 // ---------------------------------------------------------------------
147 /* Remove an item from the acquire list. This is usually not used.. */
148 void pkgAcquire::Remove(Item
*Itm
)
152 for (ItemIterator I
= Items
.begin(); I
!= Items
.end();)
164 // Acquire::Add - Add a worker /*{{{*/
165 // ---------------------------------------------------------------------
166 /* A list of workers is kept so that the select loop can direct their FD
168 void pkgAcquire::Add(Worker
*Work
)
170 Work
->NextAcquire
= Workers
;
174 // Acquire::Remove - Remove a worker /*{{{*/
175 // ---------------------------------------------------------------------
176 /* A worker has died. This can not be done while the select loop is running
177 as it would require that RunFds could handling a changing list state and
179 void pkgAcquire::Remove(Worker
*Work
)
184 Worker
**I
= &Workers
;
188 *I
= (*I
)->NextAcquire
;
190 I
= &(*I
)->NextAcquire
;
194 // Acquire::Enqueue - Queue an URI for fetching /*{{{*/
195 // ---------------------------------------------------------------------
196 /* This is the entry point for an item. An item calls this function when
197 it is constructed which creates a queue (based on the current queue
198 mode) and puts the item in that queue. If the system is running then
199 the queue might be started. */
200 void pkgAcquire::Enqueue(ItemDesc
&Item
)
202 // Determine which queue to put the item in
203 const MethodConfig
*Config
;
204 string Name
= QueueName(Item
.URI
,Config
);
205 if (Name
.empty() == true)
208 // Find the queue structure
210 for (; I
!= 0 && I
->Name
!= Name
; I
= I
->Next
);
213 I
= new Queue(Name
,this);
221 // See if this is a local only URI
222 if (Config
->LocalOnly
== true && Item
.Owner
->Complete
== false)
223 Item
.Owner
->Local
= true;
224 Item
.Owner
->Status
= Item::StatIdle
;
226 // Queue it into the named queue
233 clog
<< "Fetching " << Item
.URI
<< endl
;
234 clog
<< " to " << Item
.Owner
->DestFile
<< endl
;
235 clog
<< " Queue is: " << Name
<< endl
;
239 // Acquire::Dequeue - Remove an item from all queues /*{{{*/
240 // ---------------------------------------------------------------------
241 /* This is called when an item is finished being fetched. It removes it
242 from all the queues */
243 void pkgAcquire::Dequeue(Item
*Itm
)
248 clog
<< "Dequeuing " << Itm
->DestFile
<< endl
;
250 for (; I
!= 0; I
= I
->Next
)
256 clog
<< "Dequeued from " << I
->Name
<< endl
;
264 // Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
265 // ---------------------------------------------------------------------
266 /* The string returned depends on the configuration settings and the
267 method parameters. Given something like http://foo.org/bar it can
268 return http://foo.org or http */
269 string
pkgAcquire::QueueName(string Uri
,MethodConfig
const *&Config
)
273 Config
= GetConfig(U
.Access
);
277 /* Single-Instance methods get exactly one queue per URI. This is
278 also used for the Access queue method */
279 if (Config
->SingleInstance
== true || QueueMode
== QueueAccess
)
282 string AccessSchema
= U
.Access
+ ':',
283 FullQueueName
= AccessSchema
+ U
.Host
;
284 unsigned int Instances
= 0, SchemaLength
= AccessSchema
.length();
287 for (; I
!= 0; I
= I
->Next
) {
288 // if the queue already exists, re-use it
289 if (I
->Name
== FullQueueName
)
290 return FullQueueName
;
292 if (I
->Name
.compare(0, SchemaLength
, AccessSchema
) == 0)
297 clog
<< "Found " << Instances
<< " instances of " << U
.Access
<< endl
;
300 if (Instances
>= (unsigned int)_config
->FindI("Acquire::QueueHost::Limit",10))
303 return FullQueueName
;
306 // Acquire::GetConfig - Fetch the configuration information /*{{{*/
307 // ---------------------------------------------------------------------
308 /* This locates the configuration structure for an access method. If
309 a config structure cannot be found a Worker will be created to
311 pkgAcquire::MethodConfig
*pkgAcquire::GetConfig(string Access
)
313 // Search for an existing config
315 for (Conf
= Configs
; Conf
!= 0; Conf
= Conf
->Next
)
316 if (Conf
->Access
== Access
)
319 // Create the new config class
320 Conf
= new MethodConfig
;
321 Conf
->Access
= Access
;
322 Conf
->Next
= Configs
;
325 // Create the worker to fetch the configuration
327 if (Work
.Start() == false)
330 /* if a method uses DownloadLimit, we switch to SingleInstance mode */
331 if(_config
->FindI("Acquire::"+Access
+"::Dl-Limit",0) > 0)
332 Conf
->SingleInstance
= true;
337 // Acquire::SetFds - Deal with readable FDs /*{{{*/
338 // ---------------------------------------------------------------------
339 /* Collect FDs that have activity monitors into the fd sets */
340 void pkgAcquire::SetFds(int &Fd
,fd_set
*RSet
,fd_set
*WSet
)
342 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
344 if (I
->InReady
== true && I
->InFd
>= 0)
348 FD_SET(I
->InFd
,RSet
);
350 if (I
->OutReady
== true && I
->OutFd
>= 0)
354 FD_SET(I
->OutFd
,WSet
);
359 // Acquire::RunFds - Deal with active FDs /*{{{*/
360 // ---------------------------------------------------------------------
361 /* Dispatch active FDs over to the proper workers. It is very important
362 that a worker never be erased while this is running! The queue class
363 should never erase a worker except during shutdown processing. */
364 void pkgAcquire::RunFds(fd_set
*RSet
,fd_set
*WSet
)
366 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
368 if (I
->InFd
>= 0 && FD_ISSET(I
->InFd
,RSet
) != 0)
370 if (I
->OutFd
>= 0 && FD_ISSET(I
->OutFd
,WSet
) != 0)
375 // Acquire::Run - Run the fetch sequence /*{{{*/
376 // ---------------------------------------------------------------------
377 /* This runs the queues. It manages a select loop for all of the
378 Worker tasks. The workers interact with the queues and items to
379 manage the actual fetch. */
380 pkgAcquire::RunResult
pkgAcquire::Run(int PulseIntervall
)
384 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
390 bool WasCancelled
= false;
392 // Run till all things have been acquired
395 tv
.tv_usec
= PulseIntervall
;
403 SetFds(Highest
,&RFds
,&WFds
);
408 Res
= select(Highest
+1,&RFds
,&WFds
,0,&tv
);
410 while (Res
< 0 && errno
== EINTR
);
414 _error
->Errno("select","Select has failed");
419 if (_error
->PendingError() == true)
422 // Timeout, notify the log class
423 if (Res
== 0 || (Log
!= 0 && Log
->Update
== true))
425 tv
.tv_usec
= PulseIntervall
;
426 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
428 if (Log
!= 0 && Log
->Pulse(this) == false)
439 // Shut down the acquire bits
441 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
444 // Shut down the items
445 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
448 if (_error
->PendingError())
455 // Acquire::Bump - Called when an item is dequeued /*{{{*/
456 // ---------------------------------------------------------------------
457 /* This routine bumps idle queues in hopes that they will be able to fetch
459 void pkgAcquire::Bump()
461 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
465 // Acquire::WorkerStep - Step to the next worker /*{{{*/
466 // ---------------------------------------------------------------------
467 /* Not inlined to advoid including acquire-worker.h */
468 pkgAcquire::Worker
*pkgAcquire::WorkerStep(Worker
*I
)
470 return I
->NextAcquire
;
473 // Acquire::Clean - Cleans a directory /*{{{*/
474 // ---------------------------------------------------------------------
475 /* This is a bit simplistic, it looks at every file in the dir and sees
476 if it is part of the download set. */
477 bool pkgAcquire::Clean(string Dir
)
479 // non-existing directories are by definition clean…
480 if (DirectoryExists(Dir
) == false)
483 DIR *D
= opendir(Dir
.c_str());
485 return _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
487 string StartDir
= SafeGetCWD();
488 if (chdir(Dir
.c_str()) != 0)
491 return _error
->Errno("chdir",_("Unable to change to %s"),Dir
.c_str());
494 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
497 if (strcmp(Dir
->d_name
,"lock") == 0 ||
498 strcmp(Dir
->d_name
,"partial") == 0 ||
499 strcmp(Dir
->d_name
,".") == 0 ||
500 strcmp(Dir
->d_name
,"..") == 0)
503 // Look in the get list
504 ItemCIterator I
= Items
.begin();
505 for (; I
!= Items
.end(); ++I
)
506 if (flNotDir((*I
)->DestFile
) == Dir
->d_name
)
509 // Nothing found, nuke it
510 if (I
== Items
.end())
515 if (chdir(StartDir
.c_str()) != 0)
516 return _error
->Errno("chdir",_("Unable to change to %s"),StartDir
.c_str());
520 // Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/
521 // ---------------------------------------------------------------------
522 /* This is the total number of bytes needed */
523 unsigned long long pkgAcquire::TotalNeeded()
525 unsigned long long Total
= 0;
526 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
527 Total
+= (*I
)->FileSize
;
531 // Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/
532 // ---------------------------------------------------------------------
533 /* This is the number of bytes that is not local */
534 unsigned long long pkgAcquire::FetchNeeded()
536 unsigned long long Total
= 0;
537 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
538 if ((*I
)->Local
== false)
539 Total
+= (*I
)->FileSize
;
543 // Acquire::PartialPresent - Number of partial bytes we already have /*{{{*/
544 // ---------------------------------------------------------------------
545 /* This is the number of bytes that is not local */
546 unsigned long long pkgAcquire::PartialPresent()
548 unsigned long long Total
= 0;
549 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
550 if ((*I
)->Local
== false)
551 Total
+= (*I
)->PartialSize
;
555 // Acquire::UriBegin - Start iterator for the uri list /*{{{*/
556 // ---------------------------------------------------------------------
558 pkgAcquire::UriIterator
pkgAcquire::UriBegin()
560 return UriIterator(Queues
);
563 // Acquire::UriEnd - End iterator for the uri list /*{{{*/
564 // ---------------------------------------------------------------------
566 pkgAcquire::UriIterator
pkgAcquire::UriEnd()
568 return UriIterator(0);
571 // Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
572 // ---------------------------------------------------------------------
574 pkgAcquire::MethodConfig::MethodConfig()
576 SingleInstance
= false;
584 // Queue::Queue - Constructor /*{{{*/
585 // ---------------------------------------------------------------------
587 pkgAcquire::Queue::Queue(string Name
,pkgAcquire
*Owner
) : Name(Name
),
597 // Queue::~Queue - Destructor /*{{{*/
598 // ---------------------------------------------------------------------
600 pkgAcquire::Queue::~Queue()
612 // Queue::Enqueue - Queue an item to the queue /*{{{*/
613 // ---------------------------------------------------------------------
615 bool pkgAcquire::Queue::Enqueue(ItemDesc
&Item
)
618 // move to the end of the queue and check for duplicates here
619 for (; *I
!= 0; I
= &(*I
)->Next
)
620 if (Item
.URI
== (*I
)->URI
)
622 Item
.Owner
->Status
= Item::StatDone
;
627 QItem
*Itm
= new QItem
;
632 Item
.Owner
->QueueCounter
++;
633 if (Items
->Next
== 0)
638 // Queue::Dequeue - Remove an item from the queue /*{{{*/
639 // ---------------------------------------------------------------------
640 /* We return true if we hit something */
641 bool pkgAcquire::Queue::Dequeue(Item
*Owner
)
643 if (Owner
->Status
== pkgAcquire::Item::StatFetching
)
644 return _error
->Error("Tried to dequeue a fetching object");
651 if ((*I
)->Owner
== Owner
)
655 Owner
->QueueCounter
--;
666 // Queue::Startup - Start the worker processes /*{{{*/
667 // ---------------------------------------------------------------------
668 /* It is possible for this to be called with a pre-existing set of
670 bool pkgAcquire::Queue::Startup()
675 pkgAcquire::MethodConfig
*Cnf
= Owner
->GetConfig(U
.Access
);
679 Workers
= new Worker(this,Cnf
,Owner
->Log
);
681 if (Workers
->Start() == false)
684 /* When pipelining we commit 10 items. This needs to change when we
685 added other source retry to have cycle maintain a pipeline depth
687 if (Cnf
->Pipeline
== true)
688 MaxPipeDepth
= _config
->FindI("Acquire::Max-Pipeline-Depth",10);
696 // Queue::Shutdown - Shutdown the worker processes /*{{{*/
697 // ---------------------------------------------------------------------
698 /* If final is true then all workers are eliminated, otherwise only workers
699 that do not need cleanup are removed */
700 bool pkgAcquire::Queue::Shutdown(bool Final
)
702 // Delete all of the workers
703 pkgAcquire::Worker
**Cur
= &Workers
;
706 pkgAcquire::Worker
*Jnk
= *Cur
;
707 if (Final
== true || Jnk
->GetConf()->NeedsCleanup
== false)
709 *Cur
= Jnk
->NextQueue
;
714 Cur
= &(*Cur
)->NextQueue
;
720 // Queue::FindItem - Find a URI in the item list /*{{{*/
721 // ---------------------------------------------------------------------
723 pkgAcquire::Queue::QItem
*pkgAcquire::Queue::FindItem(string URI
,pkgAcquire::Worker
*Owner
)
725 for (QItem
*I
= Items
; I
!= 0; I
= I
->Next
)
726 if (I
->URI
== URI
&& I
->Worker
== Owner
)
731 // Queue::ItemDone - Item has been completed /*{{{*/
732 // ---------------------------------------------------------------------
733 /* The worker signals this which causes the item to be removed from the
734 queue. If this is the last queue instance then it is removed from the
736 bool pkgAcquire::Queue::ItemDone(QItem
*Itm
)
739 if (Itm
->Owner
->Status
== pkgAcquire::Item::StatFetching
)
740 Itm
->Owner
->Status
= pkgAcquire::Item::StatDone
;
742 if (Itm
->Owner
->QueueCounter
<= 1)
743 Owner
->Dequeue(Itm
->Owner
);
753 // Queue::Cycle - Queue new items into the method /*{{{*/
754 // ---------------------------------------------------------------------
755 /* This locates a new idle item and sends it to the worker. If pipelining
756 is enabled then it keeps the pipe full. */
757 bool pkgAcquire::Queue::Cycle()
759 if (Items
== 0 || Workers
== 0)
763 return _error
->Error("Pipedepth failure");
765 // Look for a queable item
767 while (PipeDepth
< (signed)MaxPipeDepth
)
769 for (; I
!= 0; I
= I
->Next
)
770 if (I
->Owner
->Status
== pkgAcquire::Item::StatIdle
)
773 // Nothing to do, queue is idle.
778 I
->Owner
->Status
= pkgAcquire::Item::StatFetching
;
780 if (Workers
->QueueItem(I
) == false)
787 // Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
788 // ---------------------------------------------------------------------
789 /* This is called when an item in multiple queues is dequeued */
790 void pkgAcquire::Queue::Bump()
795 // AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/
796 // ---------------------------------------------------------------------
798 pkgAcquireStatus::pkgAcquireStatus() : d(NULL
), Update(true), MorePulses(false)
803 // AcquireStatus::Pulse - Called periodically /*{{{*/
804 // ---------------------------------------------------------------------
805 /* This computes some internal state variables for the derived classes to
806 use. It generates the current downloaded bytes and total bytes to download
807 as well as the current CPS estimate. */
808 bool pkgAcquireStatus::Pulse(pkgAcquire
*Owner
)
815 // Compute the total number of bytes to fetch
816 unsigned int Unknown
= 0;
817 unsigned int Count
= 0;
818 for (pkgAcquire::ItemCIterator I
= Owner
->ItemsBegin(); I
!= Owner
->ItemsEnd();
822 if ((*I
)->Status
== pkgAcquire::Item::StatDone
)
825 // Totally ignore local items
826 if ((*I
)->Local
== true)
829 TotalBytes
+= (*I
)->FileSize
;
830 if ((*I
)->Complete
== true)
831 CurrentBytes
+= (*I
)->FileSize
;
832 if ((*I
)->FileSize
== 0 && (*I
)->Complete
== false)
836 // Compute the current completion
837 unsigned long long ResumeSize
= 0;
838 for (pkgAcquire::Worker
*I
= Owner
->WorkersBegin(); I
!= 0;
839 I
= Owner
->WorkerStep(I
))
840 if (I
->CurrentItem
!= 0 && I
->CurrentItem
->Owner
->Complete
== false)
842 CurrentBytes
+= I
->CurrentSize
;
843 ResumeSize
+= I
->ResumePoint
;
845 // Files with unknown size always have 100% completion
846 if (I
->CurrentItem
->Owner
->FileSize
== 0 &&
847 I
->CurrentItem
->Owner
->Complete
== false)
848 TotalBytes
+= I
->CurrentSize
;
851 // Normalize the figures and account for unknown size downloads
854 if (Unknown
== Count
)
855 TotalBytes
= Unknown
;
857 // Wha?! Is not supposed to happen.
858 if (CurrentBytes
> TotalBytes
)
859 CurrentBytes
= TotalBytes
;
862 struct timeval NewTime
;
863 gettimeofday(&NewTime
,0);
864 if ((NewTime
.tv_sec
- Time
.tv_sec
== 6 && NewTime
.tv_usec
> Time
.tv_usec
) ||
865 NewTime
.tv_sec
- Time
.tv_sec
> 6)
867 double Delta
= NewTime
.tv_sec
- Time
.tv_sec
+
868 (NewTime
.tv_usec
- Time
.tv_usec
)/1000000.0;
870 // Compute the CPS value
874 CurrentCPS
= ((CurrentBytes
- ResumeSize
) - LastBytes
)/Delta
;
875 LastBytes
= CurrentBytes
- ResumeSize
;
876 ElapsedTime
= (unsigned long long)Delta
;
880 int fd
= _config
->FindI("APT::Status-Fd",-1);
883 ostringstream status
;
886 long i
= CurrentItems
< TotalItems
? CurrentItems
+ 1 : CurrentItems
;
887 unsigned long long ETA
= 0;
889 ETA
= (TotalBytes
- CurrentBytes
) / CurrentCPS
;
891 // only show the ETA if it makes sense
892 if (ETA
> 0 && ETA
< 172800 /* two days */ )
893 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li (%s remaining)"), i
, TotalItems
, TimeToStr(ETA
).c_str());
895 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li"), i
, TotalItems
);
899 // build the status str
900 status
<< "dlstatus:" << i
901 << ":" << (CurrentBytes
/float(TotalBytes
)*100.0)
905 std::string
const dlstatus
= status
.str();
906 FileFd::Write(fd
, dlstatus
.c_str(), dlstatus
.size());
912 // AcquireStatus::Start - Called when the download is started /*{{{*/
913 // ---------------------------------------------------------------------
914 /* We just reset the counters */
915 void pkgAcquireStatus::Start()
917 gettimeofday(&Time
,0);
918 gettimeofday(&StartTime
,0);
929 // AcquireStatus::Stop - Finished downloading /*{{{*/
930 // ---------------------------------------------------------------------
931 /* This accurately computes the elapsed time and the total overall CPS. */
932 void pkgAcquireStatus::Stop()
934 // Compute the CPS and elapsed time
935 struct timeval NewTime
;
936 gettimeofday(&NewTime
,0);
938 double Delta
= NewTime
.tv_sec
- StartTime
.tv_sec
+
939 (NewTime
.tv_usec
- StartTime
.tv_usec
)/1000000.0;
941 // Compute the CPS value
945 CurrentCPS
= FetchedBytes
/Delta
;
946 LastBytes
= CurrentBytes
;
947 ElapsedTime
= (unsigned long long)Delta
;
950 // AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/
951 // ---------------------------------------------------------------------
952 /* This is used to get accurate final transfer rate reporting. */
953 void pkgAcquireStatus::Fetched(unsigned long long Size
,unsigned long long Resume
)
955 FetchedBytes
+= Size
- Resume
;