New http method
[ntk/apt.git] / apt-pkg / acquire.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
be4401bf 3// $Id: acquire.cc,v 1.7 1998/11/01 05:27:34 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 292 }
be4401bf
AL
293
294 // Shut down the acquire bits
295 Running = false;
0a8a80e5
AL
296 for (Queue *I = Queues; I != 0; I = I->Next)
297 I->Shutdown();
298
93bf083d
AL
299 return _error->PendingError();
300}
301 /*}}}*/
be4401bf 302// Acquire::Bump - Called when an item is dequeued /*{{{*/
93bf083d
AL
303// ---------------------------------------------------------------------
304/* This routine bumps idle queues in hopes that they will be able to fetch
305 the dequeued item */
306void pkgAcquire::Bump()
307{
be4401bf
AL
308 for (Queue *I = Queues; I != 0; I = I->Next)
309 I->Bump();
0a8a80e5
AL
310}
311 /*}}}*/
3b5421b4
AL
312
313// Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
314// ---------------------------------------------------------------------
315/* */
316pkgAcquire::MethodConfig::MethodConfig()
317{
318 SingleInstance = false;
319 PreScan = false;
0a8a80e5
AL
320 Pipeline = false;
321 SendConfig = false;
322 Next = 0;
323}
324 /*}}}*/
325
326// Queue::Queue - Constructor /*{{{*/
327// ---------------------------------------------------------------------
328/* */
329pkgAcquire::Queue::Queue(string Name,pkgAcquire *Owner) : Name(Name),
330 Owner(Owner)
331{
332 Items = 0;
333 Next = 0;
334 Workers = 0;
335}
336 /*}}}*/
337// Queue::~Queue - Destructor /*{{{*/
338// ---------------------------------------------------------------------
339/* */
340pkgAcquire::Queue::~Queue()
341{
342 Shutdown();
343
344 while (Items != 0)
345 {
346 QItem *Jnk = Items;
347 Items = Items->Next;
348 delete Jnk;
349 }
350}
351 /*}}}*/
352// Queue::Enqueue - Queue an item to the queue /*{{{*/
353// ---------------------------------------------------------------------
354/* */
355void pkgAcquire::Queue::Enqueue(Item *Owner,string URI,string Description)
356{
357 // Create a new item
358 QItem *I = new QItem;
359 I->Next = Items;
360 Items = I;
361
362 // Fill it in
363 Items->Owner = Owner;
364 Items->URI = URI;
365 Items->Description = Description;
366 Owner->QueueCounter++;
93bf083d
AL
367
368 if (Items->Next == 0)
369 Cycle();
0a8a80e5
AL
370}
371 /*}}}*/
c88edf1d 372// Queue::Dequeue - Remove an item from the queue /*{{{*/
0a8a80e5
AL
373// ---------------------------------------------------------------------
374/* */
375void pkgAcquire::Queue::Dequeue(Item *Owner)
376{
377 QItem **I = &Items;
378 for (; *I != 0;)
379 {
380 if ((*I)->Owner == Owner)
381 {
382 QItem *Jnk= *I;
383 *I = (*I)->Next;
384 Owner->QueueCounter--;
385 delete Jnk;
386 }
387 else
388 I = &(*I)->Next;
389 }
390}
391 /*}}}*/
392// Queue::Startup - Start the worker processes /*{{{*/
393// ---------------------------------------------------------------------
394/* */
395bool pkgAcquire::Queue::Startup()
396{
397 Shutdown();
398
93bf083d
AL
399 URI U(Name);
400 pkgAcquire::MethodConfig *Cnf = Owner->GetConfig(U.Access);
0a8a80e5
AL
401 if (Cnf == 0)
402 return false;
403
404 Workers = new Worker(this,Cnf);
405 Owner->Add(Workers);
406 if (Workers->Start() == false)
407 return false;
0a8a80e5 408
93bf083d 409 return Cycle();
0a8a80e5
AL
410}
411 /*}}}*/
412// Queue::Shutdown - Shutdown the worker processes /*{{{*/
413// ---------------------------------------------------------------------
414/* */
415bool pkgAcquire::Queue::Shutdown()
416{
417 // Delete all of the workers
418 while (Workers != 0)
419 {
420 pkgAcquire::Worker *Jnk = Workers;
421 Workers = Workers->NextQueue;
422 Owner->Remove(Jnk);
423 delete Jnk;
424 }
425
426 return true;
3b5421b4
AL
427}
428 /*}}}*/
c88edf1d
AL
429// Queue::Finditem - Find a URI in the item list /*{{{*/
430// ---------------------------------------------------------------------
431/* */
432pkgAcquire::Queue::QItem *pkgAcquire::Queue::FindItem(string URI,pkgAcquire::Worker *Owner)
433{
434 for (QItem *I = Items; I != 0; I = I->Next)
435 if (I->URI == URI && I->Worker == Owner)
436 return I;
437 return 0;
438}
439 /*}}}*/
440// Queue::ItemDone - Item has been completed /*{{{*/
441// ---------------------------------------------------------------------
442/* The worker signals this which causes the item to be removed from the
93bf083d
AL
443 queue. If this is the last queue instance then it is removed from the
444 main queue too.*/
c88edf1d
AL
445bool pkgAcquire::Queue::ItemDone(QItem *Itm)
446{
93bf083d
AL
447 if (Itm->Owner->QueueCounter <= 1)
448 Owner->Dequeue(Itm->Owner);
449 else
450 {
451 Dequeue(Itm->Owner);
452 Owner->Bump();
453 }
c88edf1d 454
93bf083d
AL
455 return Cycle();
456}
457 /*}}}*/
458// Queue::Cycle - Queue new items into the method /*{{{*/
459// ---------------------------------------------------------------------
460/* This locates a new idle item and sends it to the worker */
461bool pkgAcquire::Queue::Cycle()
462{
463 if (Items == 0 || Workers == 0)
c88edf1d
AL
464 return true;
465
93bf083d
AL
466 // Look for a queable item
467 QItem *I = Items;
468 for (; I != 0; I = I->Next)
469 if (I->Owner->Status == pkgAcquire::Item::StatIdle)
470 break;
471
472 // Nothing to do, queue is idle.
473 if (I == 0)
474 return true;
475
476 I->Worker = Workers;
477 I->Owner->Status = pkgAcquire::Item::StatFetching;
478 return Workers->QueueItem(I);
c88edf1d
AL
479}
480 /*}}}*/
be4401bf
AL
481// Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
482// ---------------------------------------------------------------------
483/* */
484void pkgAcquire::Queue::Bump()
485{
486}
487 /*}}}*/