]> git.saurik.com Git - apt.git/blob - apt-pkg/acquire.cc
mips and cps changes
[apt.git] / apt-pkg / acquire.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: acquire.cc,v 1.39 1999/10/16 19:53:18 jgg Exp $
4 /* ######################################################################
5
6 Acquire - File Acquiration
7
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.
12
13 ##################################################################### */
14 /*}}}*/
15 // Include Files /*{{{*/
16 #ifdef __GNUG__
17 #pragma implementation "apt-pkg/acquire.h"
18 #endif
19 #include <apt-pkg/acquire.h>
20 #include <apt-pkg/acquire-item.h>
21 #include <apt-pkg/acquire-worker.h>
22 #include <apt-pkg/configuration.h>
23 #include <apt-pkg/error.h>
24 #include <apt-pkg/strutl.h>
25
26 #include <dirent.h>
27 #include <sys/time.h>
28 #include <errno.h>
29 /*}}}*/
30
31 // Acquire::pkgAcquire - Constructor /*{{{*/
32 // ---------------------------------------------------------------------
33 /* We grab some runtime state from the configuration space */
34 pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log)
35 {
36 Queues = 0;
37 Configs = 0;
38 Workers = 0;
39 ToFetch = 0;
40 Running = false;
41
42 string Mode = _config->Find("Acquire::Queue-Mode","host");
43 if (strcasecmp(Mode.c_str(),"host") == 0)
44 QueueMode = QueueHost;
45 if (strcasecmp(Mode.c_str(),"access") == 0)
46 QueueMode = QueueAccess;
47
48 Debug = _config->FindB("Debug::pkgAcquire",false);
49 }
50 /*}}}*/
51 // Acquire::~pkgAcquire - Destructor /*{{{*/
52 // ---------------------------------------------------------------------
53 /* Free our memory, clean up the queues (destroy the workers) */
54 pkgAcquire::~pkgAcquire()
55 {
56 while (Configs != 0)
57 {
58 MethodConfig *Jnk = Configs;
59 Configs = Configs->Next;
60 delete Jnk;
61 }
62
63 Shutdown();
64 }
65 /*}}}*/
66 // pkgAcquire::Shutdown - Clean out the acquire object /*{{{*/
67 // ---------------------------------------------------------------------
68 /* */
69 void pkgAcquire::Shutdown()
70 {
71 while (Items.size() != 0)
72 delete Items[0];
73
74 while (Queues != 0)
75 {
76 Queue *Jnk = Queues;
77 Queues = Queues->Next;
78 delete Jnk;
79 }
80 }
81 /*}}}*/
82 // Acquire::Add - Add a new item /*{{{*/
83 // ---------------------------------------------------------------------
84 /* This puts an item on the acquire list. This list is mainly for tracking
85 item status */
86 void pkgAcquire::Add(Item *Itm)
87 {
88 Items.push_back(Itm);
89 }
90 /*}}}*/
91 // Acquire::Remove - Remove a item /*{{{*/
92 // ---------------------------------------------------------------------
93 /* Remove an item from the acquire list. This is usually not used.. */
94 void pkgAcquire::Remove(Item *Itm)
95 {
96 for (vector<Item *>::iterator I = Items.begin(); I < Items.end(); I++)
97 {
98 if (*I == Itm)
99 Items.erase(I);
100 }
101 }
102 /*}}}*/
103 // Acquire::Add - Add a worker /*{{{*/
104 // ---------------------------------------------------------------------
105 /* A list of workers is kept so that the select loop can direct their FD
106 usage. */
107 void pkgAcquire::Add(Worker *Work)
108 {
109 Work->NextAcquire = Workers;
110 Workers = Work;
111 }
112 /*}}}*/
113 // Acquire::Remove - Remove a worker /*{{{*/
114 // ---------------------------------------------------------------------
115 /* A worker has died. This can not be done while the select loop is running
116 as it would require that RunFds could handling a changing list state and
117 it cant.. */
118 void pkgAcquire::Remove(Worker *Work)
119 {
120 if (Running == true)
121 abort();
122
123 Worker **I = &Workers;
124 for (; *I != 0;)
125 {
126 if (*I == Work)
127 *I = (*I)->NextAcquire;
128 else
129 I = &(*I)->NextAcquire;
130 }
131 }
132 /*}}}*/
133 // Acquire::Enqueue - Queue an URI for fetching /*{{{*/
134 // ---------------------------------------------------------------------
135 /* This is the entry point for an item. An item calls this function when
136 it is constructed which creates a queue (based on the current queue
137 mode) and puts the item in that queue. If the system is running then
138 the queue might be started. */
139 void pkgAcquire::Enqueue(ItemDesc &Item)
140 {
141 // Determine which queue to put the item in
142 const MethodConfig *Config;
143 string Name = QueueName(Item.URI,Config);
144 if (Name.empty() == true)
145 return;
146
147 // Find the queue structure
148 Queue *I = Queues;
149 for (; I != 0 && I->Name != Name; I = I->Next);
150 if (I == 0)
151 {
152 I = new Queue(Name,this);
153 I->Next = Queues;
154 Queues = I;
155
156 if (Running == true)
157 I->Startup();
158 }
159
160 // See if this is a local only URI
161 if (Config->LocalOnly == true && Item.Owner->Complete == false)
162 Item.Owner->Local = true;
163 Item.Owner->Status = Item::StatIdle;
164
165 // Queue it into the named queue
166 I->Enqueue(Item);
167 ToFetch++;
168
169 // Some trace stuff
170 if (Debug == true)
171 {
172 clog << "Fetching " << Item.URI << endl;
173 clog << " to " << Item.Owner->DestFile << endl;
174 clog << " Queue is: " << Name << endl;
175 }
176 }
177 /*}}}*/
178 // Acquire::Dequeue - Remove an item from all queues /*{{{*/
179 // ---------------------------------------------------------------------
180 /* This is called when an item is finished being fetched. It removes it
181 from all the queues */
182 void pkgAcquire::Dequeue(Item *Itm)
183 {
184 Queue *I = Queues;
185 bool Res = false;
186 for (; I != 0; I = I->Next)
187 Res |= I->Dequeue(Itm);
188
189 if (Debug == true)
190 clog << "Dequeuing " << Itm->DestFile << endl;
191 if (Res == true)
192 ToFetch--;
193 }
194 /*}}}*/
195 // Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
196 // ---------------------------------------------------------------------
197 /* The string returned depends on the configuration settings and the
198 method parameters. Given something like http://foo.org/bar it can
199 return http://foo.org or http */
200 string pkgAcquire::QueueName(string Uri,MethodConfig const *&Config)
201 {
202 URI U(Uri);
203
204 Config = GetConfig(U.Access);
205 if (Config == 0)
206 return string();
207
208 /* Single-Instance methods get exactly one queue per URI. This is
209 also used for the Access queue method */
210 if (Config->SingleInstance == true || QueueMode == QueueAccess)
211 return U.Access;
212
213 return U.Access + ':' + U.Host;
214 }
215 /*}}}*/
216 // Acquire::GetConfig - Fetch the configuration information /*{{{*/
217 // ---------------------------------------------------------------------
218 /* This locates the configuration structure for an access method. If
219 a config structure cannot be found a Worker will be created to
220 retrieve it */
221 pkgAcquire::MethodConfig *pkgAcquire::GetConfig(string Access)
222 {
223 // Search for an existing config
224 MethodConfig *Conf;
225 for (Conf = Configs; Conf != 0; Conf = Conf->Next)
226 if (Conf->Access == Access)
227 return Conf;
228
229 // Create the new config class
230 Conf = new MethodConfig;
231 Conf->Access = Access;
232 Conf->Next = Configs;
233 Configs = Conf;
234
235 // Create the worker to fetch the configuration
236 Worker Work(Conf);
237 if (Work.Start() == false)
238 return 0;
239
240 return Conf;
241 }
242 /*}}}*/
243 // Acquire::SetFds - Deal with readable FDs /*{{{*/
244 // ---------------------------------------------------------------------
245 /* Collect FDs that have activity monitors into the fd sets */
246 void pkgAcquire::SetFds(int &Fd,fd_set *RSet,fd_set *WSet)
247 {
248 for (Worker *I = Workers; I != 0; I = I->NextAcquire)
249 {
250 if (I->InReady == true && I->InFd >= 0)
251 {
252 if (Fd < I->InFd)
253 Fd = I->InFd;
254 FD_SET(I->InFd,RSet);
255 }
256 if (I->OutReady == true && I->OutFd >= 0)
257 {
258 if (Fd < I->OutFd)
259 Fd = I->OutFd;
260 FD_SET(I->OutFd,WSet);
261 }
262 }
263 }
264 /*}}}*/
265 // Acquire::RunFds - Deal with active FDs /*{{{*/
266 // ---------------------------------------------------------------------
267 /* Dispatch active FDs over to the proper workers. It is very important
268 that a worker never be erased while this is running! The queue class
269 should never erase a worker except during shutdown processing. */
270 void pkgAcquire::RunFds(fd_set *RSet,fd_set *WSet)
271 {
272 for (Worker *I = Workers; I != 0; I = I->NextAcquire)
273 {
274 if (I->InFd >= 0 && FD_ISSET(I->InFd,RSet) != 0)
275 I->InFdReady();
276 if (I->OutFd >= 0 && FD_ISSET(I->OutFd,WSet) != 0)
277 I->OutFdReady();
278 }
279 }
280 /*}}}*/
281 // Acquire::Run - Run the fetch sequence /*{{{*/
282 // ---------------------------------------------------------------------
283 /* This runs the queues. It manages a select loop for all of the
284 Worker tasks. The workers interact with the queues and items to
285 manage the actual fetch. */
286 pkgAcquire::RunResult pkgAcquire::Run()
287 {
288 Running = true;
289
290 for (Queue *I = Queues; I != 0; I = I->Next)
291 I->Startup();
292
293 if (Log != 0)
294 Log->Start();
295
296 bool WasCancelled = false;
297
298 // Run till all things have been acquired
299 struct timeval tv;
300 tv.tv_sec = 0;
301 tv.tv_usec = 500000;
302 while (ToFetch > 0)
303 {
304 fd_set RFds;
305 fd_set WFds;
306 int Highest = 0;
307 FD_ZERO(&RFds);
308 FD_ZERO(&WFds);
309 SetFds(Highest,&RFds,&WFds);
310
311 int Res;
312 do
313 {
314 Res = select(Highest+1,&RFds,&WFds,0,&tv);
315 }
316 while (Res < 0 && errno == EINTR);
317
318 if (Res < 0)
319 {
320 _error->Errno("select","Select has failed");
321 break;
322 }
323
324 RunFds(&RFds,&WFds);
325 if (_error->PendingError() == true)
326 break;
327
328 // Timeout, notify the log class
329 if (Res == 0 || (Log != 0 && Log->Update == true))
330 {
331 tv.tv_usec = 500000;
332 for (Worker *I = Workers; I != 0; I = I->NextAcquire)
333 I->Pulse();
334 if (Log != 0 && Log->Pulse(this) == false)
335 {
336 WasCancelled = true;
337 break;
338 }
339 }
340 }
341
342 if (Log != 0)
343 Log->Stop();
344
345 // Shut down the acquire bits
346 Running = false;
347 for (Queue *I = Queues; I != 0; I = I->Next)
348 I->Shutdown();
349
350 // Shut down the items
351 for (Item **I = Items.begin(); I != Items.end(); I++)
352 (*I)->Finished();
353
354 if (_error->PendingError())
355 return Failed;
356 if (WasCancelled)
357 return Cancelled;
358 return Continue;
359 }
360 /*}}}*/
361 // Acquire::Bump - Called when an item is dequeued /*{{{*/
362 // ---------------------------------------------------------------------
363 /* This routine bumps idle queues in hopes that they will be able to fetch
364 the dequeued item */
365 void pkgAcquire::Bump()
366 {
367 for (Queue *I = Queues; I != 0; I = I->Next)
368 I->Bump();
369 }
370 /*}}}*/
371 // Acquire::WorkerStep - Step to the next worker /*{{{*/
372 // ---------------------------------------------------------------------
373 /* Not inlined to advoid including acquire-worker.h */
374 pkgAcquire::Worker *pkgAcquire::WorkerStep(Worker *I)
375 {
376 return I->NextAcquire;
377 };
378 /*}}}*/
379 // Acquire::Clean - Cleans a directory /*{{{*/
380 // ---------------------------------------------------------------------
381 /* This is a bit simplistic, it looks at every file in the dir and sees
382 if it is part of the download set. */
383 bool pkgAcquire::Clean(string Dir)
384 {
385 DIR *D = opendir(Dir.c_str());
386 if (D == 0)
387 return _error->Errno("opendir","Unable to read %s",Dir.c_str());
388
389 string StartDir = SafeGetCWD();
390 if (chdir(Dir.c_str()) != 0)
391 {
392 closedir(D);
393 return _error->Errno("chdir","Unable to change to ",Dir.c_str());
394 }
395
396 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
397 {
398 // Skip some files..
399 if (strcmp(Dir->d_name,"lock") == 0 ||
400 strcmp(Dir->d_name,"partial") == 0 ||
401 strcmp(Dir->d_name,".") == 0 ||
402 strcmp(Dir->d_name,"..") == 0)
403 continue;
404
405 // Look in the get list
406 vector<Item *>::iterator I = Items.begin();
407 for (; I != Items.end(); I++)
408 if (flNotDir((*I)->DestFile) == Dir->d_name)
409 break;
410
411 // Nothing found, nuke it
412 if (I == Items.end())
413 unlink(Dir->d_name);
414 };
415
416 chdir(StartDir.c_str());
417 closedir(D);
418 return true;
419 }
420 /*}}}*/
421 // Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/
422 // ---------------------------------------------------------------------
423 /* This is the total number of bytes needed */
424 unsigned long pkgAcquire::TotalNeeded()
425 {
426 unsigned long Total = 0;
427 for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++)
428 Total += (*I)->FileSize;
429 return Total;
430 }
431 /*}}}*/
432 // Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/
433 // ---------------------------------------------------------------------
434 /* This is the number of bytes that is not local */
435 unsigned long pkgAcquire::FetchNeeded()
436 {
437 unsigned long Total = 0;
438 for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++)
439 if ((*I)->Local == false)
440 Total += (*I)->FileSize;
441 return Total;
442 }
443 /*}}}*/
444 // Acquire::PartialPresent - Number of partial bytes we already have /*{{{*/
445 // ---------------------------------------------------------------------
446 /* This is the number of bytes that is not local */
447 unsigned long pkgAcquire::PartialPresent()
448 {
449 unsigned long Total = 0;
450 for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++)
451 if ((*I)->Local == false)
452 Total += (*I)->PartialSize;
453 return Total;
454 }
455 /*}}}*/
456 // pkgAcquire::UriBegin - Start iterator for the uri list /*{{{*/
457 // ---------------------------------------------------------------------
458 /* */
459 pkgAcquire::UriIterator pkgAcquire::UriBegin()
460 {
461 return UriIterator(Queues);
462 }
463 /*}}}*/
464 // pkgAcquire::UriEnd - End iterator for the uri list /*{{{*/
465 // ---------------------------------------------------------------------
466 /* */
467 pkgAcquire::UriIterator pkgAcquire::UriEnd()
468 {
469 return UriIterator(0);
470 }
471 /*}}}*/
472
473 // Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
474 // ---------------------------------------------------------------------
475 /* */
476 pkgAcquire::MethodConfig::MethodConfig()
477 {
478 SingleInstance = false;
479 Pipeline = false;
480 SendConfig = false;
481 LocalOnly = false;
482 Next = 0;
483 }
484 /*}}}*/
485
486 // Queue::Queue - Constructor /*{{{*/
487 // ---------------------------------------------------------------------
488 /* */
489 pkgAcquire::Queue::Queue(string Name,pkgAcquire *Owner) : Name(Name),
490 Owner(Owner)
491 {
492 Items = 0;
493 Next = 0;
494 Workers = 0;
495 MaxPipeDepth = 1;
496 PipeDepth = 0;
497 }
498 /*}}}*/
499 // Queue::~Queue - Destructor /*{{{*/
500 // ---------------------------------------------------------------------
501 /* */
502 pkgAcquire::Queue::~Queue()
503 {
504 Shutdown();
505
506 while (Items != 0)
507 {
508 QItem *Jnk = Items;
509 Items = Items->Next;
510 delete Jnk;
511 }
512 }
513 /*}}}*/
514 // Queue::Enqueue - Queue an item to the queue /*{{{*/
515 // ---------------------------------------------------------------------
516 /* */
517 void pkgAcquire::Queue::Enqueue(ItemDesc &Item)
518 {
519 QItem **I = &Items;
520 for (; *I != 0; I = &(*I)->Next);
521
522 // Create a new item
523 QItem *Itm = new QItem;
524 *Itm = Item;
525 Itm->Next = 0;
526 *I = Itm;
527
528 Item.Owner->QueueCounter++;
529 if (Items->Next == 0)
530 Cycle();
531 }
532 /*}}}*/
533 // Queue::Dequeue - Remove an item from the queue /*{{{*/
534 // ---------------------------------------------------------------------
535 /* We return true if we hit something */
536 bool pkgAcquire::Queue::Dequeue(Item *Owner)
537 {
538 if (Owner->Status == pkgAcquire::Item::StatFetching)
539 return _error->Error("Tried to dequeue a fetching object");
540
541 bool Res = false;
542
543 QItem **I = &Items;
544 for (; *I != 0;)
545 {
546 if ((*I)->Owner == Owner)
547 {
548 QItem *Jnk= *I;
549 *I = (*I)->Next;
550 Owner->QueueCounter--;
551 delete Jnk;
552 Res = true;
553 }
554 else
555 I = &(*I)->Next;
556 }
557
558 return Res;
559 }
560 /*}}}*/
561 // Queue::Startup - Start the worker processes /*{{{*/
562 // ---------------------------------------------------------------------
563 /* */
564 bool pkgAcquire::Queue::Startup()
565 {
566 Shutdown();
567
568 URI U(Name);
569 pkgAcquire::MethodConfig *Cnf = Owner->GetConfig(U.Access);
570 if (Cnf == 0)
571 return false;
572
573 Workers = new Worker(this,Cnf,Owner->Log);
574 Owner->Add(Workers);
575 if (Workers->Start() == false)
576 return false;
577
578 /* When pipelining we commit 10 items. This needs to change when we
579 added other source retry to have cycle maintain a pipeline depth
580 on its own. */
581 if (Cnf->Pipeline == true)
582 MaxPipeDepth = 10;
583 else
584 MaxPipeDepth = 1;
585
586 return Cycle();
587 }
588 /*}}}*/
589 // Queue::Shutdown - Shutdown the worker processes /*{{{*/
590 // ---------------------------------------------------------------------
591 /* */
592 bool pkgAcquire::Queue::Shutdown()
593 {
594 // Delete all of the workers
595 while (Workers != 0)
596 {
597 pkgAcquire::Worker *Jnk = Workers;
598 Workers = Workers->NextQueue;
599 Owner->Remove(Jnk);
600 delete Jnk;
601 }
602
603 return true;
604 }
605 /*}}}*/
606 // Queue::FindItem - Find a URI in the item list /*{{{*/
607 // ---------------------------------------------------------------------
608 /* */
609 pkgAcquire::Queue::QItem *pkgAcquire::Queue::FindItem(string URI,pkgAcquire::Worker *Owner)
610 {
611 for (QItem *I = Items; I != 0; I = I->Next)
612 if (I->URI == URI && I->Worker == Owner)
613 return I;
614 return 0;
615 }
616 /*}}}*/
617 // Queue::ItemDone - Item has been completed /*{{{*/
618 // ---------------------------------------------------------------------
619 /* The worker signals this which causes the item to be removed from the
620 queue. If this is the last queue instance then it is removed from the
621 main queue too.*/
622 bool pkgAcquire::Queue::ItemDone(QItem *Itm)
623 {
624 PipeDepth--;
625 if (Itm->Owner->Status == pkgAcquire::Item::StatFetching)
626 Itm->Owner->Status = pkgAcquire::Item::StatDone;
627
628 if (Itm->Owner->QueueCounter <= 1)
629 Owner->Dequeue(Itm->Owner);
630 else
631 {
632 Dequeue(Itm->Owner);
633 Owner->Bump();
634 }
635
636 return Cycle();
637 }
638 /*}}}*/
639 // Queue::Cycle - Queue new items into the method /*{{{*/
640 // ---------------------------------------------------------------------
641 /* This locates a new idle item and sends it to the worker. If pipelining
642 is enabled then it keeps the pipe full. */
643 bool pkgAcquire::Queue::Cycle()
644 {
645 if (Items == 0 || Workers == 0)
646 return true;
647
648 if (PipeDepth < 0)
649 return _error->Error("Pipedepth failure");
650
651 // Look for a queable item
652 QItem *I = Items;
653 while (PipeDepth < (signed)MaxPipeDepth)
654 {
655 for (; I != 0; I = I->Next)
656 if (I->Owner->Status == pkgAcquire::Item::StatIdle)
657 break;
658
659 // Nothing to do, queue is idle.
660 if (I == 0)
661 return true;
662
663 I->Worker = Workers;
664 I->Owner->Status = pkgAcquire::Item::StatFetching;
665 PipeDepth++;
666 if (Workers->QueueItem(I) == false)
667 return false;
668 }
669
670 return true;
671 }
672 /*}}}*/
673 // Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
674 // ---------------------------------------------------------------------
675 /* This is called when an item in multiple queues is dequeued */
676 void pkgAcquire::Queue::Bump()
677 {
678 Cycle();
679 }
680 /*}}}*/
681
682 // AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/
683 // ---------------------------------------------------------------------
684 /* */
685 pkgAcquireStatus::pkgAcquireStatus()
686 {
687 Start();
688 }
689 /*}}}*/
690 // AcquireStatus::Pulse - Called periodically /*{{{*/
691 // ---------------------------------------------------------------------
692 /* This computes some internal state variables for the derived classes to
693 use. It generates the current downloaded bytes and total bytes to download
694 as well as the current CPS estimate. */
695 bool pkgAcquireStatus::Pulse(pkgAcquire *Owner)
696 {
697 TotalBytes = 0;
698 CurrentBytes = 0;
699 TotalItems = 0;
700 CurrentItems = 0;
701
702 // Compute the total number of bytes to fetch
703 unsigned int Unknown = 0;
704 unsigned int Count = 0;
705 for (pkgAcquire::Item **I = Owner->ItemsBegin(); I != Owner->ItemsEnd();
706 I++, Count++)
707 {
708 TotalItems++;
709 if ((*I)->Status == pkgAcquire::Item::StatDone)
710 CurrentItems++;
711
712 // Totally ignore local items
713 if ((*I)->Local == true)
714 continue;
715
716 TotalBytes += (*I)->FileSize;
717 if ((*I)->Complete == true)
718 CurrentBytes += (*I)->FileSize;
719 if ((*I)->FileSize == 0 && (*I)->Complete == false)
720 Unknown++;
721 }
722
723 // Compute the current completion
724 unsigned long ResumeSize = 0;
725 for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
726 I = Owner->WorkerStep(I))
727 if (I->CurrentItem != 0 && I->CurrentItem->Owner->Complete == false)
728 {
729 CurrentBytes += I->CurrentSize;
730 ResumeSize += I->ResumePoint;
731
732 // Files with unknown size always have 100% completion
733 if (I->CurrentItem->Owner->FileSize == 0 &&
734 I->CurrentItem->Owner->Complete == false)
735 TotalBytes += I->CurrentSize;
736 }
737
738 // Normalize the figures and account for unknown size downloads
739 if (TotalBytes <= 0)
740 TotalBytes = 1;
741 if (Unknown == Count)
742 TotalBytes = Unknown;
743
744 // Wha?! Is not supposed to happen.
745 if (CurrentBytes > TotalBytes)
746 CurrentBytes = TotalBytes;
747
748 // Compute the CPS
749 struct timeval NewTime;
750 gettimeofday(&NewTime,0);
751 if (NewTime.tv_sec - Time.tv_sec == 6 && NewTime.tv_usec > Time.tv_usec ||
752 NewTime.tv_sec - Time.tv_sec > 6)
753 {
754 double Delta = NewTime.tv_sec - Time.tv_sec +
755 (NewTime.tv_usec - Time.tv_usec)/1000000.0;
756
757 // Compute the CPS value
758 if (Delta < 0.01)
759 CurrentCPS = 0;
760 else
761 CurrentCPS = ((CurrentBytes - ResumeSize) - LastBytes)/Delta;
762 LastBytes = CurrentBytes - ResumeSize;
763 ElapsedTime = (unsigned long)Delta;
764 Time = NewTime;
765 }
766
767 return true;
768 }
769 /*}}}*/
770 // AcquireStatus::Start - Called when the download is started /*{{{*/
771 // ---------------------------------------------------------------------
772 /* We just reset the counters */
773 void pkgAcquireStatus::Start()
774 {
775 gettimeofday(&Time,0);
776 gettimeofday(&StartTime,0);
777 LastBytes = 0;
778 CurrentCPS = 0;
779 CurrentBytes = 0;
780 TotalBytes = 0;
781 FetchedBytes = 0;
782 ElapsedTime = 0;
783 TotalItems = 0;
784 CurrentItems = 0;
785 }
786 /*}}}*/
787 // AcquireStatus::Stop - Finished downloading /*{{{*/
788 // ---------------------------------------------------------------------
789 /* This accurately computes the elapsed time and the total overall CPS. */
790 void pkgAcquireStatus::Stop()
791 {
792 // Compute the CPS and elapsed time
793 struct timeval NewTime;
794 gettimeofday(&NewTime,0);
795
796 double Delta = NewTime.tv_sec - StartTime.tv_sec +
797 (NewTime.tv_usec - StartTime.tv_usec)/1000000.0;
798
799 // Compute the CPS value
800 if (Delta < 0.01)
801 CurrentCPS = 0;
802 else
803 CurrentCPS = FetchedBytes/Delta;
804 LastBytes = CurrentBytes;
805 ElapsedTime = (unsigned int)Delta;
806 }
807 /*}}}*/
808 // AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/
809 // ---------------------------------------------------------------------
810 /* This is used to get accurate final transfer rate reporting. */
811 void pkgAcquireStatus::Fetched(unsigned long Size,unsigned long Resume)
812 {
813 FetchedBytes += Size - Resume;
814 }
815 /*}}}*/