]> git.ipfire.org Git - thirdparty/squid.git/blob - src/delay_pools.cc
merge changes from SQUID_2_3 branch
[thirdparty/squid.git] / src / delay_pools.cc
1
2 /*
3 * $Id: delay_pools.cc,v 1.12 1999/12/30 17:36:30 wessels Exp $
4 *
5 * DEBUG: section 77 Delay Pools
6 * AUTHOR: David Luyer <luyer@ucs.uwa.edu.au>
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "config.h"
37
38 #if DELAY_POOLS
39 #include "squid.h"
40
41 struct _class1DelayPool {
42 int aggregate;
43 };
44
45 struct _class2DelayPool {
46 int aggregate;
47 /* OK: -1 is terminator. individual[255] is always host 255. */
48 /* 255 entries + 1 terminator byte */
49 unsigned char individual_map[256];
50 unsigned char individual_255_used;
51 /* 256 entries */
52 int individual[256];
53 };
54
55 struct _class3DelayPool {
56 int aggregate;
57 /* OK: -1 is terminator. network[255] is always host 255. */
58 /* 255 entries + 1 terminator byte */
59 unsigned char network_map[256];
60 unsigned char network_255_used;
61 /* 256 entries */
62 int network[256];
63 /* 256 sets of (255 entries + 1 terminator byte) */
64 unsigned char individual_map[256][256];
65 /* Pack this into one bit per net */
66 unsigned char individual_255_used[32];
67 /* largest entry = (255<<8)+255 = 65535 */
68 int individual[65536];
69 };
70
71 typedef struct _class1DelayPool class1DelayPool;
72 typedef struct _class2DelayPool class2DelayPool;
73 typedef struct _class3DelayPool class3DelayPool;
74
75 union _delayPool {
76 class1DelayPool *class1;
77 class2DelayPool *class2;
78 class3DelayPool *class3;
79 };
80
81 typedef union _delayPool delayPool;
82
83 static delayPool *delay_data = NULL;
84 static fd_set delay_no_delay;
85 static time_t delay_pools_last_update = 0;
86 static hash_table *delay_id_ptr_hash = NULL;
87
88 static OBJH delayPoolStats;
89
90 static unsigned int
91 delayIdPtrHash(const void *key, unsigned int n)
92 {
93 /* Hashes actual POINTER VALUE.
94 * Assumes <= 256 hash buckets & even hash size.
95 * Assumes the most variation in pointers to inside
96 * medium size objects occurs in the 2nd and 3rd
97 * least significant bytes.
98 */
99 const char *ptr = (char *) &key;
100 #if SIZEOF_VOID_P == 4
101 return (ptr[1] ^ ptr[2]) & (n - 1);
102 #elif SIZEOF_VOID_P == 8
103 #if WORDS_BIGENDIAN
104 return (ptr[5] ^ ptr[6]) & (n - 1);
105 #else
106 return (ptr[1] ^ ptr[2]) & (n - 1);
107 #endif
108 #else
109 #error What kind of a sick architecture are you on anyway?
110 #endif
111 }
112
113 static int
114 delayIdPtrHashCmp(const void *a, const void *b)
115 {
116 /*
117 * Compare POINTER VALUE.
118 * Note, we can't subtract void pointers, but we don't need
119 * to anyway. All we need is a test for equality.
120 */
121 return a != b;
122 }
123
124 void
125 delayPoolsInit(void)
126 {
127 delay_pools_last_update = getCurrentTime();
128 FD_ZERO(&delay_no_delay);
129 cachemgrRegister("delay", "Delay Pool Levels", delayPoolStats, 0, 1);
130 }
131
132 void
133 delayInitDelayData(unsigned short pools)
134 {
135 if (!pools)
136 return;
137 delay_data = xcalloc(pools, sizeof(delayPool));
138 eventAdd("delayPoolsUpdate", delayPoolsUpdate, NULL, 1.0, 1);
139 delay_id_ptr_hash = hash_create(delayIdPtrHashCmp, 256, delayIdPtrHash);
140 }
141
142 static void
143 delayIdZero(void *hlink)
144 {
145 hash_link *h = hlink;
146 delay_id *id = (delay_id *) h->key;
147 *id = 0;
148 xfree(h);
149 }
150
151 void
152 delayFreeDelayData(void)
153 {
154 safe_free(delay_data);
155 if (!delay_id_ptr_hash)
156 return;
157 hashFreeItems(delay_id_ptr_hash, delayIdZero);
158 hashFreeMemory(delay_id_ptr_hash);
159 delay_id_ptr_hash = NULL;
160 }
161
162 void
163 delayRegisterDelayIdPtr(delay_id * loc)
164 {
165 hash_link *lnk;
166 if (!delay_id_ptr_hash)
167 return;
168 if (*loc == 0)
169 return;
170 lnk = xmalloc(sizeof(hash_link));
171 lnk->key = (char *) loc;
172 hash_join(delay_id_ptr_hash, lnk);
173 }
174
175 void
176 delayUnregisterDelayIdPtr(delay_id * loc)
177 {
178 hash_link *lnk;
179 if (!delay_id_ptr_hash)
180 return;
181 /*
182 * If we went through a reconfigure, then all the delay_id's
183 * got set to zero, and they were removed from our hash
184 * table.
185 */
186 if (*loc == 0)
187 return;
188 lnk = hash_lookup(delay_id_ptr_hash, loc);
189 assert(lnk);
190 hash_remove_link(delay_id_ptr_hash, lnk);
191 xxfree(lnk);
192 }
193
194 void
195 delayCreateDelayPool(unsigned short pool, u_char class)
196 {
197 switch (class) {
198 case 1:
199 delay_data[pool].class1 = xmalloc(sizeof(class1DelayPool));
200 break;
201 case 2:
202 delay_data[pool].class2 = xmalloc(sizeof(class2DelayPool));
203 break;
204 case 3:
205 delay_data[pool].class3 = xmalloc(sizeof(class3DelayPool));
206 break;
207 default:
208 assert(0);
209 }
210 }
211
212 void
213 delayInitDelayPool(unsigned short pool, u_char class, delaySpecSet * rates)
214 {
215 /* delaySetSpec may be pointer to partial structure so MUST pass by
216 * reference.
217 */
218 switch (class) {
219 case 1:
220 delay_data[pool].class1->aggregate = (rates->aggregate.max_bytes *
221 Config.Delay.initial) / 100;
222 break;
223 case 2:
224 delay_data[pool].class2->aggregate = (rates->aggregate.max_bytes *
225 Config.Delay.initial) / 100;
226 delay_data[pool].class2->individual_map[0] = 255;
227 delay_data[pool].class2->individual_255_used = 0;
228 break;
229 case 3:
230 delay_data[pool].class3->aggregate = (rates->aggregate.max_bytes *
231 Config.Delay.initial) / 100;
232 delay_data[pool].class3->network_map[0] = 255;
233 delay_data[pool].class3->network_255_used = 0;
234 memset(&delay_data[pool].class3->individual_255_used, '\0',
235 sizeof(delay_data[pool].class3->individual_255_used));
236 break;
237 default:
238 assert(0);
239 }
240 }
241
242 void
243 delayFreeDelayPool(unsigned short pool)
244 {
245 /* this is a union - and all free() cares about is the pointer location */
246 safe_free(delay_data[pool].class1);
247 }
248
249 void
250 delaySetNoDelay(int fd)
251 {
252 FD_SET(fd, &delay_no_delay);
253 }
254
255 void
256 delayClearNoDelay(int fd)
257 {
258 FD_CLR(fd, &delay_no_delay);
259 }
260
261 int
262 delayIsNoDelay(int fd)
263 {
264 return FD_ISSET(fd, &delay_no_delay);
265 }
266
267 static delay_id
268 delayId(unsigned short pool, unsigned short position)
269 {
270 return (pool << 16) | position;
271 }
272
273 delay_id
274 delayClient(request_t * r)
275 {
276 aclCheck_t ch;
277 int i;
278 int j;
279 unsigned int host;
280 unsigned short pool, position;
281 unsigned char class, net;
282
283 memset(&ch, '\0', sizeof(ch));
284 ch.src_addr = r->client_addr;
285 ch.my_addr = r->my_addr;
286 ch.my_port = r->my_port;
287 ch.request = r;
288 for (pool = 0; pool < Config.Delay.pools; pool++) {
289 if (aclCheckFast(Config.Delay.access[pool], &ch))
290 break;
291 }
292 if (pool == Config.Delay.pools)
293 return delayId(0, 0);
294 class = Config.Delay.class[pool];
295 if (class == 0)
296 return delayId(0, 0);
297 if (class == 1)
298 return delayId(pool + 1, 0);
299 if (class == 2) {
300 host = ntohl(ch.src_addr.s_addr) & 0xff;
301 if (host == 255) {
302 if (!delay_data[pool].class2->individual_255_used) {
303 delay_data[pool].class2->individual_255_used = 1;
304 delay_data[pool].class2->individual[255] =
305 (Config.Delay.rates[pool]->individual.max_bytes *
306 Config.Delay.initial) / 100;
307 }
308 return delayId(pool + 1, 255);
309 }
310 for (i = 0;; i++) {
311 if (delay_data[pool].class2->individual_map[i] == host)
312 break;
313 if (delay_data[pool].class2->individual_map[i] == 255) {
314 delay_data[pool].class2->individual_map[i] = host;
315 delay_data[pool].class2->individual_map[i + 1] = 255;
316 delay_data[pool].class2->individual[i] =
317 (Config.Delay.rates[pool]->individual.max_bytes *
318 Config.Delay.initial) / 100;
319 break;
320 }
321 }
322 return delayId(pool + 1, i);
323 }
324 /* class == 3 */
325 host = ntohl(ch.src_addr.s_addr) & 0xffff;
326 net = host >> 8;
327 host &= 0xff;
328 if (net == 255) {
329 i = 255;
330 if (!delay_data[pool].class3->network_255_used) {
331 delay_data[pool].class3->network_255_used = 1;
332 delay_data[pool].class3->network[255] =
333 (Config.Delay.rates[pool]->network.max_bytes *
334 Config.Delay.initial) / 100;
335 }
336 } else {
337 for (i = 0;; i++) {
338 if (delay_data[pool].class3->network_map[i] == net)
339 break;
340 if (delay_data[pool].class3->network_map[i] == 255) {
341 delay_data[pool].class3->network_map[i] = net;
342 delay_data[pool].class3->individual_map[i][0] = 255;
343 delay_data[pool].class3->network_map[i + 1] = 255;
344 delay_data[pool].class3->network[i] =
345 (Config.Delay.rates[pool]->network.max_bytes *
346 Config.Delay.initial) / 100;
347 break;
348 }
349 }
350 }
351 position = i << 8;
352 if (host == 255) {
353 position |= 255;
354 if (!(delay_data[pool].class3->individual_255_used[i / 8] & (1 << (i % 8)))) {
355 delay_data[pool].class3->individual_255_used[i / 8] |= (1 << (i % 8));
356 delay_data[pool].class3->individual[position] =
357 (Config.Delay.rates[pool]->individual.max_bytes *
358 Config.Delay.initial) / 100;
359 }
360 return delayId(pool + 1, position);
361 }
362 for (j = 0;; j++) {
363 if (delay_data[pool].class3->individual_map[i][j] == host) {
364 position |= j;
365 break;
366 }
367 if (delay_data[pool].class3->individual_map[i][j] == 255) {
368 delay_data[pool].class3->individual_map[i][j] = host;
369 delay_data[pool].class3->individual_map[i][j + 1] = 255;
370 delay_data[pool].class3->individual[position |= j] =
371 (Config.Delay.rates[pool]->individual.max_bytes *
372 Config.Delay.initial) / 100;
373 break;
374 }
375 }
376 return delayId(pool + 1, position);
377 }
378
379 static void
380 delayUpdateClass1(class1DelayPool * class1, delaySpecSet * rates, int incr)
381 {
382 /* delaySetSpec may be pointer to partial structure so MUST pass by
383 * reference.
384 */
385 if (rates->aggregate.restore_bps != -1 &&
386 (class1->aggregate += rates->aggregate.restore_bps * incr) >
387 rates->aggregate.max_bytes)
388 class1->aggregate = rates->aggregate.max_bytes;
389 }
390
391 static void
392 delayUpdateClass2(class2DelayPool * class2, delaySpecSet * rates, int incr)
393 {
394 int restore_bytes;
395 unsigned char i;
396 /* delaySetSpec may be pointer to partial structure so MUST pass by
397 * reference.
398 */
399 if (rates->aggregate.restore_bps != -1 &&
400 (class2->aggregate += rates->aggregate.restore_bps * incr) >
401 rates->aggregate.max_bytes)
402 class2->aggregate = rates->aggregate.max_bytes;
403 if ((restore_bytes = rates->individual.restore_bps) == -1)
404 return;
405 restore_bytes *= incr;
406 if (class2->individual_255_used)
407 i = 255;
408 else
409 i = 0;
410 for (;;) {
411 if (i != 255 && class2->individual_map[i] == 255)
412 return;
413 if (class2->individual[i] != rates->individual.max_bytes &&
414 (class2->individual[i] += restore_bytes) > rates->individual.max_bytes)
415 class2->individual[i] = rates->individual.max_bytes;
416 if (++i == 255)
417 return;
418 }
419 }
420
421 static void
422 delayUpdateClass3(class3DelayPool * class3, delaySpecSet * rates, int incr)
423 {
424 int individual_restore_bytes, network_restore_bytes;
425 int mpos;
426 unsigned char i, j;
427 /* delaySetSpec may be pointer to partial structure so MUST pass by
428 * reference.
429 */
430 if (rates->aggregate.restore_bps != -1 &&
431 (class3->aggregate += rates->aggregate.restore_bps * incr) >
432 rates->aggregate.max_bytes)
433 class3->aggregate = rates->aggregate.max_bytes;
434 /* the following line deliberately uses &, not &&, in an if statement
435 * to avoid conditional execution
436 */
437 if (((network_restore_bytes = rates->network.restore_bps) == -1) &
438 ((individual_restore_bytes = rates->individual.restore_bps) == -1))
439 return;
440 individual_restore_bytes *= incr;
441 network_restore_bytes *= incr;
442 if (class3->network_255_used)
443 i = 255;
444 else
445 i = 0;
446 for (;;) {
447 if (i != 255 && class3->network_map[i] == 255)
448 return;
449 if (individual_restore_bytes != -incr) {
450 mpos = i << 8;
451 if (class3->individual_255_used[i / 8] & (1 << (i % 8)))
452 j = 255;
453 else
454 j = 0;
455 for (;;) {
456 if (j != 255 && class3->individual_map[i][j] == 255)
457 break;
458 if (class3->individual[mpos] != rates->individual.max_bytes &&
459 (class3->individual[mpos] += individual_restore_bytes) >
460 rates->individual.max_bytes)
461 class3->individual[mpos] = rates->individual.max_bytes;
462 mpos++;
463 if (j == 255)
464 mpos -= 256;
465 if (++j == 255)
466 break;
467 }
468 }
469 if (network_restore_bytes != -incr &&
470 class3->network[i] != rates->network.max_bytes &&
471 (class3->network[i] += network_restore_bytes) >
472 rates->network.max_bytes)
473 class3->network[i] = rates->network.max_bytes;
474 if (++i == 255)
475 return;
476 }
477 }
478
479 void
480 delayPoolsUpdate(void *unused)
481 {
482 int incr = squid_curtime - delay_pools_last_update;
483 unsigned short i;
484 unsigned char class;
485 if (!Config.Delay.pools)
486 return;
487 eventAdd("delayPoolsUpdate", delayPoolsUpdate, NULL, 1.0, 1);
488 if (incr < 1)
489 return;
490 delay_pools_last_update = squid_curtime;
491 for (i = 0; i < Config.Delay.pools; i++) {
492 class = Config.Delay.class[i];
493 if (!class)
494 continue;
495 switch (class) {
496 case 1:
497 delayUpdateClass1(delay_data[i].class1, Config.Delay.rates[i], incr);
498 break;
499 case 2:
500 delayUpdateClass2(delay_data[i].class2, Config.Delay.rates[i], incr);
501 break;
502 case 3:
503 delayUpdateClass3(delay_data[i].class3, Config.Delay.rates[i], incr);
504 break;
505 default:
506 assert(0);
507 }
508 }
509 }
510
511 /*
512 * this returns the number of bytes the client is permitted. it does not take
513 * into account bytes already buffered - that is up to the caller.
514 */
515 int
516 delayBytesWanted(delay_id d, int min, int max)
517 {
518 unsigned short position = d & 0xFFFF;
519 unsigned short pool = (d >> 16) - 1;
520 unsigned char class = (pool == 0xFFFF) ? 0 : Config.Delay.class[pool];
521 int nbytes = max;
522
523 switch (class) {
524 case 0:
525 break;
526
527 case 1:
528 if (Config.Delay.rates[pool]->aggregate.restore_bps != -1)
529 nbytes = XMIN(nbytes, delay_data[pool].class1->aggregate);
530 break;
531
532 case 2:
533 if (Config.Delay.rates[pool]->aggregate.restore_bps != -1)
534 nbytes = XMIN(nbytes, delay_data[pool].class2->aggregate);
535 if (Config.Delay.rates[pool]->individual.restore_bps != -1)
536 nbytes = XMIN(nbytes, delay_data[pool].class2->individual[position]);
537 break;
538
539 case 3:
540 if (Config.Delay.rates[pool]->aggregate.restore_bps != -1)
541 nbytes = XMIN(nbytes, delay_data[pool].class3->aggregate);
542 if (Config.Delay.rates[pool]->individual.restore_bps != -1)
543 nbytes = XMIN(nbytes, delay_data[pool].class3->individual[position]);
544 if (Config.Delay.rates[pool]->network.restore_bps != -1)
545 nbytes = XMIN(nbytes, delay_data[pool].class3->network[position >> 8]);
546 break;
547
548 default:
549 fatalf("delayBytesWanted: Invalid class %d\n", class);
550 break;
551 }
552 nbytes = XMAX(min, nbytes);
553 return nbytes;
554 }
555
556 /*
557 * this records actual bytes recieved. always recorded, even if the
558 * class is disabled - it's more efficient to just do it than to do all
559 * the checks.
560 */
561 void
562 delayBytesIn(delay_id d, int qty)
563 {
564 unsigned short position = d & 0xFFFF;
565 unsigned short pool = (d >> 16) - 1;
566 unsigned char class;
567
568 if (pool == 0xFFFF)
569 return;
570 class = Config.Delay.class[pool];
571 switch (class) {
572 case 1:
573 delay_data[pool].class1->aggregate -= qty;
574 return;
575 case 2:
576 delay_data[pool].class2->aggregate -= qty;
577 delay_data[pool].class2->individual[position] -= qty;
578 return;
579 case 3:
580 delay_data[pool].class3->aggregate -= qty;
581 delay_data[pool].class3->network[position >> 8] -= qty;
582 delay_data[pool].class3->individual[position] -= qty;
583 return;
584 }
585 fatalf("delayBytesWanted: Invalid class %d\n", class);
586 assert(0);
587 }
588
589 int
590 delayMostBytesWanted(const MemObject * mem, int max)
591 {
592 int i = 0;
593 int found = 0;
594 store_client *sc;
595 for (sc = mem->clients; sc; sc = sc->next) {
596 if (sc->callback_data == NULL) /* open slot */
597 continue;
598 if (sc->type != STORE_MEM_CLIENT)
599 continue;
600 i = delayBytesWanted(sc->delay_id, i, max);
601 found = 1;
602 }
603 return found ? i : max;
604 }
605
606 delay_id
607 delayMostBytesAllowed(const MemObject * mem)
608 {
609 int j;
610 int jmax = -1;
611 store_client *sc;
612 delay_id d = 0;
613 for (sc = mem->clients; sc; sc = sc->next) {
614 if (sc->callback_data == NULL) /* open slot */
615 continue;
616 if (sc->type != STORE_MEM_CLIENT)
617 continue;
618 j = delayBytesWanted(sc->delay_id, 0, SQUID_TCP_SO_RCVBUF);
619 if (j > jmax) {
620 jmax = j;
621 d = sc->delay_id;
622 }
623 }
624 return d;
625 }
626
627 void
628 delaySetStoreClient(StoreEntry * e, void *data, delay_id delay_id)
629 {
630 store_client *sc = storeClientListSearch(e->mem_obj, data);
631 assert(sc != NULL);
632 sc->delay_id = delay_id;
633 delayRegisterDelayIdPtr(&sc->delay_id);
634 }
635
636 static void
637 delayPoolStatsAg(StoreEntry * sentry, delaySpecSet * rate, int ag)
638 {
639 /* note - always pass delaySpecSet's by reference as may be incomplete */
640 if (rate->aggregate.restore_bps == -1) {
641 storeAppendPrintf(sentry, "\tAggregate:\n\t\tDisabled.\n\n");
642 return;
643 }
644 storeAppendPrintf(sentry, "\tAggregate:\n");
645 storeAppendPrintf(sentry, "\t\tMax: %d\n", rate->aggregate.max_bytes);
646 storeAppendPrintf(sentry, "\t\tRestore: %d\n", rate->aggregate.restore_bps);
647 storeAppendPrintf(sentry, "\t\tCurrent: %d\n\n", ag);
648 }
649
650 static void
651 delayPoolStats1(StoreEntry * sentry, unsigned short pool)
652 {
653 /* must be a reference only - partially malloc()d struct */
654 delaySpecSet *rate = Config.Delay.rates[pool];
655
656 storeAppendPrintf(sentry, "Pool: %d\n\tClass: 1\n\n", pool + 1);
657 delayPoolStatsAg(sentry, rate, delay_data[pool].class1->aggregate);
658 }
659
660 static void
661 delayPoolStats2(StoreEntry * sentry, unsigned short pool)
662 {
663 /* must be a reference only - partially malloc()d struct */
664 delaySpecSet *rate = Config.Delay.rates[pool];
665 class2DelayPool *class2 = delay_data[pool].class2;
666 unsigned char shown = 0, i;
667
668 storeAppendPrintf(sentry, "Pool: %d\n\tClass: 2\n\n", pool + 1);
669 delayPoolStatsAg(sentry, rate, class2->aggregate);
670 if (rate->individual.restore_bps == -1) {
671 storeAppendPrintf(sentry, "\tIndividual:\n\t\tDisabled.\n\n");
672 return;
673 }
674 storeAppendPrintf(sentry, "\tIndividual:\n");
675 storeAppendPrintf(sentry, "\t\tMax: %d\n", rate->individual.max_bytes);
676 storeAppendPrintf(sentry, "\t\tRate: %d\n", rate->individual.restore_bps);
677 storeAppendPrintf(sentry, "\t\tCurrent: ");
678 for (i = 0;; i++) {
679 if (class2->individual_map[i] == 255)
680 break;
681 storeAppendPrintf(sentry, "%d:%d ", class2->individual_map[i],
682 class2->individual[i]);
683 shown = 1;
684 }
685 if (class2->individual_255_used) {
686 storeAppendPrintf(sentry, "%d:%d ", 255, class2->individual[255]);
687 shown = 1;
688 }
689 if (!shown)
690 storeAppendPrintf(sentry, "Not used yet.");
691 storeAppendPrintf(sentry, "\n\n");
692 }
693
694 static void
695 delayPoolStats3(StoreEntry * sentry, unsigned short pool)
696 {
697 /* fully malloc()d struct in this case only */
698 delaySpecSet *rate = Config.Delay.rates[pool];
699 class3DelayPool *class3 = delay_data[pool].class3;
700 unsigned char shown = 0, i, j;
701
702 storeAppendPrintf(sentry, "Pool: %d\n\tClass: 3\n\n", pool + 1);
703 delayPoolStatsAg(sentry, rate, class3->aggregate);
704 if (rate->network.restore_bps == -1) {
705 storeAppendPrintf(sentry, "\tNetwork:\n\t\tDisabled.");
706 } else {
707 storeAppendPrintf(sentry, "\tNetwork:\n");
708 storeAppendPrintf(sentry, "\t\tMax: %d\n", rate->network.max_bytes);
709 storeAppendPrintf(sentry, "\t\tRate: %d\n", rate->network.restore_bps);
710 storeAppendPrintf(sentry, "\t\tCurrent: ");
711 for (i = 0;; i++) {
712 if (class3->network_map[i] == 255)
713 break;
714 storeAppendPrintf(sentry, "%d:%d ", class3->network_map[i],
715 class3->network[i]);
716 shown = 1;
717 }
718 if (class3->network_255_used) {
719 storeAppendPrintf(sentry, "%d:%d ", 255, class3->network[255]);
720 shown = 1;
721 }
722 if (!shown)
723 storeAppendPrintf(sentry, "Not used yet.");
724 }
725 storeAppendPrintf(sentry, "\n\n");
726 shown = 0;
727 if (rate->individual.restore_bps == -1) {
728 storeAppendPrintf(sentry, "\tIndividual:\n\t\tDisabled.\n\n");
729 return;
730 }
731 storeAppendPrintf(sentry, "\tIndividual:\n");
732 storeAppendPrintf(sentry, "\t\tMax: %d\n", rate->individual.max_bytes);
733 storeAppendPrintf(sentry, "\t\tRate: %d\n", rate->individual.restore_bps);
734 for (i = 0;; i++) {
735 if (class3->network_map[i] == 255)
736 break;
737 storeAppendPrintf(sentry, "\t\tCurrent [Network %d]: ", class3->network_map[i]);
738 shown = 1;
739 for (j = 0;; j++) {
740 if (class3->individual_map[i][j] == 255)
741 break;
742 storeAppendPrintf(sentry, "%d:%d ", class3->individual_map[i][j],
743 class3->individual[(i << 8) | j]);
744 }
745 if (class3->individual_255_used[i / 8] & (1 << (i % 8))) {
746 storeAppendPrintf(sentry, "%d:%d ", 255, class3->individual[(i << 8) | 255]);
747 }
748 storeAppendPrintf(sentry, "\n");
749 }
750 if (class3->network_255_used) {
751 storeAppendPrintf(sentry, "\t\tCurrent [Network 255]: ");
752 shown = 1;
753 for (j = 0;; j++) {
754 if (class3->individual_map[255][j] == 255)
755 break;
756 storeAppendPrintf(sentry, "%d:%d ", class3->individual_map[255][j],
757 class3->individual[(255 << 8) | j]);
758 }
759 if (class3->individual_255_used[255 / 8] & (1 << (255 % 8))) {
760 storeAppendPrintf(sentry, "%d:%d ", 255, class3->individual[(255 << 8) | 255]);
761 }
762 storeAppendPrintf(sentry, "\n");
763 }
764 if (!shown)
765 storeAppendPrintf(sentry, "\t\tCurrent [All networks]: Not used yet.\n");
766 storeAppendPrintf(sentry, "\n");
767 }
768
769 static void
770 delayPoolStats(StoreEntry * sentry)
771 {
772 unsigned short i;
773
774 storeAppendPrintf(sentry, "Delay pools configured: %d\n\n", Config.Delay.pools);
775 for (i = 0; i < Config.Delay.pools; i++) {
776 switch (Config.Delay.class[i]) {
777 case 0:
778 storeAppendPrintf(sentry, "Pool: %d\n\tClass: 0\n\n", i + 1);
779 storeAppendPrintf(sentry, "\tMisconfigured pool.\n\n");
780 break;
781 case 1:
782 delayPoolStats1(sentry, i);
783 break;
784 case 2:
785 delayPoolStats2(sentry, i);
786 break;
787 case 3:
788 delayPoolStats3(sentry, i);
789 break;
790 default:
791 assert(0);
792 }
793 }
794 }
795
796 #endif