]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire.cc
Sync
[apt.git] / apt-pkg / acquire.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
93bf083d 3// $Id: acquire.cc,v 1.6 1998/10/30 07:53:37 jgg Exp $
0118833a
AL
4/* ######################################################################
5
6 Acquire - File Acquiration
7
0a8a80e5
AL
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
0118833a
AL
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>
0a8a80e5
AL
22#include <apt-pkg/configuration.h>
23#include <apt-pkg/error.h>
3b5421b4 24#include <strutl.h>
0118833a
AL
25 /*}}}*/
26
27// Acquire::pkgAcquire - Constructor /*{{{*/
28// ---------------------------------------------------------------------
93bf083d 29/* We grab some runtime state from the configuration space */
0118833a
AL
30pkgAcquire::pkgAcquire()
31{
32 Queues = 0;
33 Configs = 0;
0a8a80e5
AL
34 Workers = 0;
35 ToFetch = 0;
8b89e57f 36 Running = false;
0a8a80e5
AL
37
38 string Mode = _config->Find("Acquire::Queue-Mode","host");
39 if (strcasecmp(Mode.c_str(),"host") == 0)
40 QueueMode = QueueHost;
41 if (strcasecmp(Mode.c_str(),"access") == 0)
42 QueueMode = QueueAccess;
43
44 Debug = _config->FindB("Debug::pkgAcquire",false);
0118833a
AL
45}
46 /*}}}*/
47// Acquire::~pkgAcquire - Destructor /*{{{*/
48// ---------------------------------------------------------------------
93bf083d 49/* Free our memory, clean up the queues (destroy the workers) */
0118833a
AL
50pkgAcquire::~pkgAcquire()
51{
52 while (Items.size() != 0)
53 delete Items[0];
3b5421b4
AL
54
55 while (Configs != 0)
56 {
57 MethodConfig *Jnk = Configs;
58 Configs = Configs->Next;
59 delete Jnk;
60 }
0a8a80e5
AL
61
62 while (Queues != 0)
63 {
64 Queue *Jnk = Queues;
65 Queues = Queues->Next;
66 delete Jnk;
67 }
0118833a
AL
68}
69 /*}}}*/
70// Acquire::Add - Add a new item /*{{{*/
71// ---------------------------------------------------------------------
93bf083d
AL
72/* This puts an item on the acquire list. This list is mainly for tracking
73 item status */
0118833a
AL
74void pkgAcquire::Add(Item *Itm)
75{
76 Items.push_back(Itm);
77}
78 /*}}}*/
79// Acquire::Remove - Remove a item /*{{{*/
80// ---------------------------------------------------------------------
93bf083d 81/* Remove an item from the acquire list. This is usually not used.. */
0118833a
AL
82void pkgAcquire::Remove(Item *Itm)
83{
84 for (vector<Item *>::iterator I = Items.begin(); I < Items.end(); I++)
85 {
86 if (*I == Itm)
87 Items.erase(I);
88 }
89}
90 /*}}}*/
0a8a80e5
AL
91// Acquire::Add - Add a worker /*{{{*/
92// ---------------------------------------------------------------------
93bf083d
AL
93/* A list of workers is kept so that the select loop can direct their FD
94 usage. */
0a8a80e5
AL
95void pkgAcquire::Add(Worker *Work)
96{
97 Work->NextAcquire = Workers;
98 Workers = Work;
99}
100 /*}}}*/
101// Acquire::Remove - Remove a worker /*{{{*/
102// ---------------------------------------------------------------------
93bf083d
AL
103/* A worker has died. This can not be done while the select loop is running
104 as it would require that RunFds could handling a changing list state and
105 it cant.. */
0a8a80e5
AL
106void pkgAcquire::Remove(Worker *Work)
107{
93bf083d
AL
108 if (Running == true)
109 abort();
110
0a8a80e5
AL
111 Worker **I = &Workers;
112 for (; *I != 0;)
113 {
114 if (*I == Work)
115 *I = (*I)->NextAcquire;
116 else
117 I = &(*I)->NextAcquire;
118 }
119}
120 /*}}}*/
0118833a
AL
121// Acquire::Enqueue - Queue an URI for fetching /*{{{*/
122// ---------------------------------------------------------------------
93bf083d
AL
123/* This is the entry point for an item. An item calls this function when
124 it is construction which creates a queue (based on the current queue
125 mode) and puts the item in that queue. If the system is running then
126 the queue might be started. */
0a8a80e5 127void pkgAcquire::Enqueue(Item *Itm,string URI,string Description)
0118833a 128{
0a8a80e5
AL
129 // Determine which queue to put the item in
130 string Name = QueueName(URI);
131 if (Name.empty() == true)
132 return;
133
134 // Find the queue structure
135 Queue *I = Queues;
136 for (; I != 0 && I->Name != Name; I = I->Next);
137 if (I == 0)
138 {
139 I = new Queue(Name,this);
140 I->Next = Queues;
141 Queues = I;
93bf083d
AL
142
143 if (Running == true)
144 I->Startup();
0a8a80e5
AL
145 }
146
147 // Queue it into the named queue
148 I->Enqueue(Itm,URI,Description);
149 ToFetch++;
93bf083d 150
0a8a80e5
AL
151 // Some trace stuff
152 if (Debug == true)
153 {
154 clog << "Fetching " << URI << endl;
155 clog << " to " << Itm->DestFile << endl;
156 clog << " Queue is: " << QueueName(URI) << endl;
157 }
3b5421b4
AL
158}
159 /*}}}*/
0a8a80e5 160// Acquire::Dequeue - Remove an item from all queues /*{{{*/
3b5421b4 161// ---------------------------------------------------------------------
93bf083d
AL
162/* This is called when an item is finished being fetched. It removes it
163 from all the queues */
0a8a80e5
AL
164void pkgAcquire::Dequeue(Item *Itm)
165{
166 Queue *I = Queues;
167 for (; I != 0; I = I->Next)
168 I->Dequeue(Itm);
93bf083d
AL
169
170 if (Debug == true)
171 clog << "Dequeuing " << Itm->DestFile << endl;
0a8a80e5
AL
172 ToFetch--;
173}
174 /*}}}*/
175// Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
176// ---------------------------------------------------------------------
177/* The string returned depends on the configuration settings and the
178 method parameters. Given something like http://foo.org/bar it can
179 return http://foo.org or http */
93bf083d 180string pkgAcquire::QueueName(string Uri)
3b5421b4 181{
93bf083d
AL
182 URI U(Uri);
183
184 const MethodConfig *Config = GetConfig(U.Access);
0a8a80e5
AL
185 if (Config == 0)
186 return string();
187
188 /* Single-Instance methods get exactly one queue per URI. This is
189 also used for the Access queue method */
190 if (Config->SingleInstance == true || QueueMode == QueueAccess)
93bf083d
AL
191 return U.Access;
192
193 return U.Access + ':' + U.Host;
0118833a
AL
194}
195 /*}}}*/
3b5421b4
AL
196// Acquire::GetConfig - Fetch the configuration information /*{{{*/
197// ---------------------------------------------------------------------
198/* This locates the configuration structure for an access method. If
199 a config structure cannot be found a Worker will be created to
200 retrieve it */
0a8a80e5 201pkgAcquire::MethodConfig *pkgAcquire::GetConfig(string Access)
3b5421b4
AL
202{
203 // Search for an existing config
204 MethodConfig *Conf;
205 for (Conf = Configs; Conf != 0; Conf = Conf->Next)
206 if (Conf->Access == Access)
207 return Conf;
208
209 // Create the new config class
210 Conf = new MethodConfig;
211 Conf->Access = Access;
212 Conf->Next = Configs;
213 Configs = Conf;
0118833a 214
3b5421b4
AL
215 // Create the worker to fetch the configuration
216 Worker Work(Conf);
217 if (Work.Start() == false)
218 return 0;
219
220 return Conf;
221}
222 /*}}}*/
0a8a80e5
AL
223// Acquire::SetFds - Deal with readable FDs /*{{{*/
224// ---------------------------------------------------------------------
225/* Collect FDs that have activity monitors into the fd sets */
226void pkgAcquire::SetFds(int &Fd,fd_set *RSet,fd_set *WSet)
227{
228 for (Worker *I = Workers; I != 0; I = I->NextAcquire)
229 {
230 if (I->InReady == true && I->InFd >= 0)
231 {
232 if (Fd < I->InFd)
233 Fd = I->InFd;
234 FD_SET(I->InFd,RSet);
235 }
236 if (I->OutReady == true && I->OutFd >= 0)
237 {
238 if (Fd < I->OutFd)
239 Fd = I->OutFd;
240 FD_SET(I->OutFd,WSet);
241 }
242 }
243}
244 /*}}}*/
245// Acquire::RunFds - Deal with active FDs /*{{{*/
246// ---------------------------------------------------------------------
93bf083d
AL
247/* Dispatch active FDs over to the proper workers. It is very important
248 that a worker never be erased while this is running! The queue class
249 should never erase a worker except during shutdown processing. */
0a8a80e5
AL
250void pkgAcquire::RunFds(fd_set *RSet,fd_set *WSet)
251{
252 for (Worker *I = Workers; I != 0; I = I->NextAcquire)
253 {
254 if (I->InFd >= 0 && FD_ISSET(I->InFd,RSet) != 0)
255 I->InFdReady();
256 if (I->OutFd >= 0 && FD_ISSET(I->OutFd,WSet) != 0)
257 I->OutFdReady();
258 }
259}
260 /*}}}*/
261// Acquire::Run - Run the fetch sequence /*{{{*/
262// ---------------------------------------------------------------------
263/* This runs the queues. It manages a select loop for all of the
264 Worker tasks. The workers interact with the queues and items to
265 manage the actual fetch. */
266bool pkgAcquire::Run()
267{
8b89e57f
AL
268 Running = true;
269
0a8a80e5
AL
270 for (Queue *I = Queues; I != 0; I = I->Next)
271 I->Startup();
272
273 // Run till all things have been acquired
274 while (ToFetch > 0)
275 {
276 fd_set RFds;
277 fd_set WFds;
278 int Highest = 0;
279 FD_ZERO(&RFds);
280 FD_ZERO(&WFds);
281 SetFds(Highest,&RFds,&WFds);
282
283 if (select(Highest+1,&RFds,&WFds,0,0) <= 0)
8b89e57f
AL
284 {
285 Running = false;
0a8a80e5 286 return _error->Errno("select","Select has failed");
8b89e57f 287 }
93bf083d 288
0a8a80e5 289 RunFds(&RFds,&WFds);
93bf083d
AL
290 if (_error->PendingError() == true)
291 break;
0a8a80e5
AL
292 }
293
294 for (Queue *I = Queues; I != 0; I = I->Next)
295 I->Shutdown();
296
8b89e57f 297 Running = false;
93bf083d
AL
298 return _error->PendingError();
299}
300 /*}}}*/
301// pkgAcquire::Bump - Called when an item is dequeued /*{{{*/
302// ---------------------------------------------------------------------
303/* This routine bumps idle queues in hopes that they will be able to fetch
304 the dequeued item */
305void pkgAcquire::Bump()
306{
307
0a8a80e5
AL
308}
309 /*}}}*/
3b5421b4
AL
310
311// Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
312// ---------------------------------------------------------------------
313/* */
314pkgAcquire::MethodConfig::MethodConfig()
315{
316 SingleInstance = false;
317 PreScan = false;
0a8a80e5
AL
318 Pipeline = false;
319 SendConfig = false;
320 Next = 0;
321}
322 /*}}}*/
323
324// Queue::Queue - Constructor /*{{{*/
325// ---------------------------------------------------------------------
326/* */
327pkgAcquire::Queue::Queue(string Name,pkgAcquire *Owner) : Name(Name),
328 Owner(Owner)
329{
330 Items = 0;
331 Next = 0;
332 Workers = 0;
333}
334 /*}}}*/
335// Queue::~Queue - Destructor /*{{{*/
336// ---------------------------------------------------------------------
337/* */
338pkgAcquire::Queue::~Queue()
339{
340 Shutdown();
341
342 while (Items != 0)
343 {
344 QItem *Jnk = Items;
345 Items = Items->Next;
346 delete Jnk;
347 }
348}
349 /*}}}*/
350// Queue::Enqueue - Queue an item to the queue /*{{{*/
351// ---------------------------------------------------------------------
352/* */
353void pkgAcquire::Queue::Enqueue(Item *Owner,string URI,string Description)
354{
355 // Create a new item
356 QItem *I = new QItem;
357 I->Next = Items;
358 Items = I;
359
360 // Fill it in
361 Items->Owner = Owner;
362 Items->URI = URI;
363 Items->Description = Description;
364 Owner->QueueCounter++;
93bf083d
AL
365
366 if (Items->Next == 0)
367 Cycle();
0a8a80e5
AL
368}
369 /*}}}*/
c88edf1d 370// Queue::Dequeue - Remove an item from the queue /*{{{*/
0a8a80e5
AL
371// ---------------------------------------------------------------------
372/* */
373void pkgAcquire::Queue::Dequeue(Item *Owner)
374{
375 QItem **I = &Items;
376 for (; *I != 0;)
377 {
378 if ((*I)->Owner == Owner)
379 {
380 QItem *Jnk= *I;
381 *I = (*I)->Next;
382 Owner->QueueCounter--;
383 delete Jnk;
384 }
385 else
386 I = &(*I)->Next;
387 }
388}
389 /*}}}*/
390// Queue::Startup - Start the worker processes /*{{{*/
391// ---------------------------------------------------------------------
392/* */
393bool pkgAcquire::Queue::Startup()
394{
395 Shutdown();
396
93bf083d
AL
397 URI U(Name);
398 pkgAcquire::MethodConfig *Cnf = Owner->GetConfig(U.Access);
0a8a80e5
AL
399 if (Cnf == 0)
400 return false;
401
402 Workers = new Worker(this,Cnf);
403 Owner->Add(Workers);
404 if (Workers->Start() == false)
405 return false;
0a8a80e5 406
93bf083d 407 return Cycle();
0a8a80e5
AL
408}
409 /*}}}*/
410// Queue::Shutdown - Shutdown the worker processes /*{{{*/
411// ---------------------------------------------------------------------
412/* */
413bool pkgAcquire::Queue::Shutdown()
414{
415 // Delete all of the workers
416 while (Workers != 0)
417 {
418 pkgAcquire::Worker *Jnk = Workers;
419 Workers = Workers->NextQueue;
420 Owner->Remove(Jnk);
421 delete Jnk;
422 }
423
424 return true;
3b5421b4
AL
425}
426 /*}}}*/
c88edf1d
AL
427// Queue::Finditem - Find a URI in the item list /*{{{*/
428// ---------------------------------------------------------------------
429/* */
430pkgAcquire::Queue::QItem *pkgAcquire::Queue::FindItem(string URI,pkgAcquire::Worker *Owner)
431{
432 for (QItem *I = Items; I != 0; I = I->Next)
433 if (I->URI == URI && I->Worker == Owner)
434 return I;
435 return 0;
436}
437 /*}}}*/
438// Queue::ItemDone - Item has been completed /*{{{*/
439// ---------------------------------------------------------------------
440/* The worker signals this which causes the item to be removed from the
93bf083d
AL
441 queue. If this is the last queue instance then it is removed from the
442 main queue too.*/
c88edf1d
AL
443bool pkgAcquire::Queue::ItemDone(QItem *Itm)
444{
93bf083d
AL
445 if (Itm->Owner->QueueCounter <= 1)
446 Owner->Dequeue(Itm->Owner);
447 else
448 {
449 Dequeue(Itm->Owner);
450 Owner->Bump();
451 }
c88edf1d 452
93bf083d
AL
453 return Cycle();
454}
455 /*}}}*/
456// Queue::Cycle - Queue new items into the method /*{{{*/
457// ---------------------------------------------------------------------
458/* This locates a new idle item and sends it to the worker */
459bool pkgAcquire::Queue::Cycle()
460{
461 if (Items == 0 || Workers == 0)
c88edf1d
AL
462 return true;
463
93bf083d
AL
464 // Look for a queable item
465 QItem *I = Items;
466 for (; I != 0; I = I->Next)
467 if (I->Owner->Status == pkgAcquire::Item::StatIdle)
468 break;
469
470 // Nothing to do, queue is idle.
471 if (I == 0)
472 return true;
473
474 I->Worker = Workers;
475 I->Owner->Status = pkgAcquire::Item::StatFetching;
476 return Workers->QueueItem(I);
c88edf1d
AL
477}
478 /*}}}*/