Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 58badfca4f
Fetching contributors…

Cannot retrieve contributors at this time

854 lines (798 sloc) 25.357 kb
/*
* $Id: delay_pools.c,v 1.36 2007/08/27 12:51:41 hno Exp $
*
* DEBUG: section 77 Delay Pools
* AUTHOR: David Luyer <david@luyer.net>
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
* ----------------------------------------------------------
*
* Squid is the result of efforts by numerous individuals from
* the Internet community; see the CONTRIBUTORS file for full
* details. Many organizations have provided support for Squid's
* development; see the SPONSORS file for full details. Squid is
* Copyrighted (C) 2001 by the Regents of the University of
* California; see the COPYRIGHT file for full details. Squid
* incorporates software developed and/or copyrighted by other
* sources; see the CREDITS file for full details.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
*/
#include "config.h"
#if DELAY_POOLS
#include "squid.h"
struct _class1DelayPool {
int class;
int aggregate;
};
#define IND_MAP_SZ 256
struct _class2DelayPool {
int class;
int aggregate;
/* OK: -1 is terminator. individual[255] is always host 255. */
/* 255 entries + 1 terminator byte */
unsigned char individual_map[IND_MAP_SZ];
unsigned char individual_255_used;
/* 256 entries */
int individual[IND_MAP_SZ];
};
#define NET_MAP_SZ 256
#define C3_IND_SZ (NET_MAP_SZ*IND_MAP_SZ)
struct _class3DelayPool {
int class;
int aggregate;
/* OK: -1 is terminator. network[255] is always host 255. */
/* 255 entries + 1 terminator byte */
unsigned char network_map[NET_MAP_SZ];
unsigned char network_255_used;
/* 256 entries */
int network[256];
/* 256 sets of (255 entries + 1 terminator byte) */
unsigned char individual_map[NET_MAP_SZ][IND_MAP_SZ];
/* Pack this into one bit per net */
unsigned char individual_255_used[32];
/* largest entry = (255<<8)+255 = 65535 */
int individual[C3_IND_SZ];
};
typedef struct _class1DelayPool class1DelayPool;
typedef struct _class2DelayPool class2DelayPool;
typedef struct _class3DelayPool class3DelayPool;
union _delayPool {
class1DelayPool *class1;
class2DelayPool *class2;
class3DelayPool *class3;
};
typedef union _delayPool delayPool;
static delayPool *delay_data = NULL;
static char *delay_no_delay;
static time_t delay_pools_last_update = 0;
static hash_table *delay_id_ptr_hash = NULL;
static long memory_used = 0;
static OBJH delayPoolStats;
static unsigned int
delayIdPtrHash(const void *key, unsigned int n)
{
/* Hashes actual POINTER VALUE.
* Assumes <= 256 hash buckets & even hash size.
* Assumes the most variation in pointers to inside
* medium size objects occurs in the 2nd and 3rd
* least significant bytes.
*/
const char *ptr = (char *) &key;
#if SIZEOF_VOID_P == 4
return (ptr[1] ^ ptr[2]) & (n - 1);
#elif SIZEOF_VOID_P == 8
#if WORDS_BIGENDIAN
return (ptr[5] ^ ptr[6]) & (n - 1);
#else
return (ptr[1] ^ ptr[2]) & (n - 1);
#endif
#else
#error What kind of a sick architecture are you on anyway?
#endif
}
static int
delayIdPtrHashCmp(const void *a, const void *b)
{
/*
* Compare POINTER VALUE.
* Note, we can't subtract void pointers, but we don't need
* to anyway. All we need is a test for equality.
*/
return a != b;
}
void
delayPoolsInit(void)
{
delay_pools_last_update = getCurrentTime();
delay_no_delay = xcalloc(1, Squid_MaxFD);
cachemgrRegister("delay", "Delay Pool Levels", delayPoolStats, 0, 1);
}
void
delayInitDelayData(unsigned short pools)
{
if (!pools)
return;
delay_data = xcalloc(pools, sizeof(*delay_data));
memory_used += pools * sizeof(*delay_data);
delay_id_ptr_hash = hash_create(delayIdPtrHashCmp, 256, delayIdPtrHash);
}
static void
delayIdZero(void *hlink)
{
hash_link *h = hlink;
delay_id *id = (delay_id *) h->key;
*id = 0;
xfree(h);
memory_used -= sizeof(*h);
}
void
delayFreeDelayData(unsigned short pools)
{
if (!delay_id_ptr_hash)
return;
safe_free(delay_data);
memory_used -= pools * sizeof(*delay_data);
hashFreeItems(delay_id_ptr_hash, delayIdZero);
hashFreeMemory(delay_id_ptr_hash);
delay_id_ptr_hash = NULL;
}
void
delayRegisterDelayIdPtr(delay_id * loc)
{
hash_link *lnk;
if (!delay_id_ptr_hash)
return;
if (*loc == 0)
return;
lnk = xmalloc(sizeof(hash_link));
memory_used += sizeof(hash_link);
lnk->key = (char *) loc;
hash_join(delay_id_ptr_hash, lnk);
}
void
delayUnregisterDelayIdPtr(delay_id * loc)
{
hash_link *lnk;
if (!delay_id_ptr_hash)
return;
/*
* If we went through a reconfigure, then all the delay_id's
* got set to zero, and they were removed from our hash
* table.
*/
if (*loc == 0)
return;
lnk = hash_lookup(delay_id_ptr_hash, loc);
assert(lnk);
hash_remove_link(delay_id_ptr_hash, lnk);
xxfree(lnk);
memory_used -= sizeof(*lnk);
}
void
delayCreateDelayPool(unsigned short pool, u_char class)
{
switch (class) {
case 1:
delay_data[pool].class1 = xmalloc(sizeof(class1DelayPool));
delay_data[pool].class1->class = 1;
memory_used += sizeof(class1DelayPool);
break;
case 2:
delay_data[pool].class2 = xmalloc(sizeof(class2DelayPool));
delay_data[pool].class1->class = 2;
memory_used += sizeof(class2DelayPool);
break;
case 3:
delay_data[pool].class3 = xmalloc(sizeof(class3DelayPool));
delay_data[pool].class1->class = 3;
memory_used += sizeof(class3DelayPool);
break;
default:
assert(0);
}
}
void
delayInitDelayPool(unsigned short pool, u_char class, delaySpecSet * rates)
{
/* delaySetSpec may be pointer to partial structure so MUST pass by
* reference.
*/
switch (class) {
case 1:
delay_data[pool].class1->aggregate = (int) (((double) rates->aggregate.max_bytes *
Config.Delay.initial) / 100);
break;
case 2:
delay_data[pool].class2->aggregate = (int) (((double) rates->aggregate.max_bytes *
Config.Delay.initial) / 100);
delay_data[pool].class2->individual_map[0] = 255;
delay_data[pool].class2->individual_255_used = 0;
break;
case 3:
delay_data[pool].class3->aggregate = (int) (((double) rates->aggregate.max_bytes *
Config.Delay.initial) / 100);
delay_data[pool].class3->network_map[0] = 255;
delay_data[pool].class3->network_255_used = 0;
memset(&delay_data[pool].class3->individual_255_used, '\0',
sizeof(delay_data[pool].class3->individual_255_used));
break;
default:
assert(0);
}
}
void
delayFreeDelayPool(unsigned short pool)
{
/* this is a union - and all free() cares about is the pointer location */
switch (delay_data[pool].class1->class) {
case 1:
memory_used -= sizeof(class1DelayPool);
break;
case 2:
memory_used -= sizeof(class2DelayPool);
break;
case 3:
memory_used -= sizeof(class3DelayPool);
break;
default:
debug(77, 1) ("delayFreeDelayPool: bad class %d\n",
delay_data[pool].class1->class);
}
safe_free(delay_data[pool].class1);
}
void
delaySetNoDelay(int fd)
{
delay_no_delay[fd] = 1;
}
void
delayClearNoDelay(int fd)
{
delay_no_delay[fd] = 0;
}
int
delayIsNoDelay(int fd)
{
return delay_no_delay[fd];
}
static delay_id
delayId(unsigned short pool, unsigned short position)
{
return (pool << 16) | position;
}
delay_id
delayClient(clientHttpRequest * http)
{
request_t *r;
aclCheck_t ch;
int i;
int j;
unsigned int host;
unsigned short pool, position;
unsigned char class, net;
assert(http);
r = http->request;
memset(&ch, '\0', sizeof(ch));
ch.conn = http->conn;
ch.request = r;
if (r->client_addr.s_addr == INADDR_BROADCAST) {
debug(77, 2) ("delayClient: WARNING: Called with 'allones' address, ignoring\n");
return delayId(0, 0);
}
for (pool = 0; pool < Config.Delay.pools; pool++) {
if (aclCheckFast(Config.Delay.access[pool], &ch))
break;
}
if (pool == Config.Delay.pools)
return delayId(0, 0);
class = Config.Delay.class[pool];
if (class == 0)
return delayId(0, 0);
if (class == 1)
return delayId(pool + 1, 0);
if (class == 2) {
host = ntohl(ch.src_addr.s_addr) & 0xff;
if (host == 255) {
if (!delay_data[pool].class2->individual_255_used) {
delay_data[pool].class2->individual_255_used = 1;
delay_data[pool].class2->individual[IND_MAP_SZ - 1] =
(int) (((double) Config.Delay.rates[pool]->individual.max_bytes *
Config.Delay.initial) / 100);
}
return delayId(pool + 1, 255);
}
for (i = 0; i < IND_MAP_SZ; i++) {
if (delay_data[pool].class2->individual_map[i] == host)
break;
if (delay_data[pool].class2->individual_map[i] == 255) {
delay_data[pool].class2->individual_map[i] = host;
assert(i < (IND_MAP_SZ - 1));
delay_data[pool].class2->individual_map[i + 1] = 255;
delay_data[pool].class2->individual[i] =
(int) (((double) Config.Delay.rates[pool]->individual.max_bytes *
Config.Delay.initial) / 100);
break;
}
}
return delayId(pool + 1, i);
}
/* class == 3 */
host = ntohl(ch.src_addr.s_addr) & 0xffff;
net = host >> 8;
host &= 0xff;
if (net == 255) {
i = 255;
if (!delay_data[pool].class3->network_255_used) {
delay_data[pool].class3->network_255_used = 1;
delay_data[pool].class3->network[255] =
(int) (((double) Config.Delay.rates[pool]->network.max_bytes *
Config.Delay.initial) / 100);
delay_data[pool].class3->individual_map[i][0] = 255;
}
} else {
for (i = 0; i < NET_MAP_SZ; i++) {
if (delay_data[pool].class3->network_map[i] == net)
break;
if (delay_data[pool].class3->network_map[i] == 255) {
delay_data[pool].class3->network_map[i] = net;
delay_data[pool].class3->individual_map[i][0] = 255;
assert(i < (NET_MAP_SZ - 1));
delay_data[pool].class3->network_map[i + 1] = 255;
delay_data[pool].class3->network[i] =
(int) (((double) Config.Delay.rates[pool]->network.max_bytes *
Config.Delay.initial) / 100);
break;
}
}
}
position = i << 8;
if (host == 255) {
position |= 255;
if (!(delay_data[pool].class3->individual_255_used[i / 8] & (1 << (i % 8)))) {
delay_data[pool].class3->individual_255_used[i / 8] |= (1 << (i % 8));
delay_data[pool].class3->individual[position] =
(int) (((double) Config.Delay.rates[pool]->individual.max_bytes *
Config.Delay.initial) / 100);
}
return delayId(pool + 1, position);
}
assert(i < NET_MAP_SZ);
for (j = 0; j < IND_MAP_SZ; j++) {
if (delay_data[pool].class3->individual_map[i][j] == host) {
position |= j;
break;
}
if (delay_data[pool].class3->individual_map[i][j] == 255) {
delay_data[pool].class3->individual_map[i][j] = host;
assert(j < (IND_MAP_SZ - 1));
delay_data[pool].class3->individual_map[i][j + 1] = 255;
position |= j;
delay_data[pool].class3->individual[position] =
(int) (((double) Config.Delay.rates[pool]->individual.max_bytes *
Config.Delay.initial) / 100);
break;
}
}
return delayId(pool + 1, position);
}
static void
delayUpdateClass1(class1DelayPool * class1, delaySpecSet * rates, int incr)
{
/* delaySetSpec may be pointer to partial structure so MUST pass by
* reference.
*/
if (rates->aggregate.restore_bps != -1 &&
(class1->aggregate += rates->aggregate.restore_bps * incr) >
rates->aggregate.max_bytes)
class1->aggregate = rates->aggregate.max_bytes;
}
static void
delayUpdateClass2(class2DelayPool * class2, delaySpecSet * rates, int incr)
{
int restore_bytes;
unsigned char i; /* depends on 255 + 1 = 0 */
/* delaySetSpec may be pointer to partial structure so MUST pass by
* reference.
*/
if (rates->aggregate.restore_bps != -1 &&
(class2->aggregate += rates->aggregate.restore_bps * incr) >
rates->aggregate.max_bytes)
class2->aggregate = rates->aggregate.max_bytes;
if ((restore_bytes = rates->individual.restore_bps) == -1)
return;
restore_bytes *= incr;
/* i < IND_MAP_SZ is enforced by data type (unsigned chars are all < 256).
* this loop starts at 0 or 255 and ends at 254 unless terminated earlier
* by finding the end of the map. note as above that 255 + 1 = 0.
*/
for (i = (class2->individual_255_used ? 255 : 0);; i++) {
if (i != 255 && class2->individual_map[i] == 255)
return;
if (class2->individual[i] != rates->individual.max_bytes &&
(class2->individual[i] += restore_bytes) > rates->individual.max_bytes)
class2->individual[i] = rates->individual.max_bytes;
if (i == 254)
return;
}
}
static void
delayUpdateClass3(class3DelayPool * class3, delaySpecSet * rates, int incr)
{
int individual_restore_bytes, network_restore_bytes;
int mpos;
unsigned char i, j; /* depends on 255 + 1 = 0 */
/* delaySetSpec may be pointer to partial structure so MUST pass by
* reference.
*/
if (rates->aggregate.restore_bps != -1 &&
(class3->aggregate += rates->aggregate.restore_bps * incr) >
rates->aggregate.max_bytes)
class3->aggregate = rates->aggregate.max_bytes;
/* the following line deliberately uses &, not &&, in an if statement
* to avoid conditional execution
*/
if (((network_restore_bytes = rates->network.restore_bps) == -1) &
((individual_restore_bytes = rates->individual.restore_bps) == -1))
return;
individual_restore_bytes *= incr;
network_restore_bytes *= incr;
/* i < NET_MAP_SZ is enforced by data type (unsigned chars are all < 256).
* this loop starts at 0 or 255 and ends at 254 unless terminated earlier
* by finding the end of the map. note as above that 255 + 1 = 0.
*/
for (i = (class3->network_255_used ? 255 : 0);; ++i) {
if (i != 255 && class3->network_map[i] == 255)
return;
if (individual_restore_bytes != -incr) {
mpos = i << 8;
/* this is not as simple as the outer loop as mpos doesn't wrap like
* i and j do. so the net 255 increment is done as a separate special
* case. the alternative would be overlapping a union of two chars on
* top of a 16-bit unsigned int, but that wouldn't really be worth the
* effort.
*/
for (j = 0;; ++j, ++mpos) {
if (class3->individual_map[i][j] == 255)
break;
assert(mpos < C3_IND_SZ);
if (class3->individual[mpos] != rates->individual.max_bytes &&
(class3->individual[mpos] += individual_restore_bytes) >
rates->individual.max_bytes)
class3->individual[mpos] = rates->individual.max_bytes;
if (j == 254)
break;
}
if (class3->individual_255_used[i / 8] & (1 << (i % 8))) {
mpos |= 255; /* this will set mpos to network 255 */
assert(mpos < C3_IND_SZ);
if (class3->individual[mpos] != rates->individual.max_bytes &&
(class3->individual[mpos] += individual_restore_bytes) >
rates->individual.max_bytes)
class3->individual[mpos] = rates->individual.max_bytes;
}
}
if (network_restore_bytes != -incr &&
class3->network[i] != rates->network.max_bytes &&
(class3->network[i] += network_restore_bytes) >
rates->network.max_bytes)
class3->network[i] = rates->network.max_bytes;
if (i == 254)
return;
}
}
void
delayPoolsUpdate(void *unused)
{
int incr = squid_curtime - delay_pools_last_update;
unsigned short i;
unsigned char class;
if (!Config.Delay.pools)
return;
if (incr < 1)
return;
delay_pools_last_update = squid_curtime;
for (i = 0; i < Config.Delay.pools; i++) {
class = Config.Delay.class[i];
if (!class)
continue;
switch (class) {
case 1:
delayUpdateClass1(delay_data[i].class1, Config.Delay.rates[i], incr);
break;
case 2:
delayUpdateClass2(delay_data[i].class2, Config.Delay.rates[i], incr);
break;
case 3:
delayUpdateClass3(delay_data[i].class3, Config.Delay.rates[i], incr);
break;
default:
assert(0);
}
}
}
/*
* this returns the number of bytes the client is permitted. it does not take
* into account bytes already buffered - that is up to the caller.
*/
int
delayBytesWanted(delay_id d, int min, int max)
{
unsigned short position = d & 0xFFFF;
unsigned short pool = (d >> 16) - 1;
unsigned char class = (pool == 0xFFFF) ? 0 : Config.Delay.class[pool];
int nbytes = max;
switch (class) {
case 0:
break;
case 1:
if (Config.Delay.rates[pool]->aggregate.restore_bps != -1)
nbytes = XMIN(nbytes, delay_data[pool].class1->aggregate);
break;
case 2:
if (Config.Delay.rates[pool]->aggregate.restore_bps != -1)
nbytes = XMIN(nbytes, delay_data[pool].class2->aggregate);
if (Config.Delay.rates[pool]->individual.restore_bps != -1)
nbytes = XMIN(nbytes, delay_data[pool].class2->individual[position]);
break;
case 3:
if (Config.Delay.rates[pool]->aggregate.restore_bps != -1)
nbytes = XMIN(nbytes, delay_data[pool].class3->aggregate);
if (Config.Delay.rates[pool]->individual.restore_bps != -1)
nbytes = XMIN(nbytes, delay_data[pool].class3->individual[position]);
if (Config.Delay.rates[pool]->network.restore_bps != -1)
nbytes = XMIN(nbytes, delay_data[pool].class3->network[position >> 8]);
break;
default:
fatalf("delayBytesWanted: Invalid class %d\n", class);
break;
}
nbytes = XMAX(min, nbytes);
return nbytes;
}
/*
* this records actual bytes received. always recorded, even if the
* class is disabled - it's more efficient to just do it than to do all
* the checks.
*/
void
delayBytesIn(delay_id d, int qty)
{
unsigned short position = d & 0xFFFF;
unsigned short pool = (d >> 16) - 1;
unsigned char class;
if (pool == 0xFFFF)
return;
class = Config.Delay.class[pool];
switch (class) {
case 1:
delay_data[pool].class1->aggregate -= qty;
return;
case 2:
delay_data[pool].class2->aggregate -= qty;
delay_data[pool].class2->individual[position] -= qty;
return;
case 3:
delay_data[pool].class3->aggregate -= qty;
delay_data[pool].class3->network[position >> 8] -= qty;
delay_data[pool].class3->individual[position] -= qty;
return;
}
fatalf("delayBytesWanted: Invalid class %d\n", class);
assert(0);
}
int
delayMostBytesWanted(const MemObject * mem, int max)
{
int i = 0;
int found = 0;
store_client *sc;
dlink_node *node;
for (node = mem->clients.head; node; node = node->next) {
sc = (store_client *) node->data;
i = delayBytesWanted(sc->delay_id, i, max);
found = 1;
}
return found ? i : max;
}
delay_id
delayMostBytesAllowed(const MemObject * mem, size_t * read_sz)
{
int j;
int jmax = -1;
store_client *sc;
dlink_node *node;
delay_id d = 0;
for (node = mem->clients.head; node; node = node->next) {
sc = (store_client *) node->data;
j = delayBytesWanted(sc->delay_id, 0, INT_MAX);
if (j > jmax) {
jmax = j;
d = sc->delay_id;
}
}
if (jmax >= 0 && jmax < (int) *read_sz) {
if (jmax == 0)
jmax = 1;
if (jmax > 1460)
jmax = 1460;
*read_sz = (size_t) jmax;
}
return d;
}
void
delaySetStoreClient(store_client * sc, delay_id delay_id)
{
assert(sc != NULL);
sc->delay_id = delay_id;
delayRegisterDelayIdPtr(&sc->delay_id);
}
static void
delayPoolStatsAg(StoreEntry * sentry, delaySpecSet * rate, int ag)
{
/* note - always pass delaySpecSet's by reference as may be incomplete */
if (rate->aggregate.restore_bps == -1) {
storeAppendPrintf(sentry, "\tAggregate:\n\t\tDisabled.\n\n");
return;
}
storeAppendPrintf(sentry, "\tAggregate:\n");
storeAppendPrintf(sentry, "\t\tMax: %d\n", rate->aggregate.max_bytes);
storeAppendPrintf(sentry, "\t\tRestore: %d\n", rate->aggregate.restore_bps);
storeAppendPrintf(sentry, "\t\tCurrent: %d\n\n", ag);
}
static void
delayPoolStats1(StoreEntry * sentry, unsigned short pool)
{
/* must be a reference only - partially malloc()d struct */
delaySpecSet *rate = Config.Delay.rates[pool];
storeAppendPrintf(sentry, "Pool: %d\n\tClass: 1\n\n", pool + 1);
delayPoolStatsAg(sentry, rate, delay_data[pool].class1->aggregate);
}
static void
delayPoolStats2(StoreEntry * sentry, unsigned short pool)
{
/* must be a reference only - partially malloc()d struct */
delaySpecSet *rate = Config.Delay.rates[pool];
class2DelayPool *class2 = delay_data[pool].class2;
unsigned char shown = 0;
unsigned int i;
storeAppendPrintf(sentry, "Pool: %d\n\tClass: 2\n\n", pool + 1);
delayPoolStatsAg(sentry, rate, class2->aggregate);
if (rate->individual.restore_bps == -1) {
storeAppendPrintf(sentry, "\tIndividual:\n\t\tDisabled.\n\n");
return;
}
storeAppendPrintf(sentry, "\tIndividual:\n");
storeAppendPrintf(sentry, "\t\tMax: %d\n", rate->individual.max_bytes);
storeAppendPrintf(sentry, "\t\tRate: %d\n", rate->individual.restore_bps);
storeAppendPrintf(sentry, "\t\tCurrent: ");
for (i = 0; i < IND_MAP_SZ; i++) {
if (class2->individual_map[i] == 255)
break;
storeAppendPrintf(sentry, "%d:%d ", class2->individual_map[i],
class2->individual[i]);
shown = 1;
}
if (class2->individual_255_used) {
storeAppendPrintf(sentry, "%d:%d ", 255, class2->individual[255]);
shown = 1;
}
if (!shown)
storeAppendPrintf(sentry, "Not used yet.");
storeAppendPrintf(sentry, "\n\n");
}
static void
delayPoolStats3(StoreEntry * sentry, unsigned short pool)
{
/* fully malloc()d struct in this case only */
delaySpecSet *rate = Config.Delay.rates[pool];
class3DelayPool *class3 = delay_data[pool].class3;
unsigned char shown = 0;
unsigned int i;
unsigned int j;
storeAppendPrintf(sentry, "Pool: %d\n\tClass: 3\n\n", pool + 1);
delayPoolStatsAg(sentry, rate, class3->aggregate);
if (rate->network.restore_bps == -1) {
storeAppendPrintf(sentry, "\tNetwork:\n\t\tDisabled.");
} else {
storeAppendPrintf(sentry, "\tNetwork:\n");
storeAppendPrintf(sentry, "\t\tMax: %d\n", rate->network.max_bytes);
storeAppendPrintf(sentry, "\t\tRate: %d\n", rate->network.restore_bps);
storeAppendPrintf(sentry, "\t\tCurrent: ");
for (i = 0; i < NET_MAP_SZ; i++) {
if (class3->network_map[i] == 255)
break;
storeAppendPrintf(sentry, "%d:%d ", class3->network_map[i],
class3->network[i]);
shown = 1;
}
if (class3->network_255_used) {
storeAppendPrintf(sentry, "%d:%d ", 255, class3->network[255]);
shown = 1;
}
if (!shown)
storeAppendPrintf(sentry, "Not used yet.");
}
storeAppendPrintf(sentry, "\n\n");
shown = 0;
if (rate->individual.restore_bps == -1) {
storeAppendPrintf(sentry, "\tIndividual:\n\t\tDisabled.\n\n");
return;
}
storeAppendPrintf(sentry, "\tIndividual:\n");
storeAppendPrintf(sentry, "\t\tMax: %d\n", rate->individual.max_bytes);
storeAppendPrintf(sentry, "\t\tRate: %d\n", rate->individual.restore_bps);
for (i = 0; i < NET_MAP_SZ; i++) {
if (class3->network_map[i] == 255)
break;
storeAppendPrintf(sentry, "\t\tCurrent [Network %d]: ", class3->network_map[i]);
shown = 1;
for (j = 0; j < IND_MAP_SZ; j++) {
if (class3->individual_map[i][j] == 255)
break;
storeAppendPrintf(sentry, "%d:%d ", class3->individual_map[i][j],
class3->individual[(i << 8) | j]);
}
if (class3->individual_255_used[i / 8] & (1 << (i % 8))) {
storeAppendPrintf(sentry, "%d:%d ", 255, class3->individual[(i << 8) | 255]);
}
storeAppendPrintf(sentry, "\n");
}
if (class3->network_255_used) {
storeAppendPrintf(sentry, "\t\tCurrent [Network 255]: ");
shown = 1;
for (j = 0; j < IND_MAP_SZ; j++) {
if (class3->individual_map[255][j] == 255)
break;
storeAppendPrintf(sentry, "%d:%d ", class3->individual_map[255][j],
class3->individual[(255 << 8) | j]);
}
if (class3->individual_255_used[255 / 8] & (1 << (255 % 8))) {
storeAppendPrintf(sentry, "%d:%d ", 255, class3->individual[(255 << 8) | 255]);
}
storeAppendPrintf(sentry, "\n");
}
if (!shown)
storeAppendPrintf(sentry, "\t\tCurrent [All networks]: Not used yet.\n");
storeAppendPrintf(sentry, "\n");
}
static void
delayPoolStats(StoreEntry * sentry)
{
unsigned short i;
storeAppendPrintf(sentry, "Delay pools configured: %d\n\n", Config.Delay.pools);
for (i = 0; i < Config.Delay.pools; i++) {
switch (Config.Delay.class[i]) {
case 0:
storeAppendPrintf(sentry, "Pool: %d\n\tClass: 0\n\n", i + 1);
storeAppendPrintf(sentry, "\tMisconfigured pool.\n\n");
break;
case 1:
delayPoolStats1(sentry, i);
break;
case 2:
delayPoolStats2(sentry, i);
break;
case 3:
delayPoolStats3(sentry, i);
break;
default:
assert(0);
}
}
storeAppendPrintf(sentry, "Memory Used: %d bytes\n", (int) memory_used);
}
#endif
Jump to Line
Something went wrong with that request. Please try again.