Mercurial > illumos > illumos-gate
changeset 955:c52aa32ada37
6221022 syslogd grows due to hostname lookup
author | pd155743 |
---|---|
date | Mon, 21 Nov 2005 03:16:25 -0800 |
parents | 3ca84f048d8e |
children | f9d0be3d33a1 |
files | usr/src/cmd/syslogd/syslogd.c usr/src/cmd/syslogd/syslogd.h |
diffstat | 2 files changed, 118 insertions(+), 87 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/cmd/syslogd/syslogd.c Mon Nov 21 02:26:46 2005 -0800 +++ b/usr/src/cmd/syslogd/syslogd.c Mon Nov 21 03:16:25 2005 -0800 @@ -244,7 +244,7 @@ static int turnoff = 0; static int shutting_down; -static struct hostname_cache *hnc_cache, *hnc_active, *hnc_freeq; +static struct hostname_cache **hnc_cache; static pthread_mutex_t hnc_mutex = PTHREAD_MUTEX_INITIALIZER; static size_t hnc_size = DEF_HNC_SIZE; static unsigned int hnc_ttl = DEF_HNC_TTL; @@ -2187,6 +2187,7 @@ struct nd_hostservlist *hsp; struct nd_hostserv *hspp; pthread_t mythreadno; + int hindex; char *uap; if (Debug) { @@ -2199,7 +2200,7 @@ DPRINT2(2, "cvthname(%u): looking up hostname for %s\n", mythreadno, uap ? uap : "<unknown>"); - if ((h = hnc_lookup(nbp, ncp)) != NULL) { + if ((h = hnc_lookup(nbp, ncp, &hindex)) != NULL) { DPRINT4(2, "cvthname(%u): Cache found %p for %s (%s)\n", mythreadno, h, uap ? uap : "<unknown>", h->hl_hosts[0]); @@ -2281,7 +2282,7 @@ /* This host_list won't be shared by the cache. */ return (h); } - hnc_register(nbp, ncp, h); + hnc_register(nbp, ncp, h, hindex); DPRINT3(2, "cvthname(%u): returning %p for %s\n", mythreadno, h, h->hl_hosts[0]); return (h); @@ -5230,28 +5231,21 @@ /* * The following function implements simple hostname cache mechanism. - * Host name cache consists of single linked list structure which contains - * host_list_t and netbuf pair. All cache entries(hnc_size) are allocated - * initially and linked to "hnc_freeq". If cache register request comes, - * then one element will be pulled from freeq, and will be linked to - * "hnc_active" with given netbuf, host_list_t and expiration time. All valid - * cahces are linked from hnc_active. If the cache element has run - * out, most unused element will be re-used for the new request. + * Host name cache is implemented through hash table bucket chaining method. + * Collisions are handled by bucket chaining. * * hnc_init(): * allocate and initialize the cache. If reinit is set, * invalidate all cache entries. * hnc_look(): - * lookup the cache entries by following single linked list - * from hnc_active. If cached entry was found, it will be - * put in the head of the list, and return. While going through + * It hashes the ipaddress gets the index and walks thru the + * single linked list. if cached entry was found, it will + * put in the head of the list, and return.While going through * the entries, an entry which has already expired will be invalidated. * hnc_register(): - * take one element from freeq, and put the new entry at the top - * of hnc_active. + * Hashes the ipaddress finds the index and puts current entry to the list. * hnc_unreg(): - * invalidate the cache. i.e unlink from hnc_active, and linked the - * element to freeq. + * invalidate the cachep. */ static void @@ -5259,6 +5253,7 @@ { struct hostname_cache **hpp; pthread_t mythreadno; + int i; if (Debug) { mythreadno = pthread_self(); @@ -5267,17 +5262,18 @@ if (reinit) { pthread_mutex_lock(&hnc_mutex); - for (hpp = &hnc_active; *hpp != NULL; ) { - hnc_unreg(hpp); + for (i = 0; i < hnc_size; i++) { + for (hpp = &hnc_cache[i]; *hpp != NULL; ) { + hnc_unreg(hpp); + } } pthread_mutex_unlock(&hnc_mutex); DPRINT1(2, "hnc_init(%u): hostname cache re-configured\n", mythreadno); } else { - int i; - - hnc_cache = malloc(hnc_size * sizeof (struct hostname_cache)); + + hnc_cache = calloc(hnc_size, sizeof (struct hostname_cache *)); if (hnc_cache == NULL) { MALLOC_FAIL("hostname cache"); @@ -5285,26 +5281,18 @@ return; } - for (i = 0; i < hnc_size; i++) { - hnc_cache[i].h = NULL; - hnc_cache[i].next = hnc_cache + i + 1; - } - - hnc_cache[hnc_size - 1].next = NULL; - hnc_freeq = hnc_cache; - hnc_active = NULL; - DPRINT3(1, "hnc_init(%u): hostname cache configured %d entry" " ttl:%d\n", mythreadno, hnc_size, hnc_ttl); } } static host_list_t * -hnc_lookup(struct netbuf *nbp, struct netconfig *ncp) +hnc_lookup(struct netbuf *nbp, struct netconfig *ncp, int *hindex) { struct hostname_cache **hpp, *hp; time_t now; pthread_t mythreadno; + int index; if (Debug) { mythreadno = pthread_self(); @@ -5317,14 +5305,15 @@ pthread_mutex_lock(&hnc_mutex); now = time(0); - for (hpp = &hnc_active; (hp = *hpp) != NULL; ) { + *hindex = index = addr_hash(nbp); + + for (hpp = &hnc_cache[index]; (hp = *hpp) != NULL; ) { DPRINT4(10, "hnc_lookup(%u): check %p on %p for %s\n", mythreadno, hp->h, hp, hp->h->hl_hosts[0]); if (hp->expire < now) { DPRINT2(9, "hnc_lookup(%u): purge %p\n", mythreadno, hp); - /* Note: hnc_unreg changes *hpp */ hnc_unreg(hpp); continue; } @@ -5335,12 +5324,12 @@ * Put the entry at the top. */ - if (hp != hnc_active) { + if (hp != hnc_cache[index]) { /* unlink from active list */ *hpp = (*hpp)->next; /* push it onto the top */ - hp->next = hnc_active; - hnc_active = hp; + hp->next = hnc_cache[index]; + hnc_cache[index] = hp; } pthread_mutex_lock(&hp->h->hl_mutex); @@ -5362,12 +5351,14 @@ } static void -hnc_register(struct netbuf *nbp, struct netconfig *ncp, host_list_t *h) +hnc_register(struct netbuf *nbp, struct netconfig *ncp, + host_list_t *h, int hindex) { - struct hostname_cache **hpp, **tailp, *hp; + struct hostname_cache **hpp, **tailp, *hp, *entry; void *addrbuf; time_t now; pthread_t mythreadno; + int i; if (Debug) { mythreadno = pthread_self(); @@ -5382,51 +5373,54 @@ return; } + if ((entry = malloc(sizeof (struct hostname_cache))) == NULL) { + MALLOC_FAIL("pushing hostname entry"); + free(addrbuf); + return; + } + pthread_mutex_lock(&hnc_mutex); - if (hnc_freeq == NULL) { - DPRINT1(9, "hnc_register(%u): freeq empty\n", mythreadno); - now = time(NULL); - /* - * first go through active list, and discard the - * caches which has been invalid. - */ - for (hpp = &hnc_active; (hp = *hpp) != NULL; ) { - tailp = hpp; - - if (hp->expire < now) { - DPRINT2(9, "hnc_register(%u): discard %p\n", - mythreadno, hp); - hnc_unreg(hpp); - } else { - hpp = &hp->next; - } + i = 0; + + now = time(0); + /* + * first go through active list, and discard the + * caches which has been invalid. Count number of + * non-expired buckets. + */ + + for (hpp = &hnc_cache[hindex]; (hp = *hpp) != NULL; ) { + tailp = hpp; + + if (hp->expire < now) { + DPRINT2(9, "hnc_register(%u): discard %p\n", + mythreadno, hp); + hnc_unreg(hpp); + } else { + i++; + hpp = &hp->next; } - - if (hnc_freeq == NULL) { - DPRINT2(9, "hnc_register(%u): stealing %p\n", - mythreadno, *tailp); - /* - * If still no inactive cache, then steal the least - * active element. - */ - hnc_unreg(tailp); - } - } - - hp = hnc_freeq; - hnc_freeq = hnc_freeq->next; - - /* push it on the top */ - hp->next = hnc_active; - hnc_active = hp; + } + + /* + * If max limit of chained hash buckets has been used up + * delete the least active element in the chain. + */ + if (i == MAX_BUCKETS) { + hnc_unreg(tailp); + } (void) memcpy(addrbuf, nbp->buf, nbp->len); - hp->addr.len = nbp->len; - hp->addr.buf = addrbuf; - hp->ncp = ncp; - hp->h = h; - hp->expire = time(NULL) + hnc_ttl; + entry->addr.len = nbp->len; + entry->addr.buf = addrbuf; + entry->ncp = ncp; + entry->h = h; + entry->expire = time(NULL) + hnc_ttl; + + /* insert it at the top */ + entry->next = hnc_cache[hindex]; + hnc_cache[hindex] = entry; /* * As far as cache is valid, corresponding host_list must @@ -5457,9 +5451,7 @@ /* unlink from active list */ *hpp = (*hpp)->next; - /* put in freeq */ - hp->next = hnc_freeq; - hnc_freeq = hp; + free(hp); } /* @@ -5499,3 +5491,38 @@ } dataq_destroy(&tmpq); } + +/* + * Generate a hash value of the given address and derive + * an index into the hnc_cache hashtable. + * The hashing method is similar to what Java does for strings. + */ +static int +addr_hash(struct netbuf *nbp) +{ + char *uap; + int i; + unsigned long hcode = 0; + + uap = nbp->buf; + + if (uap == NULL) { + return (0); + } + + /* + * Compute a hashcode of the address string + */ + for (i = 0; i < nbp->len; i++) + hcode = (31 * hcode) + uap[i]; + + /* + * Scramble the hashcode for better distribution + */ + hcode += ~(hcode << 9); + hcode ^= (hcode >> 14); + hcode += (hcode << 4); + hcode ^= (hcode >> 10); + + return ((int)(hcode % hnc_size)); +}
--- a/usr/src/cmd/syslogd/syslogd.h Mon Nov 21 02:26:46 2005 -0800 +++ b/usr/src/cmd/syslogd/syslogd.h Mon Nov 21 03:16:25 2005 -0800 @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 1983,1984,1985,1986,1987,1988,1989 AT&T. @@ -229,8 +229,9 @@ time_t expire; }; -#define DEF_HNC_SIZE 128 -#define DEF_HNC_TTL 600 /* 10 minutes */ +#define DEF_HNC_SIZE 2037 +#define DEF_HNC_TTL 1200 /* 20 minutes */ +#define MAX_BUCKETS 30 /* * function prototypes @@ -297,9 +298,12 @@ static void enable_errorlog(void); static void hnc_init(int); -static host_list_t *hnc_lookup(struct netbuf *, struct netconfig *); -static void hnc_register(struct netbuf *, struct netconfig *, host_list_t *); +static host_list_t *hnc_lookup(struct netbuf *, + struct netconfig *, int *); +static void hnc_register(struct netbuf *, + struct netconfig *, host_list_t *, int); static void hnc_unreg(struct hostname_cache **); +static int addr_hash(struct netbuf *nbp); #ifdef __cplusplus