aboutsummaryrefslogtreecommitdiff
path: root/ircd/hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'ircd/hash.c')
-rw-r--r--ircd/hash.c940
1 files changed, 940 insertions, 0 deletions
diff --git a/ircd/hash.c b/ircd/hash.c
new file mode 100644
index 0000000..9d31f47
--- /dev/null
+++ b/ircd/hash.c
@@ -0,0 +1,940 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/hash.c
+ * Copyright (C) 1991 Darren Reed
+ *
+ * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef lint
+static char rcsid[] = "@(#)$Id: hash.c,v 1.15 1999/06/25 21:50:01 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define HASH_C
+#include "s_externs.h"
+#undef HASH_C
+
+static aHashEntry *clientTable = NULL;
+static aHashEntry *channelTable = NULL;
+static aHashEntry *serverTable = NULL;
+static unsigned int *hashtab = NULL;
+static int clhits = 0, clmiss = 0, clsize = 0;
+static int chhits = 0, chmiss = 0, chsize = 0;
+static int svsize = 0;
+int _HASHSIZE = 0;
+int _CHANNELHASHSIZE = 0;
+int _SERVERSIZE = 0;
+
+/*
+ * Hashing.
+ *
+ * The server uses a chained hash table to provide quick and efficient
+ * hash table mantainence (providing the hash function works evenly over
+ * the input range). The hash table is thus not susceptible to problems
+ * of filling all the buckets or the need to rehash.
+ * It is expected that the hash table would look somehting like this
+ * during use:
+ * +-----+ +-----+ +-----+ +-----+
+ * ---| 224 |----| 225 |----| 226 |---| 227 |---
+ * +-----+ +-----+ +-----+ +-----+
+ * | | |
+ * +-----+ +-----+ +-----+
+ * | A | | C | | D |
+ * +-----+ +-----+ +-----+
+ * |
+ * +-----+
+ * | B |
+ * +-----+
+ *
+ * A - GOPbot, B - chang, C - hanuaway, D - *.mu.OZ.AU
+ *
+ * The order shown above is just one instant of the server. Each time a
+ * lookup is made on an entry in the hash table and it is found, the entry
+ * is moved to the top of the chain.
+ */
+
+/*
+ * hash_nick_name
+ *
+ * this function must be *quick*. Thus there should be no multiplication
+ * or division or modulus in the inner loop. subtraction and other bit
+ * operations allowed.
+ */
+static u_int hash_nick_name(nname, store)
+char *nname;
+int *store;
+{
+ Reg u_char *name = (u_char *)nname;
+ Reg u_char ch;
+ Reg u_int hash = 1;
+
+ for (; (ch = *name); name++)
+ {
+ hash <<= 1;
+ hash += hashtab[(int)ch];
+ }
+ /*
+ if (hash < 0)
+ hash = -hash;
+ */
+ *store = hash;
+ hash %= _HASHSIZE;
+ return (hash);
+}
+
+/*
+ * hash_channel_name
+ *
+ * calculate a hash value on at most the first 30 characters of the channel
+ * name. Most names are short than this or dissimilar in this range. There
+ * is little or no point hashing on a full channel name which maybe 255 chars
+ * long.
+ */
+static u_int hash_channel_name(hname, store, shortname)
+char *hname, shortname;
+int *store;
+{
+ Reg u_char *name = (u_char *)hname;
+ Reg u_char ch;
+ Reg int i = 30;
+ Reg u_int hash = 5;
+
+ if (*name == '!' && shortname == 0)
+ name += 1 + CHIDLEN;
+ for (; (ch = *name) && --i; name++)
+ {
+ hash <<= 1;
+ hash += hashtab[(u_int)ch] + (i << 1);
+ }
+ *store = hash;
+ hash %= _CHANNELHASHSIZE;
+ return (hash);
+}
+
+/* bigger prime
+ *
+ * given a positive integer, return a prime number that's larger
+ *
+ * 13feb94 gbl
+ */
+static int bigger_prime(size)
+int size;
+{
+ int trial, failure, sq;
+
+ if (size < 0)
+ return -1;
+
+ if (size < 4)
+ return size;
+
+ if (size % 2 == 0) /* Make sure it's odd because... */
+ size++;
+
+ for ( ; ; size += 2) /* ...no point checking even numbers - Core */
+ {
+ failure = 0;
+ sq = (int)sqrt((double)size);
+ for (trial = 2; trial <= sq ; trial++)
+ {
+ if ((size % trial) == 0)
+ {
+ failure = 1;
+ break;
+ }
+ }
+ if (!failure)
+ return size;
+ }
+ /* return -1; */ /* Never reached */
+}
+
+/*
+ * clear_*_hash_table
+ *
+ * Nullify the hashtable and its contents so it is completely empty.
+ */
+static void clear_client_hash_table(size)
+int size;
+{
+ _HASHSIZE = bigger_prime(size);
+ clhits = 0;
+ clmiss = 0;
+ if (!clientTable)
+ clientTable = (aHashEntry *)MyMalloc(_HASHSIZE *
+ sizeof(aHashEntry));
+ bzero((char *)clientTable, sizeof(aHashEntry) * _HASHSIZE);
+ Debug((DEBUG_DEBUG, "Client Hash Table Init: %d (%d)",
+ _HASHSIZE, size));
+}
+
+static void clear_channel_hash_table(size)
+int size;
+{
+ _CHANNELHASHSIZE = bigger_prime(size);
+ chmiss = 0;
+ chhits = 0;
+ if (!channelTable)
+ channelTable = (aHashEntry *)MyMalloc(_CHANNELHASHSIZE *
+ sizeof(aHashEntry));
+ bzero((char *)channelTable, sizeof(aHashEntry) * _CHANNELHASHSIZE);
+ Debug((DEBUG_DEBUG, "Channel Hash Table Init: %d (%d)",
+ _CHANNELHASHSIZE, size));
+}
+
+static void clear_server_hash_table(size)
+int size;
+{
+ _SERVERSIZE = bigger_prime(size);
+ if (!serverTable)
+ serverTable = (aHashEntry *)MyMalloc(_SERVERSIZE *
+ sizeof(aHashEntry));
+ bzero((char *)serverTable, sizeof(aHashEntry) * _SERVERSIZE);
+ Debug((DEBUG_DEBUG, "Server Hash Table Init: %d (%d)",
+ _SERVERSIZE, size));
+}
+
+void inithashtables()
+{
+ Reg int i;
+
+ clear_client_hash_table((_HASHSIZE) ? _HASHSIZE : HASHSIZE);
+ clear_channel_hash_table((_CHANNELHASHSIZE) ? _CHANNELHASHSIZE
+ : CHANNELHASHSIZE);
+ clear_server_hash_table((_SERVERSIZE) ? _SERVERSIZE : SERVERSIZE);
+
+ /*
+ * Moved multiplication out from the hashfunctions and into
+ * a pre-generated lookup table. Should save some CPU usage
+ * even on machines with a fast mathprocessor. -- Core
+ */
+ hashtab = (u_int *) MyMalloc(256 * sizeof(u_int));
+ for (i = 0; i < 256; i++)
+ hashtab[i] = tolower((char)i) * 109;
+}
+
+static void bigger_hash_table(size, table, new)
+int *size;
+aHashEntry *table;
+int new;
+{
+ Reg aClient *cptr;
+ Reg aChannel *chptr;
+ Reg aServer *sptr;
+ aHashEntry *otab = table;
+ int osize = *size;
+
+ while (!new || new <= osize)
+ if (!new)
+ {
+ new = osize;
+ new = bigger_prime(1 + (int)((float)new * 1.30));
+ }
+ else
+ new = bigger_prime(1 + new);
+
+ Debug((DEBUG_NOTICE, "bigger_h_table(*%#x = %d,%#x,%d)",
+ size, osize, table, new));
+
+ *size = new;
+ MyFree((char *)table);
+ table = (aHashEntry *)MyMalloc(sizeof(*table) * new);
+ bzero((char *)table, sizeof(*table) * new);
+
+ if (otab == channelTable)
+ {
+ Debug((DEBUG_ERROR, "Channel Hash Table from %d to %d (%d)",
+ osize, new, chsize));
+ chmiss = 0;
+ chhits = 0;
+ chsize = 0;
+ channelTable = table;
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ chptr->hnextch = NULL;
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ (void)add_to_channel_hash_table(chptr->chname, chptr);
+ sendto_flag(SCH_HASH, "Channel Hash Table from %d to %d (%d)",
+ osize, new, chsize);
+ }
+ else if (otab == clientTable)
+ {
+ Debug((DEBUG_ERROR, "Client Hash Table from %d to %d (%d)",
+ osize, new, clsize));
+ sendto_flag(SCH_HASH, "Client Hash Table from %d to %d (%d)",
+ osize, new, clsize);
+ clmiss = 0;
+ clhits = 0;
+ clsize = 0;
+ clientTable = table;
+ for (cptr = client; cptr; cptr = cptr->next)
+ cptr->hnext = NULL;
+ for (cptr = client; cptr; cptr = cptr->next)
+ (void)add_to_client_hash_table(cptr->name, cptr);
+ }
+ else if (otab == serverTable)
+ {
+ Debug((DEBUG_ERROR, "Server Hash Table from %d to %d (%d)",
+ osize, new, svsize));
+ sendto_flag(SCH_HASH, "Server Hash Table from %d to %d (%d)",
+ osize, new, svsize);
+ svsize = 0;
+ serverTable = table;
+ for (sptr = svrtop; sptr; sptr = sptr->nexts)
+ sptr->shnext = NULL;
+ for (sptr = svrtop; sptr; sptr = sptr->nexts)
+ (void)add_to_server_hash_table(sptr, sptr->bcptr);
+ }
+ ircd_writetune(tunefile);
+ return;
+}
+
+
+/*
+ * add_to_client_hash_table
+ */
+int add_to_client_hash_table(name, cptr)
+char *name;
+aClient *cptr;
+{
+ Reg u_int hashv;
+
+ hashv = hash_nick_name(name, &cptr->hashv);
+ cptr->hnext = (aClient *)clientTable[hashv].list;
+ clientTable[hashv].list = (void *)cptr;
+ clientTable[hashv].links++;
+ clientTable[hashv].hits++;
+ clsize++;
+ if (clsize > _HASHSIZE)
+ bigger_hash_table(&_HASHSIZE, clientTable, 0);
+ return 0;
+}
+
+/*
+ * add_to_channel_hash_table
+ */
+int add_to_channel_hash_table(name, chptr)
+char *name;
+aChannel *chptr;
+{
+ Reg u_int hashv;
+
+ hashv = hash_channel_name(name, &chptr->hashv, 0);
+ chptr->hnextch = (aChannel *)channelTable[hashv].list;
+ channelTable[hashv].list = (void *)chptr;
+ channelTable[hashv].links++;
+ channelTable[hashv].hits++;
+ chsize++;
+ if (chsize > _CHANNELHASHSIZE)
+ bigger_hash_table(&_CHANNELHASHSIZE, channelTable, 0);
+ return 0;
+}
+
+/*
+ * add_to_server_hash_table
+ */
+int add_to_server_hash_table(sptr, cptr)
+aServer *sptr;
+aClient *cptr;
+{
+ Reg u_int hashv;
+
+ Debug((DEBUG_DEBUG, "Add %s token %d/%d/%s cptr %#x to server table",
+ sptr->bcptr->name, sptr->stok, sptr->ltok, sptr->tok, cptr));
+ hashv = sptr->stok * 15053;
+ hashv %= _SERVERSIZE;
+ sptr->shnext = (aServer *)serverTable[hashv].list;
+ serverTable[hashv].list = (void *)sptr;
+ serverTable[hashv].links++;
+ serverTable[hashv].hits++;
+ svsize++;
+ if (svsize > _SERVERSIZE)
+ bigger_hash_table(&_SERVERSIZE, serverTable, 0);
+ return 0;
+}
+
+/*
+ * del_from_client_hash_table
+ */
+int del_from_client_hash_table(name, cptr)
+char *name;
+aClient *cptr;
+{
+ Reg aClient *tmp, *prev = NULL;
+ Reg u_int hashv;
+
+ hashv = cptr->hashv;
+ hashv %= _HASHSIZE;
+ for (tmp = (aClient *)clientTable[hashv].list; tmp; tmp = tmp->hnext)
+ {
+ if (tmp == cptr)
+ {
+ if (prev)
+ prev->hnext = tmp->hnext;
+ else
+ clientTable[hashv].list = (void *)tmp->hnext;
+ tmp->hnext = NULL;
+ if (clientTable[hashv].links > 0)
+ {
+ clientTable[hashv].links--;
+ clsize--;
+ return 1;
+ }
+ else
+ {
+ sendto_flag(SCH_ERROR, "cl-hash table failure");
+ Debug((DEBUG_ERROR, "cl-hash table failure"));
+ /*
+ * Should never actually return from here and
+ * if we do it is an error/inconsistency in the
+ * hash table.
+ */
+ return -1;
+ }
+ }
+ prev = tmp;
+ }
+ return 0;
+}
+
+/*
+ * del_from_channel_hash_table
+ */
+int del_from_channel_hash_table(name, chptr)
+char *name;
+aChannel *chptr;
+{
+ Reg aChannel *tmp, *prev = NULL;
+ Reg u_int hashv;
+
+ hashv = chptr->hashv;
+ hashv %= _CHANNELHASHSIZE;
+ for (tmp = (aChannel *)channelTable[hashv].list; tmp;
+ tmp = tmp->hnextch)
+ {
+ if (tmp == chptr)
+ {
+ if (prev)
+ prev->hnextch = tmp->hnextch;
+ else
+ channelTable[hashv].list=(void *)tmp->hnextch;
+ tmp->hnextch = NULL;
+ if (channelTable[hashv].links > 0)
+ {
+ channelTable[hashv].links--;
+ chsize--;
+ return 1;
+ }
+ else
+ {
+ sendto_flag(SCH_ERROR, "ch-hash table failure");
+ return -1;
+ }
+ }
+ prev = tmp;
+ }
+ return 0;
+}
+
+
+/*
+ * del_from_server_hash_table
+ */
+int del_from_server_hash_table(sptr, cptr)
+aServer *sptr;
+aClient *cptr;
+{
+ Reg aServer *tmp, *prev = NULL;
+ Reg u_int hashv;
+
+ hashv = sptr->stok * 15053;
+ hashv %= _SERVERSIZE;
+ for (tmp = (aServer *)serverTable[hashv].list; tmp; tmp = tmp->shnext)
+ {
+ if (tmp == sptr)
+ {
+ if (prev)
+ prev->shnext = tmp->shnext;
+ else
+ serverTable[hashv].list = (void *)tmp->shnext;
+ tmp->shnext = NULL;
+ if (serverTable[hashv].links > 0)
+ {
+ serverTable[hashv].links--;
+ svsize--;
+ return 1;
+ }
+ else
+ {
+ sendto_flag(SCH_ERROR, "se-hash table failure");
+ return -1;
+ }
+ }
+ prev = tmp;
+ }
+ return 0;
+}
+
+
+/*
+ * hash_find_client
+ */
+aClient *hash_find_client(name, cptr)
+char *name;
+aClient *cptr;
+{
+ Reg aClient *tmp;
+ Reg aClient *prv = NULL;
+ Reg aHashEntry *tmp3;
+ u_int hashv, hv;
+
+ hashv = hash_nick_name(name, &hv);
+ tmp3 = &clientTable[hashv];
+
+ /*
+ * Got the bucket, now search the chain.
+ */
+ for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
+ if (hv == tmp->hashv && mycmp(name, tmp->name) == 0)
+ {
+ clhits++;
+ /*
+ * If the member of the hashtable we found isnt at
+ * the top of its chain, put it there. This builds
+ * a most-frequently used order into the chains of
+ * the hash table, giving speadier lookups on those
+ * nicks which are being used currently. This same
+ * block of code is also used for channels and
+ * servers for the same performance reasons.
+ */
+ if (prv)
+ {
+ aClient *tmp2;
+
+ tmp2 = (aClient *)tmp3->list;
+ tmp3->list = (void *)tmp;
+ prv->hnext = tmp->hnext;
+ tmp->hnext = tmp2;
+ }
+ return (tmp);
+ }
+ clmiss++;
+ return (cptr);
+}
+
+/*
+ * hash_find_server
+ */
+aClient *hash_find_server(server, cptr)
+char *server;
+aClient *cptr;
+{
+ Reg aClient *tmp, *prv = NULL;
+ Reg char *t;
+ Reg char ch;
+ aHashEntry *tmp3;
+ u_int hashv, hv;
+
+ hashv = hash_nick_name(server, &hv);
+ tmp3 = &clientTable[hashv];
+
+ for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
+ {
+ if (!IsServer(tmp) && !IsMe(tmp))
+ continue;
+ if (hv == tmp->hashv && mycmp(server, tmp->name) == 0)
+ {
+ clhits++;
+ if (prv)
+ {
+ aClient *tmp2;
+
+ tmp2 = (aClient *)tmp3->list;
+ tmp3->list = (void *)tmp;
+ prv->hnext = tmp->hnext;
+ tmp->hnext = tmp2;
+ }
+ return (tmp);
+ }
+ }
+ t = ((char *)server + strlen(server));
+ /*
+ * Whats happening in this next loop ? Well, it takes a name like
+ * foo.bar.edu and proceeds to search for *.edu and then *.bar.edu.
+ * This is for checking full server names against masks although
+ * it isn't often done this way in lieu of using match().
+ */
+ for (;;)
+ {
+ t--;
+ for (; t >= server; t--)
+ if (*(t+1) == '.')
+ break;
+ if (t < server || *t == '*')
+ break;
+ ch = *t;
+ *t = '*';
+ /*
+ * Don't need to check IsServer() here since nicknames can't
+ * have *'s in them anyway.
+ */
+ if (((tmp = hash_find_client(t, cptr))) != cptr)
+ {
+ *t = ch;
+ return (tmp);
+ }
+ *t = ch;
+ }
+ clmiss++;
+ return (cptr);
+}
+
+/*
+ * hash_find_channel
+ */
+aChannel *hash_find_channel(name, chptr)
+char *name;
+aChannel *chptr;
+{
+ Reg aChannel *tmp, *prv = NULL;
+ Reg aHashEntry *tmp3;
+ u_int hashv, hv;
+
+ hashv = hash_channel_name(name, &hv, 0);
+ tmp3 = &channelTable[hashv];
+
+ for (tmp = (aChannel *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnextch)
+ if (hv == tmp->hashv && mycmp(name, tmp->chname) == 0)
+ {
+ chhits++;
+ if (prv)
+ {
+ register aChannel *tmp2;
+
+ tmp2 = (aChannel *)tmp3->list;
+ tmp3->list = (void *)tmp;
+ prv->hnextch = tmp->hnextch;
+ tmp->hnextch = tmp2;
+ }
+ return (tmp);
+ }
+ chmiss++;
+ return chptr;
+}
+
+/*
+ * hash_find_channels
+ *
+ * look up matches for !?????name instead of a real match.
+ */
+aChannel *hash_find_channels(name, chptr)
+char *name;
+aChannel *chptr;
+{
+ aChannel *tmp;
+ u_int hashv, hv;
+
+ if (chptr == NULL)
+ {
+ aHashEntry *tmp3;
+
+ hashv = hash_channel_name(name, &hv, 1);
+ tmp3 = &channelTable[hashv];
+ chptr = (aChannel *) tmp3->list;
+ }
+ else
+ {
+ hv = chptr->hashv;
+ chptr = chptr->hnextch;
+ }
+
+ if (chptr == NULL)
+ return NULL;
+ for (tmp = chptr; tmp; tmp = tmp->hnextch)
+ if (hv == tmp->hashv && *tmp->chname == '!' &&
+ mycmp(name, tmp->chname + CHIDLEN + 1) == 0)
+ {
+ chhits++;
+ return (tmp);
+ }
+ chmiss++;
+ return NULL;
+}
+
+/*
+ * hash_find_stoken
+ */
+aServer *hash_find_stoken(tok, cptr, dummy)
+int tok;
+aClient *cptr;
+void *dummy;
+{
+ Reg aServer *tmp, *prv = NULL;
+ Reg aHashEntry *tmp3;
+ u_int hashv, hv;
+
+ hv = hashv = tok * 15053;
+ hashv %= _SERVERSIZE;
+ tmp3 = &serverTable[hashv];
+
+ for (tmp = (aServer *)tmp3->list; tmp; prv = tmp, tmp = tmp->shnext)
+ if (tmp->stok == tok && tmp->bcptr->from == cptr)
+ {
+ if (prv)
+ {
+ Reg aServer *tmp2;
+
+ tmp2 = (aServer *)tmp3->list;
+ tmp3->list = (void *)tmp;
+ prv->shnext = tmp->shnext;
+ tmp->shnext = tmp2;
+ }
+ return (tmp);
+ }
+ return (aServer *)dummy;
+}
+
+/*
+ * NOTE: this command is not supposed to be an offical part of the ircd
+ * protocol. It is simply here to help debug and to monitor the
+ * performance of the hash functions and table, enabling a better
+ * algorithm to be sought if this one becomes troublesome.
+ * -avalon
+ */
+
+int m_hash(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+#ifdef DEBUGMODE
+ register int l, i;
+ register aHashEntry *tab;
+ int deepest = 0, deeplink = 0, showlist = 0, tothits = 0;
+ int mosthit = 0, mosthits = 0, used = 0, used_now = 0, totlink = 0;
+ int link_pop[10], size = _HASHSIZE;
+ char ch;
+ aHashEntry *table;
+
+ if (parc > 1) {
+ ch = *parv[1];
+ if (islower(ch))
+ table = clientTable;
+ else {
+ table = channelTable;
+ size = _CHANNELHASHSIZE;
+ }
+ if (ch == 'L' || ch == 'l')
+ showlist = 1;
+ } else {
+ ch = '\0';
+ table = clientTable;
+ }
+
+ for (i = 0; i < 10; i++)
+ link_pop[i] = 0;
+ for (i = 0; i < size; i++) {
+ tab = &table[i];
+ l = tab->links;
+ if (showlist)
+ sendto_one(sptr,
+ "NOTICE %s :Hash Entry:%6d Hits:%7d Links:%6d",
+ parv[0], i, tab->hits, l);
+ if (l > 0) {
+ if (l < 10)
+ link_pop[l]++;
+ else
+ link_pop[9]++;
+ used_now++;
+ totlink += l;
+ if (l > deepest) {
+ deepest = l;
+ deeplink = i;
+ }
+ }
+ else
+ link_pop[0]++;
+ l = tab->hits;
+ if (l) {
+ used++;
+ tothits += l;
+ if (l > mosthits) {
+ mosthits = l;
+ mosthit = i;
+ }
+ }
+ }
+ switch((int)ch)
+ {
+ case 'V' : case 'v' :
+ {
+ register aClient *acptr;
+ int bad = 0, listlength = 0;
+
+ for (acptr = client; acptr; acptr = acptr->next) {
+ if (hash_find_client(acptr->name,acptr) != acptr) {
+ if (ch == 'V')
+ sendto_one(sptr, "NOTICE %s :Bad hash for %s",
+ parv[0], acptr->name);
+ bad++;
+ }
+ listlength++;
+ }
+ sendto_one(sptr,"NOTICE %s :List Length: %d Bad Hashes: %d",
+ parv[0], listlength, bad);
+ }
+ case 'P' : case 'p' :
+ for (i = 0; i < 10; i++)
+ sendto_one(sptr,"NOTICE %s :Entires with %d links : %d",
+ parv[0], i, link_pop[i]);
+ return (2);
+ case 'r' :
+ {
+ Reg aClient *acptr;
+
+ sendto_one(sptr,"NOTICE %s :Rehashing Client List.", parv[0]);
+ clear_client_hash_table(_HASHSIZE);
+ for (acptr = client; acptr; acptr = acptr->next)
+ (void)add_to_client_hash_table(acptr->name, acptr);
+ break;
+ }
+ case 'R' :
+ {
+ Reg aChannel *acptr;
+
+ sendto_one(sptr,"NOTICE %s :Rehashing Channel List.", parv[0]);
+ clear_channel_hash_table(_CHANNELHASHSIZE);
+ for (acptr = channel; acptr; acptr = acptr->nextch)
+ (void)add_to_channel_hash_table(acptr->chname, acptr);
+ break;
+ }
+ case 'H' :
+ if (parc > 2)
+ sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
+ parv[0], parv[2],
+ hash_channel_name(parv[2], NULL, 0));
+ return (2);
+ case 'h' :
+ if (parc > 2)
+ sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
+ parv[0], parv[2],
+ hash_nick_name(parv[2], NULL));
+ return (2);
+ case 'n' :
+ {
+ aClient *tmp;
+ int max;
+
+ if (parc <= 2 || !IsAnOper(sptr))
+ return (1);
+ l = atoi(parv[2]) % _HASHSIZE;
+ if (parc > 3)
+ max = atoi(parv[3]) % _HASHSIZE;
+ else
+ max = l;
+ for (;l <= max; l++)
+ for (i = 0, tmp = (aClient *)clientTable[l].list; tmp;
+ i++, tmp = tmp->hnext)
+ {
+ if (parv[1][2] == '1' && tmp != tmp->from)
+ continue;
+ sendto_one(sptr,"NOTICE %s :Node: %d #%d %s",
+ parv[0], l, i, tmp->name);
+ }
+ return (2);
+ }
+ case 'N' :
+ {
+ aChannel *tmp;
+ int max;
+
+ if (parc <= 2 || !IsAnOper(sptr))
+ return (1);
+ l = atoi(parv[2]) % _CHANNELHASHSIZE;
+ if (parc > 3)
+ max = atoi(parv[3]) % _CHANNELHASHSIZE;
+ else
+ max = l;
+ for (;l <= max; l++)
+ for (i = 0, tmp = (aChannel *)channelTable[l].list; tmp;
+ i++, tmp = tmp->hnextch)
+ sendto_one(sptr,"NOTICE %s :Node: %d #%d %s",
+ parv[0], l, i, tmp->chname);
+ return (2);
+ }
+ case 'S' :
+#else
+ if (parc>1&&!strcmp(parv[1],"sums")){
+#endif
+ sendto_one(sptr, "NOTICE %s :[SBSDC] [SUSER]", parv[0]);
+ sendto_one(sptr, "NOTICE %s :[SSERV] [IRCDC]", parv[0]);
+ sendto_one(sptr, "NOTICE %s :[CHANC] [SMISC]", parv[0]);
+ sendto_one(sptr, "NOTICE %s :[HASHC] [VERSH]", parv[0]);
+ sendto_one(sptr, "NOTICE %s :[MAKEF] HOSTID", parv[0]);
+#ifndef DEBUGMODE
+ }
+#endif
+ return 2;
+#ifdef DEBUGMODE
+ case 'z' :
+ {
+ if (parc <= 2 || !IsAnOper(sptr))
+ return 1;
+ l = atoi(parv[2]);
+ if (l < 256)
+ return 1;
+ bigger_hash_table(&_HASHSIZE, clientTable, l);
+ sendto_one(sptr, "NOTICE %s :HASHSIZE now %d", parv[0], l);
+ break;
+ }
+ case 'Z' :
+ {
+ if (parc <= 2 || !IsAnOper(sptr))
+ return 1;
+ l = atoi(parv[2]);
+ if (l < 256)
+ return 1;
+ bigger_hash_table(&_CHANNELHASHSIZE, channelTable, l);
+ sendto_one(sptr, "NOTICE %s :CHANNELHASHSIZE now %d",
+ parv[0], l);
+ break;
+ }
+ default :
+ break;
+ }
+ sendto_one(sptr,"NOTICE %s :Entries Hashed: %d NonEmpty: %d of %d",
+ parv[0], totlink, used_now, size);
+ if (!used_now)
+ used_now = 1;
+ sendto_one(sptr,"NOTICE %s :Hash Ratio (av. depth): %f %Full: %f",
+ parv[0], (float)((1.0 * totlink) / (1.0 * used_now)),
+ (float)((1.0 * used_now) / (1.0 * size)));
+ sendto_one(sptr,"NOTICE %s :Deepest Link: %d Links: %d",
+ parv[0], deeplink, deepest);
+ if (!used)
+ used = 1;
+ sendto_one(sptr,"NOTICE %s :Total Hits: %d Unhit: %d Av Hits: %f",
+ parv[0], tothits, size-used,
+ (float)((1.0 * (float)tothits) / (1.0 * (float)used)));
+ sendto_one(sptr,"NOTICE %s :Entry Most Hit: %d Hits: %d",
+ parv[0], mosthit, mosthits);
+ sendto_one(sptr,"NOTICE %s :Client hits %d miss %d",
+ parv[0], clhits, clmiss);
+ sendto_one(sptr,"NOTICE %s :Channel hits %d miss %d",
+ parv[0], chhits, chmiss);
+ return 2;
+#endif
+}
+
+