]>
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 schedual system is the concept of a named
9 queue. Each queue is unique and each queue has a name derived from the
10 URI. The degree of paralization can be controled by how the queue
11 name is derived from the URI.
13 ##################################################################### */
15 // Include Files /*{{{*/
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
)
247 for (; I
!= 0; I
= I
->Next
)
248 Res
|= I
->Dequeue(Itm
);
251 clog
<< "Dequeuing " << Itm
->DestFile
<< endl
;
256 // Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
257 // ---------------------------------------------------------------------
258 /* The string returned depends on the configuration settings and the
259 method parameters. Given something like http://foo.org/bar it can
260 return http://foo.org or http */
261 string
pkgAcquire::QueueName(string Uri
,MethodConfig
const *&Config
)
265 Config
= GetConfig(U
.Access
);
269 /* Single-Instance methods get exactly one queue per URI. This is
270 also used for the Access queue method */
271 if (Config
->SingleInstance
== true || QueueMode
== QueueAccess
)
274 return U
.Access
+ ':' + U
.Host
;
277 // Acquire::GetConfig - Fetch the configuration information /*{{{*/
278 // ---------------------------------------------------------------------
279 /* This locates the configuration structure for an access method. If
280 a config structure cannot be found a Worker will be created to
282 pkgAcquire::MethodConfig
*pkgAcquire::GetConfig(string Access
)
284 // Search for an existing config
286 for (Conf
= Configs
; Conf
!= 0; Conf
= Conf
->Next
)
287 if (Conf
->Access
== Access
)
290 // Create the new config class
291 Conf
= new MethodConfig
;
292 Conf
->Access
= Access
;
293 Conf
->Next
= Configs
;
296 // Create the worker to fetch the configuration
298 if (Work
.Start() == false)
301 /* if a method uses DownloadLimit, we switch to SingleInstance mode */
302 if(_config
->FindI("Acquire::"+Access
+"::Dl-Limit",0) > 0)
303 Conf
->SingleInstance
= true;
308 // Acquire::SetFds - Deal with readable FDs /*{{{*/
309 // ---------------------------------------------------------------------
310 /* Collect FDs that have activity monitors into the fd sets */
311 void pkgAcquire::SetFds(int &Fd
,fd_set
*RSet
,fd_set
*WSet
)
313 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
315 if (I
->InReady
== true && I
->InFd
>= 0)
319 FD_SET(I
->InFd
,RSet
);
321 if (I
->OutReady
== true && I
->OutFd
>= 0)
325 FD_SET(I
->OutFd
,WSet
);
330 // Acquire::RunFds - Deal with active FDs /*{{{*/
331 // ---------------------------------------------------------------------
332 /* Dispatch active FDs over to the proper workers. It is very important
333 that a worker never be erased while this is running! The queue class
334 should never erase a worker except during shutdown processing. */
335 void pkgAcquire::RunFds(fd_set
*RSet
,fd_set
*WSet
)
337 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
339 if (I
->InFd
>= 0 && FD_ISSET(I
->InFd
,RSet
) != 0)
341 if (I
->OutFd
>= 0 && FD_ISSET(I
->OutFd
,WSet
) != 0)
346 // Acquire::Run - Run the fetch sequence /*{{{*/
347 // ---------------------------------------------------------------------
348 /* This runs the queues. It manages a select loop for all of the
349 Worker tasks. The workers interact with the queues and items to
350 manage the actual fetch. */
351 pkgAcquire::RunResult
pkgAcquire::Run(int PulseIntervall
)
355 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
361 bool WasCancelled
= false;
363 // Run till all things have been acquired
366 tv
.tv_usec
= PulseIntervall
;
374 SetFds(Highest
,&RFds
,&WFds
);
379 Res
= select(Highest
+1,&RFds
,&WFds
,0,&tv
);
381 while (Res
< 0 && errno
== EINTR
);
385 _error
->Errno("select","Select has failed");
390 if (_error
->PendingError() == true)
393 // Timeout, notify the log class
394 if (Res
== 0 || (Log
!= 0 && Log
->Update
== true))
396 tv
.tv_usec
= PulseIntervall
;
397 for (Worker
*I
= Workers
; I
!= 0; I
= I
->NextAcquire
)
399 if (Log
!= 0 && Log
->Pulse(this) == false)
410 // Shut down the acquire bits
412 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
415 // Shut down the items
416 for (ItemIterator I
= Items
.begin(); I
!= Items
.end(); ++I
)
419 if (_error
->PendingError())
426 // Acquire::Bump - Called when an item is dequeued /*{{{*/
427 // ---------------------------------------------------------------------
428 /* This routine bumps idle queues in hopes that they will be able to fetch
430 void pkgAcquire::Bump()
432 for (Queue
*I
= Queues
; I
!= 0; I
= I
->Next
)
436 // Acquire::WorkerStep - Step to the next worker /*{{{*/
437 // ---------------------------------------------------------------------
438 /* Not inlined to advoid including acquire-worker.h */
439 pkgAcquire::Worker
*pkgAcquire::WorkerStep(Worker
*I
)
441 return I
->NextAcquire
;
444 // Acquire::Clean - Cleans a directory /*{{{*/
445 // ---------------------------------------------------------------------
446 /* This is a bit simplistic, it looks at every file in the dir and sees
447 if it is part of the download set. */
448 bool pkgAcquire::Clean(string Dir
)
450 // non-existing directories are by definition clean…
451 if (DirectoryExists(Dir
) == false)
454 DIR *D
= opendir(Dir
.c_str());
456 return _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
458 string StartDir
= SafeGetCWD();
459 if (chdir(Dir
.c_str()) != 0)
462 return _error
->Errno("chdir",_("Unable to change to %s"),Dir
.c_str());
465 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
468 if (strcmp(Dir
->d_name
,"lock") == 0 ||
469 strcmp(Dir
->d_name
,"partial") == 0 ||
470 strcmp(Dir
->d_name
,".") == 0 ||
471 strcmp(Dir
->d_name
,"..") == 0)
474 // Look in the get list
475 ItemCIterator I
= Items
.begin();
476 for (; I
!= Items
.end(); ++I
)
477 if (flNotDir((*I
)->DestFile
) == Dir
->d_name
)
480 // Nothing found, nuke it
481 if (I
== Items
.end())
486 if (chdir(StartDir
.c_str()) != 0)
487 return _error
->Errno("chdir",_("Unable to change to %s"),StartDir
.c_str());
491 // Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/
492 // ---------------------------------------------------------------------
493 /* This is the total number of bytes needed */
494 unsigned long long pkgAcquire::TotalNeeded()
496 unsigned long long Total
= 0;
497 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
498 Total
+= (*I
)->FileSize
;
502 // Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/
503 // ---------------------------------------------------------------------
504 /* This is the number of bytes that is not local */
505 unsigned long long pkgAcquire::FetchNeeded()
507 unsigned long long Total
= 0;
508 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
509 if ((*I
)->Local
== false)
510 Total
+= (*I
)->FileSize
;
514 // Acquire::PartialPresent - Number of partial bytes we already have /*{{{*/
515 // ---------------------------------------------------------------------
516 /* This is the number of bytes that is not local */
517 unsigned long long pkgAcquire::PartialPresent()
519 unsigned long long Total
= 0;
520 for (ItemCIterator I
= ItemsBegin(); I
!= ItemsEnd(); ++I
)
521 if ((*I
)->Local
== false)
522 Total
+= (*I
)->PartialSize
;
526 // Acquire::UriBegin - Start iterator for the uri list /*{{{*/
527 // ---------------------------------------------------------------------
529 pkgAcquire::UriIterator
pkgAcquire::UriBegin()
531 return UriIterator(Queues
);
534 // Acquire::UriEnd - End iterator for the uri list /*{{{*/
535 // ---------------------------------------------------------------------
537 pkgAcquire::UriIterator
pkgAcquire::UriEnd()
539 return UriIterator(0);
542 // Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
543 // ---------------------------------------------------------------------
545 pkgAcquire::MethodConfig::MethodConfig()
547 SingleInstance
= false;
555 // Queue::Queue - Constructor /*{{{*/
556 // ---------------------------------------------------------------------
558 pkgAcquire::Queue::Queue(string Name
,pkgAcquire
*Owner
) : Name(Name
),
568 // Queue::~Queue - Destructor /*{{{*/
569 // ---------------------------------------------------------------------
571 pkgAcquire::Queue::~Queue()
583 // Queue::Enqueue - Queue an item to the queue /*{{{*/
584 // ---------------------------------------------------------------------
586 bool pkgAcquire::Queue::Enqueue(ItemDesc
&Item
)
589 // move to the end of the queue and check for duplicates here
590 for (; *I
!= 0; I
= &(*I
)->Next
)
591 if (Item
.URI
== (*I
)->URI
)
593 Item
.Owner
->Status
= Item::StatDone
;
598 QItem
*Itm
= new QItem
;
603 Item
.Owner
->QueueCounter
++;
604 if (Items
->Next
== 0)
609 // Queue::Dequeue - Remove an item from the queue /*{{{*/
610 // ---------------------------------------------------------------------
611 /* We return true if we hit something */
612 bool pkgAcquire::Queue::Dequeue(Item
*Owner
)
614 if (Owner
->Status
== pkgAcquire::Item::StatFetching
)
615 return _error
->Error("Tried to dequeue a fetching object");
622 if ((*I
)->Owner
== Owner
)
626 Owner
->QueueCounter
--;
637 // Queue::Startup - Start the worker processes /*{{{*/
638 // ---------------------------------------------------------------------
639 /* It is possible for this to be called with a pre-existing set of
641 bool pkgAcquire::Queue::Startup()
646 pkgAcquire::MethodConfig
*Cnf
= Owner
->GetConfig(U
.Access
);
650 Workers
= new Worker(this,Cnf
,Owner
->Log
);
652 if (Workers
->Start() == false)
655 /* When pipelining we commit 10 items. This needs to change when we
656 added other source retry to have cycle maintain a pipeline depth
658 if (Cnf
->Pipeline
== true)
659 MaxPipeDepth
= _config
->FindI("Acquire::Max-Pipeline-Depth",10);
667 // Queue::Shutdown - Shutdown the worker processes /*{{{*/
668 // ---------------------------------------------------------------------
669 /* If final is true then all workers are eliminated, otherwise only workers
670 that do not need cleanup are removed */
671 bool pkgAcquire::Queue::Shutdown(bool Final
)
673 // Delete all of the workers
674 pkgAcquire::Worker
**Cur
= &Workers
;
677 pkgAcquire::Worker
*Jnk
= *Cur
;
678 if (Final
== true || Jnk
->GetConf()->NeedsCleanup
== false)
680 *Cur
= Jnk
->NextQueue
;
685 Cur
= &(*Cur
)->NextQueue
;
691 // Queue::FindItem - Find a URI in the item list /*{{{*/
692 // ---------------------------------------------------------------------
694 pkgAcquire::Queue::QItem
*pkgAcquire::Queue::FindItem(string URI
,pkgAcquire::Worker
*Owner
)
696 for (QItem
*I
= Items
; I
!= 0; I
= I
->Next
)
697 if (I
->URI
== URI
&& I
->Worker
== Owner
)
702 // Queue::ItemDone - Item has been completed /*{{{*/
703 // ---------------------------------------------------------------------
704 /* The worker signals this which causes the item to be removed from the
705 queue. If this is the last queue instance then it is removed from the
707 bool pkgAcquire::Queue::ItemDone(QItem
*Itm
)
710 if (Itm
->Owner
->Status
== pkgAcquire::Item::StatFetching
)
711 Itm
->Owner
->Status
= pkgAcquire::Item::StatDone
;
713 if (Itm
->Owner
->QueueCounter
<= 1)
714 Owner
->Dequeue(Itm
->Owner
);
724 // Queue::Cycle - Queue new items into the method /*{{{*/
725 // ---------------------------------------------------------------------
726 /* This locates a new idle item and sends it to the worker. If pipelining
727 is enabled then it keeps the pipe full. */
728 bool pkgAcquire::Queue::Cycle()
730 if (Items
== 0 || Workers
== 0)
734 return _error
->Error("Pipedepth failure");
736 // Look for a queable item
738 while (PipeDepth
< (signed)MaxPipeDepth
)
740 for (; I
!= 0; I
= I
->Next
)
741 if (I
->Owner
->Status
== pkgAcquire::Item::StatIdle
)
744 // Nothing to do, queue is idle.
749 I
->Owner
->Status
= pkgAcquire::Item::StatFetching
;
751 if (Workers
->QueueItem(I
) == false)
758 // Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
759 // ---------------------------------------------------------------------
760 /* This is called when an item in multiple queues is dequeued */
761 void pkgAcquire::Queue::Bump()
766 // AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/
767 // ---------------------------------------------------------------------
769 pkgAcquireStatus::pkgAcquireStatus() : Update(true), MorePulses(false)
774 // AcquireStatus::Pulse - Called periodically /*{{{*/
775 // ---------------------------------------------------------------------
776 /* This computes some internal state variables for the derived classes to
777 use. It generates the current downloaded bytes and total bytes to download
778 as well as the current CPS estimate. */
779 bool pkgAcquireStatus::Pulse(pkgAcquire
*Owner
)
786 // Compute the total number of bytes to fetch
787 unsigned int Unknown
= 0;
788 unsigned int Count
= 0;
789 for (pkgAcquire::ItemCIterator I
= Owner
->ItemsBegin(); I
!= Owner
->ItemsEnd();
793 if ((*I
)->Status
== pkgAcquire::Item::StatDone
)
796 // Totally ignore local items
797 if ((*I
)->Local
== true)
800 TotalBytes
+= (*I
)->FileSize
;
801 if ((*I
)->Complete
== true)
802 CurrentBytes
+= (*I
)->FileSize
;
803 if ((*I
)->FileSize
== 0 && (*I
)->Complete
== false)
807 // Compute the current completion
808 unsigned long long ResumeSize
= 0;
809 for (pkgAcquire::Worker
*I
= Owner
->WorkersBegin(); I
!= 0;
810 I
= Owner
->WorkerStep(I
))
811 if (I
->CurrentItem
!= 0 && I
->CurrentItem
->Owner
->Complete
== false)
813 CurrentBytes
+= I
->CurrentSize
;
814 ResumeSize
+= I
->ResumePoint
;
816 // Files with unknown size always have 100% completion
817 if (I
->CurrentItem
->Owner
->FileSize
== 0 &&
818 I
->CurrentItem
->Owner
->Complete
== false)
819 TotalBytes
+= I
->CurrentSize
;
822 // Normalize the figures and account for unknown size downloads
825 if (Unknown
== Count
)
826 TotalBytes
= Unknown
;
828 // Wha?! Is not supposed to happen.
829 if (CurrentBytes
> TotalBytes
)
830 CurrentBytes
= TotalBytes
;
833 struct timeval NewTime
;
834 gettimeofday(&NewTime
,0);
835 if ((NewTime
.tv_sec
- Time
.tv_sec
== 6 && NewTime
.tv_usec
> Time
.tv_usec
) ||
836 NewTime
.tv_sec
- Time
.tv_sec
> 6)
838 double Delta
= NewTime
.tv_sec
- Time
.tv_sec
+
839 (NewTime
.tv_usec
- Time
.tv_usec
)/1000000.0;
841 // Compute the CPS value
845 CurrentCPS
= ((CurrentBytes
- ResumeSize
) - LastBytes
)/Delta
;
846 LastBytes
= CurrentBytes
- ResumeSize
;
847 ElapsedTime
= (unsigned long long)Delta
;
851 int fd
= _config
->FindI("APT::Status-Fd",-1);
854 ostringstream status
;
857 long i
= CurrentItems
< TotalItems
? CurrentItems
+ 1 : CurrentItems
;
858 unsigned long long ETA
= 0;
860 ETA
= (TotalBytes
- CurrentBytes
) / CurrentCPS
;
862 // only show the ETA if it makes sense
863 if (ETA
> 0 && ETA
< 172800 /* two days */ )
864 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li (%s remaining)"), i
, TotalItems
, TimeToStr(ETA
).c_str());
866 snprintf(msg
,sizeof(msg
), _("Retrieving file %li of %li"), i
, TotalItems
);
870 // build the status str
871 status
<< "dlstatus:" << i
872 << ":" << (CurrentBytes
/float(TotalBytes
)*100.0)
875 write(fd
, status
.str().c_str(), status
.str().size());
881 // AcquireStatus::Start - Called when the download is started /*{{{*/
882 // ---------------------------------------------------------------------
883 /* We just reset the counters */
884 void pkgAcquireStatus::Start()
886 gettimeofday(&Time
,0);
887 gettimeofday(&StartTime
,0);
898 // AcquireStatus::Stop - Finished downloading /*{{{*/
899 // ---------------------------------------------------------------------
900 /* This accurately computes the elapsed time and the total overall CPS. */
901 void pkgAcquireStatus::Stop()
903 // Compute the CPS and elapsed time
904 struct timeval NewTime
;
905 gettimeofday(&NewTime
,0);
907 double Delta
= NewTime
.tv_sec
- StartTime
.tv_sec
+
908 (NewTime
.tv_usec
- StartTime
.tv_usec
)/1000000.0;
910 // Compute the CPS value
914 CurrentCPS
= FetchedBytes
/Delta
;
915 LastBytes
= CurrentBytes
;
916 ElapsedTime
= (unsigned long long)Delta
;
919 // AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/
920 // ---------------------------------------------------------------------
921 /* This is used to get accurate final transfer rate reporting. */
922 void pkgAcquireStatus::Fetched(unsigned long long Size
,unsigned long long Resume
)
924 FetchedBytes
+= Size
- Resume
;