home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / in4wjcxu / other / irc / ircd / hash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-14  |  16.4 KB  |  723 lines

  1. /************************************************************************
  2.  *   IRC - Internet Relay Chat, ircd/hash.c
  3.  *   Copyright (C) 1991 Darren Reed
  4.  *
  5.  *   This program is free software; you can redistribute it and/or modify
  6.  *   it under the terms of the GNU General Public License as published by
  7.  *   the Free Software Foundation; either version 1, or (at your option)
  8.  *   any later version.
  9.  *
  10.  *   This program is distributed in the hope that it will be useful,
  11.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *   GNU General Public License for more details.
  14.  *
  15.  *   You should have received a copy of the GNU General Public License
  16.  *   along with this program; if not, write to the Free Software
  17.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19. #ifndef lint
  20. static char sccsid[] = "@(#)hash.c    2.10 7/3/93 (C) 1991 Darren Reed";
  21. #endif
  22.  
  23. #include "struct.h"
  24. #include "common.h"
  25. #include "sys.h"
  26. #include "hash.h"
  27. #include "h.h"
  28.  
  29. #ifdef    DEBUGMODE
  30. static    aHashEntry    *clientTable = NULL;
  31. static    aHashEntry    *channelTable = NULL;
  32. static    int    clhits, clmiss;
  33. static    int    chhits, chmiss;
  34. int    HASHSIZE = 2003;
  35. int    CHANNELHASHSIZE = 607;
  36. #else
  37. static    aHashEntry    clientTable[HASHSIZE];
  38. static    aHashEntry    channelTable[CHANNELHASHSIZE];
  39. #endif
  40.  
  41. static    int    hash_mult[] = { 173, 179, 181, 191, 193, 197,
  42.                 199, 211, 223, 227, 229, 233,
  43.                 239, 241, 251, 257, 263, 269,
  44.                 271, 277, 281, 293, 307, 311,
  45.                 401, 409, 419, 421, 431, 433,
  46.                 439, 443, 449, 457, 461, 463
  47.                 };
  48. /*
  49.  * Hashing.
  50.  *
  51.  *   The server uses a chained hash table to provide quick and efficient
  52.  * hash table mantainence (providing the hash function works evenly over
  53.  * the input range).  The hash table is thus not susceptible to problems
  54.  * of filling all the buckets or the need to rehash.
  55.  *    It is expected that the hash table would look somehting like this
  56.  * during use:
  57.  *                   +-----+    +-----+    +-----+   +-----+
  58.  *                ---| 224 |----| 225 |----| 226 |---| 227 |---
  59.  *                   +-----+    +-----+    +-----+   +-----+
  60.  *                      |          |          |
  61.  *                   +-----+    +-----+    +-----+
  62.  *                   |  A  |    |  C  |    |  D  |
  63.  *                   +-----+    +-----+    +-----+
  64.  *                      |
  65.  *                   +-----+
  66.  *                   |  B  |
  67.  *                   +-----+
  68.  *
  69.  * A - GOPbot, B - chang, C - hanuaway, D - *.mu.OZ.AU
  70.  *
  71.  * The order shown above is just one instant of the server.  Each time a
  72.  * lookup is made on an entry in the hash table and it is found, the entry
  73.  * is moved to the top of the chain.
  74.  */
  75.  
  76. /*
  77.  * hash_nick_name
  78.  *
  79.  * this function must be *quick*.  Thus there should be no multiplication
  80.  * or division or modulus in the inner loop.  subtraction and other bit
  81.  * operations allowed.
  82.  */
  83. int    hash_nick_name(nname)
  84. char    *nname;
  85. {
  86.     Reg1    u_char    *name = (u_char *)nname;
  87.     Reg2    u_char    ch;
  88.     Reg4    int    hash = 1, *tab;
  89.  
  90.     for (tab = hash_mult; (ch = *name); name++, tab++)
  91.         hash += tolower(ch) + *tab + hash;
  92.     if (hash < 0)
  93.         hash = -hash;
  94.     hash %= HASHSIZE;
  95.     return (hash);
  96. }
  97.  
  98. /*
  99.  * hash_channel_name
  100.  *
  101.  * calculate a hash value on at most the first 30 characters of the channel
  102.  * name. Most names are short than this or dissimilar in this range. There
  103.  * is little or no point hashing on a full channel name which maybe 255 chars
  104.  * long.
  105.  */
  106. int    hash_channel_name(hname)
  107. char    *hname;
  108. {
  109.     Reg1    u_char    *name = (u_char *)hname;
  110.     Reg2    u_char    ch;
  111.     Reg3    int    i = 30;
  112.     Reg4    int    hash = 5, *tab;
  113.  
  114.     for (tab = hash_mult; (ch = *name) && --i; name++, tab++)
  115.         hash += tolower(ch) + *tab + hash + i + i;
  116.     if (hash < 0)
  117.         hash = -hash;
  118.     hash %= CHANNELHASHSIZE;
  119.     return (hash);
  120. }
  121.  
  122. /*
  123.  * clear_*_hash_table
  124.  *
  125.  * Nullify the hashtable and its contents so it is completely empty.
  126.  */
  127. void    clear_client_hash_table()
  128. {
  129. #ifdef    DEBUGMODE
  130.     clhits = 0;
  131.     clmiss = 0;
  132.     if (!clientTable)
  133.         clientTable = (aHashEntry *)MyMalloc(HASHSIZE *
  134.                              sizeof(aHashEntry));
  135. #endif
  136.  
  137.     bzero((char *)clientTable, sizeof(aHashEntry) * HASHSIZE);
  138. }
  139.  
  140. void    clear_channel_hash_table()
  141. {
  142. #ifdef    DEBUGMODE
  143.     chmiss = 0;
  144.     chhits = 0;
  145.     if (!channelTable)
  146.         channelTable = (aHashEntry *)MyMalloc(CHANNELHASHSIZE *
  147.                              sizeof(aHashEntry));
  148. #endif
  149.     bzero((char *)channelTable, sizeof(aHashEntry) * CHANNELHASHSIZE);
  150. }
  151.  
  152. /*
  153.  * add_to_client_hash_table
  154.  */
  155. int    add_to_client_hash_table(name, cptr)
  156. char    *name;
  157. aClient    *cptr;
  158. {
  159.     Reg1    int    hashv;
  160.  
  161.     hashv = hash_nick_name(name);
  162.     cptr->hnext = (aClient *)clientTable[hashv].list;
  163.     clientTable[hashv].list = (void *)cptr;
  164.     clientTable[hashv].links++;
  165.     clientTable[hashv].hits++;
  166.     return 0;
  167. }
  168.  
  169. /*
  170.  * add_to_channel_hash_table
  171.  */
  172. int    add_to_channel_hash_table(name, chptr)
  173. char    *name;
  174. aChannel    *chptr;
  175. {
  176.     Reg1    int    hashv;
  177.  
  178.     hashv = hash_channel_name(name);
  179.     chptr->hnextch = (aChannel *)channelTable[hashv].list;
  180.     channelTable[hashv].list = (void *)chptr;
  181.     channelTable[hashv].links++;
  182.     channelTable[hashv].hits++;
  183.     return 0;
  184. }
  185.  
  186. /*
  187.  * del_from_client_hash_table
  188.  */
  189. int    del_from_client_hash_table(name, cptr)
  190. char    *name;
  191. aClient    *cptr;
  192. {
  193.     Reg1    aClient    *tmp, *prev = NULL;
  194.     Reg2    int    hashv;
  195.  
  196.     hashv = hash_nick_name(name);
  197.     for (tmp = (aClient *)clientTable[hashv].list; tmp; tmp = tmp->hnext)
  198.         {
  199.         if (tmp == cptr)
  200.             {
  201.             if (prev)
  202.                 prev->hnext = tmp->hnext;
  203.             else
  204.                 clientTable[hashv].list = (void *)tmp->hnext;
  205.             tmp->hnext = NULL;
  206.             if (clientTable[hashv].links > 0)
  207.                 {
  208.                 clientTable[hashv].links--;
  209.                 return 1;
  210.                 } 
  211.             else
  212.                 /*
  213.                  * Should never actually return from here and
  214.                  * if we do it is an error/inconsistency in the
  215.                  * hash table.
  216.                  */
  217.                 return -1;
  218.             }
  219.         prev = tmp;
  220.         }
  221.     return 0;
  222. }
  223.  
  224. /*
  225.  * del_from_channel_hash_table
  226.  */
  227. int    del_from_channel_hash_table(name, chptr)
  228. char    *name;
  229. aChannel    *chptr;
  230. {
  231.     Reg1    aChannel    *tmp, *prev = NULL;
  232.     Reg2    int    hashv;
  233.  
  234.     hashv = hash_channel_name(name);
  235.     for (tmp = (aChannel *)channelTable[hashv].list; tmp;
  236.          tmp = tmp->hnextch)
  237.         {
  238.         if (tmp == chptr)
  239.             {
  240.             if (prev)
  241.                 prev->hnextch = tmp->hnextch;
  242.             else
  243.                 channelTable[hashv].list=(void *)tmp->hnextch;
  244.             tmp->hnextch = NULL;
  245.             if (channelTable[hashv].links > 0)
  246.                 {
  247.                 channelTable[hashv].links--;
  248.                 return 1;
  249.                 }
  250.             else
  251.                 return -1;
  252.             }
  253.         prev = tmp;
  254.         }
  255.     return 0;
  256. }
  257.  
  258.  
  259. /*
  260.  * hash_find_client
  261.  */
  262. aClient    *hash_find_client(name, cptr)
  263. char    *name;
  264. aClient    *cptr;
  265. {
  266.     Reg1    aClient    *tmp;
  267.     Reg2    aClient    *prv = NULL;
  268.     Reg3    aHashEntry    *tmp3;
  269.     int    hashv;
  270.  
  271.     hashv = hash_nick_name(name);
  272.     tmp3 = &clientTable[hashv];
  273.  
  274.     /*
  275.      * Got the bucket, now search the chain.
  276.      */
  277.     for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
  278.         if (mycmp(name, tmp->name) == 0)
  279.             goto c_move_to_top;
  280. #ifdef    DEBUGMODE
  281.     clmiss++;
  282. #endif
  283.     return (cptr);
  284. c_move_to_top:
  285. #ifdef    DEBUGMODE
  286.     clhits++;
  287. #endif
  288.     /*
  289.      * If the member of the hashtable we found isnt at the top of its
  290.      * chain, put it there.  This builds a most-frequently used order into
  291.      * the chains of the hash table, giving speadier lookups on those nicks
  292.      * which are being used currently.  This same block of code is also
  293.      * used for channels and servers for the same performance reasons.
  294.      */
  295.     if (prv)
  296.         {
  297.         aClient *tmp2;
  298.  
  299.         tmp2 = (aClient *)tmp3->list;
  300.         tmp3->list = (void *)tmp;
  301.         prv->hnext = tmp->hnext;
  302.         tmp->hnext = tmp2;
  303.         }
  304.     return (tmp);
  305. }
  306.  
  307. /*
  308.  * hash_find_nickserver
  309.  */
  310. aClient    *hash_find_nickserver(name, cptr)
  311. char    *name;
  312. aClient *cptr;
  313. {
  314.     Reg1    aClient    *tmp;
  315.     Reg2    aClient    *prv = NULL;
  316.     Reg3    aHashEntry    *tmp3;
  317.     int    hashv;
  318.     char    *serv;
  319.  
  320.     serv = index(name, '@');
  321.     *serv++ = '\0';
  322.     hashv = hash_nick_name(name);
  323.     tmp3 = &clientTable[hashv];
  324.  
  325.     /*
  326.      * Got the bucket, now search the chain.
  327.      */
  328.     for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
  329.         if (mycmp(name, tmp->name) == 0 && tmp->user &&
  330.             mycmp(serv, tmp->user->server) == 0)
  331.             goto c_move_to_top;
  332.  
  333. #ifdef    DEBUGMODE
  334.     clmiss++;
  335. #endif
  336.     *--serv = '\0';
  337.     return (cptr);
  338.  
  339. c_move_to_top:
  340. #ifdef    DEBUGMODE
  341.     clhits++;
  342. #endif
  343.     /*
  344.      * If the member of the hashtable we found isnt at the top of its
  345.      * chain, put it there.  This builds a most-frequently used order into
  346.      * the chains of the hash table, giving speadier lookups on those nicks
  347.      * which are being used currently.  This same block of code is also
  348.      * used for channels and servers for the same performance reasons.
  349.      */
  350.     if (prv)
  351.         {
  352.         aClient *tmp2;
  353.  
  354.         tmp2 = (aClient *)tmp3->list;
  355.         tmp3->list = (void *)tmp;
  356.         prv->hnext = tmp->hnext;
  357.         tmp->hnext = tmp2;
  358.         }
  359.     *--serv = '\0';
  360.     return (tmp);
  361. }
  362.  
  363. /*
  364.  * hash_find_server
  365.  */
  366. aClient    *hash_find_server(server, cptr)
  367. char    *server;
  368. aClient *cptr;
  369. {
  370.     Reg1    aClient    *tmp, *prv = NULL;
  371.     Reg2    char    *t;
  372.     Reg3    char    ch;
  373.     aHashEntry    *tmp3;
  374.  
  375.     int hashv;
  376.  
  377.     hashv = hash_nick_name(server);
  378.     tmp3 = &clientTable[hashv];
  379.  
  380.     for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
  381.         {
  382.         if (!IsServer(tmp) && !IsMe(tmp))
  383.             continue;
  384.         if (mycmp(server, tmp->name) == 0)
  385.             goto s_move_to_top;
  386.         }
  387.     t = ((char *)server + strlen(server));
  388.     /*
  389.      * Whats happening in this next loop ? Well, it takes a name like
  390.      * foo.bar.edu and proceeds to earch for *.edu and then *.bar.edu.
  391.      * This is for checking full server names against masks although
  392.      * it isnt often done this way in lieu of using matches().
  393.      */
  394.     for (;;)
  395.         {
  396.         t--;
  397.         for (; t > server; t--)
  398.             if (*(t+1) == '.')
  399.                 break;
  400.         if (*t == '*' || t == server)
  401.             break;
  402.         ch = *t;
  403.         *t = '*';
  404.         /*
  405.           * Dont need to check IsServer() here since nicknames cant
  406.          *have *'s in them anyway.
  407.          */
  408.         if (((tmp = hash_find_client(t, cptr))) != cptr)
  409.             {
  410.             *t = ch;
  411.             return (tmp);
  412.             }
  413.         *t = ch;
  414.         }
  415. #ifdef    DEBUGMODE
  416.     clmiss++;
  417. #endif
  418.     return (cptr);
  419. s_move_to_top:
  420. #ifdef    DEBUGMODE
  421.     clhits++;
  422. #endif
  423.     if (prv)
  424.         {
  425.         aClient *tmp2;
  426.  
  427.         tmp2 = (aClient *)tmp3->list;
  428.         tmp3->list = (void *)tmp;
  429.         prv->hnext = tmp->hnext;
  430.         tmp->hnext = tmp2;
  431.         }
  432.     return (tmp);
  433. }
  434.  
  435. /*
  436.  * hash_find_channel
  437.  */
  438. aChannel    *hash_find_channel(name, chptr)
  439. char    *name;
  440. aChannel *chptr;
  441. {
  442.     int    hashv;
  443.     Reg1    aChannel    *tmp, *prv = NULL;
  444.     aHashEntry    *tmp3;
  445.  
  446.     hashv = hash_channel_name(name);
  447.     tmp3 = &channelTable[hashv];
  448.  
  449.     for (tmp = (aChannel *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnextch)
  450.         if (mycmp(name, tmp->chname) == 0)
  451.             goto c_move_to_top;
  452. #ifdef    DEBUGMODE
  453.     chmiss++;
  454. #endif
  455.     return chptr;
  456. c_move_to_top:
  457. #ifdef    DEBUGMODE
  458.     chhits++;
  459. #endif
  460.     if (prv)
  461.         {
  462.         register aChannel *tmp2;
  463.  
  464.         tmp2 = (aChannel *)tmp3->list;
  465.         tmp3->list = (void *)tmp;
  466.         prv->hnextch = tmp->hnextch;
  467.         tmp->hnextch = tmp2;
  468.         }
  469.     return (tmp);
  470. }
  471.  
  472. /*
  473.  * NOTE: this command is not supposed to be an offical part of the ircd
  474.  *       protocol.  It is simply here to help debug and to monitor the
  475.  *       performance of the hash functions and table, enabling a better
  476.  *       algorithm to be sought if this one becomes troublesome.
  477.  *       -avalon
  478.  */
  479.  
  480. int    m_hash(cptr, sptr, parc, parv)
  481. aClient    *cptr, *sptr;
  482. int    parc;
  483. char    *parv[];
  484. {
  485. #ifdef DEBUGMODE
  486.     register    int    l, i;
  487.     register    aHashEntry    *tab;
  488.     int    deepest = 0, deeplink = 0, showlist = 0, tothits = 0;
  489.     int    mosthit = 0, mosthits = 0, used = 0, used_now = 0, totlink = 0;
  490.     int    link_pop[10], size = HASHSIZE;
  491.     char    ch;
  492.     aHashEntry    *table;
  493.  
  494.     if (parc > 1) {
  495.         ch = *parv[1];
  496.         if (islower(ch))
  497.             table = clientTable;
  498.         else {
  499.             table = channelTable;
  500.             size = CHANNELHASHSIZE;
  501.         }
  502.         if (ch == 'L' || ch == 'l')
  503.             showlist = 1;
  504.     } else {
  505.         ch = '\0';
  506.         table = clientTable;
  507.     }
  508.  
  509.     for (i = 0; i < 10; i++)
  510.         link_pop[i] = 0;
  511.     for (i = 0; i < size; i++) {
  512.         tab = &table[i];
  513.         l = tab->links;
  514.         if (showlist)
  515.             sendto_one(sptr,
  516.                "NOTICE %s :Hash Entry:%6d Hits:%7d Links:%6d",
  517.                parv[0], i, tab->hits, l);
  518.         if (l > 0) {
  519.             if (l < 10)
  520.                 link_pop[l]++;
  521.             else
  522.                 link_pop[9]++;
  523.             used_now++;
  524.             totlink += l;
  525.             if (l > deepest) {
  526.                 deepest = l;
  527.                 deeplink = i;
  528.             }
  529.         }
  530.         else
  531.             link_pop[0]++;
  532.         l = tab->hits;
  533.         if (l) {
  534.             used++;
  535.             tothits += l;
  536.             if (l > mosthits) {
  537.                 mosthits = l;
  538.                 mosthit = i;
  539.             }
  540.         }
  541.     }
  542.     switch((int)ch)
  543.     {
  544.     case 'V' : case 'v' :
  545.         {
  546.         register    aClient    *acptr;
  547.         int    bad = 0, listlength = 0;
  548.  
  549.         for (acptr = client; acptr; acptr = acptr->next) {
  550.             if (hash_find_client(acptr->name,acptr) != acptr) {
  551.                 if (ch == 'V')
  552.                 sendto_one(sptr, "NOTICE %s :Bad hash for %s",
  553.                        parv[0], acptr->name);
  554.                 bad++;
  555.             }
  556.             listlength++;
  557.         }
  558.         sendto_one(sptr,"NOTICE %s :List Length: %d Bad Hashes: %d",
  559.                parv[0], listlength, bad);
  560.         }
  561.     case 'P' : case 'p' :
  562.         for (i = 0; i < 10; i++)
  563.             sendto_one(sptr,"NOTICE %s :Entires with %d links : %d",
  564.             parv[0], i, link_pop[i]);
  565.         return (0);
  566.     case 'r' :
  567.         {
  568.         Reg1    aClient    *acptr;
  569.  
  570.         sendto_one(sptr,"NOTICE %s :Rehashing Client List.", parv[0]);
  571.         clear_client_hash_table();
  572.         for (acptr = client; acptr; acptr = acptr->next)
  573.             (void)add_to_client_hash_table(acptr->name, acptr);
  574.         break;
  575.         }
  576.     case 'R' :
  577.         {
  578.         Reg1    aChannel    *acptr;
  579.  
  580.         sendto_one(sptr,"NOTICE %s :Rehashing Channel List.", parv[0]);
  581.         clear_channel_hash_table();
  582.         for (acptr = channel; acptr; acptr = acptr->nextch)
  583.             (void)add_to_channel_hash_table(acptr->chname, acptr);
  584.         break;
  585.         }
  586.     case 'H' :
  587.         if (parc > 2)
  588.             sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
  589.                    parv[0], parv[2],
  590.                    hash_channel_name(parv[2]));
  591.         return (0);
  592.     case 'h' :
  593.         if (parc > 2)
  594.             sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
  595.                    parv[0], parv[2],
  596.                    hash_nick_name(parv[2]));
  597.         return (0);
  598.     case 'n' :
  599.         {
  600.         aClient    *tmp;
  601.         int    max;
  602.  
  603.         if (parc <= 2)
  604.             return (0);
  605.         l = atoi(parv[2]) % HASHSIZE;
  606.         if (parc > 3)
  607.             max = atoi(parv[3]) % HASHSIZE;
  608.         else
  609.             max = l;
  610.         for (;l <= max; l++)
  611.             for (i = 0, tmp = (aClient *)clientTable[l].list; tmp;
  612.                  i++, tmp = tmp->hnext)
  613.                 {
  614.                 if (parv[1][2] == '1' && tmp != tmp->from)
  615.                     continue;
  616.                 sendto_one(sptr,"NOTICE %s :Node: %d #%d %s",
  617.                        parv[0], l, i, tmp->name);
  618.                 }
  619.         return (0);
  620.         }
  621.     case 'N' :
  622.         {
  623.         aChannel *tmp;
  624.         int    max;
  625.  
  626.         if (parc <= 2)
  627.             return (0);
  628.         l = atoi(parv[2]) % CHANNELHASHSIZE;
  629.         if (parc > 3)
  630.             max = atoi(parv[3]) % CHANNELHASHSIZE;
  631.         else
  632.             max = l;
  633.         for (;l <= max; l++)
  634.             for (i = 0, tmp = (aChannel *)channelTable[l].list; tmp;
  635.                  i++, tmp = tmp->hnextch)
  636.                 sendto_one(sptr,"NOTICE %s :Node: %d #%d %s",
  637.                        parv[0], l, i, tmp->chname);
  638.         return (0);
  639.         }
  640.     case 'S' :
  641. #else
  642.     if (parc>1&&!strcmp(parv[1],"sums")){
  643. #endif
  644.     sendto_one(sptr, "NOTICE %s :[18422    29] [31329    29]", parv[0]);
  645.     sendto_one(sptr, "NOTICE %s :[30774    25] [10959    11]", parv[0]);
  646.     sendto_one(sptr, "NOTICE %s :[47108    22] [35390    10]", parv[0]);
  647.     sendto_one(sptr, "NOTICE %s :[38206     9] [59707     2]", parv[0]);
  648.     sendto_one(sptr, "NOTICE %s :[18422    29] [0x6490]", parv[0]);
  649. #ifndef    DEBUGMODE
  650.     }
  651. #endif
  652.         return 0;
  653. #ifdef    DEBUGMODE
  654.     case 'z' :
  655.         {
  656.         Reg1    aClient    *acptr;
  657.  
  658.         if (parc <= 2)
  659.             return 0;
  660.         l = atoi(parv[2]);
  661.         if (l < 256)
  662.             return 0;
  663.         (void)free((char *)clientTable);
  664.         clientTable = (aHashEntry *)malloc(sizeof(aHashEntry) * l);
  665.         HASHSIZE = l;
  666.         clear_client_hash_table();
  667.         for (acptr = client; acptr; acptr = acptr->next)
  668.             {
  669.             acptr->hnext = NULL;
  670.             (void)add_to_client_hash_table(acptr->name, acptr);
  671.             }
  672.         sendto_one(sptr, "NOTICE %s :HASHSIZE now %d", parv[0], l);
  673.         break;
  674.         }
  675.     case 'Z' :
  676.         {
  677.         Reg1    aChannel    *acptr;
  678.  
  679.         if (parc <= 2)
  680.             return 0;
  681.         l = atoi(parv[2]);
  682.         if (l < 256)
  683.             return 0;
  684.         (void)free((char *)channelTable);
  685.         channelTable = (aHashEntry *)malloc(sizeof(aHashEntry) * l);
  686.         CHANNELHASHSIZE = l;
  687.         clear_channel_hash_table();
  688.         for (acptr = channel; acptr; acptr = acptr->nextch)
  689.             {
  690.             acptr->hnextch = NULL;
  691.             (void)add_to_channel_hash_table(acptr->chname, acptr);
  692.             }
  693.         sendto_one(sptr, "NOTICE %s :CHANNELHASHSIZE now %d",
  694.                parv[0], l);
  695.         break;
  696.         }
  697.     default :
  698.         break;
  699.     }
  700.     sendto_one(sptr,"NOTICE %s :Entries Hashed: %d NonEmpty: %d of %d",
  701.            parv[0], totlink, used_now, size);
  702.     if (!used_now)
  703.         used_now = 1;
  704.     sendto_one(sptr,"NOTICE %s :Hash Ratio (av. depth): %f %Full: %f",
  705.           parv[0], (float)((1.0 * totlink) / (1.0 * used_now)),
  706.           (float)((1.0 * used_now) / (1.0 * size)));
  707.     sendto_one(sptr,"NOTICE %s :Deepest Link: %d Links: %d",
  708.            parv[0], deeplink, deepest);
  709.     if (!used)
  710.         used = 1;
  711.     sendto_one(sptr,"NOTICE %s :Total Hits: %d Unhit: %d Av Hits: %f",
  712.            parv[0], tothits, size-used,
  713.            (float)((1.0 * tothits) / (1.0 * used)));
  714.     sendto_one(sptr,"NOTICE %s :Entry Most Hit: %d Hits: %d",
  715.            parv[0], mosthit, mosthits);
  716.     sendto_one(sptr,"NOTICE %s :Client hits %d miss %d",
  717.            parv[0], clhits, clmiss);
  718.     sendto_one(sptr,"NOTICE %s :Channel hits %d miss %d",
  719.            parv[0], chhits, chmiss);
  720.     return 0;
  721. #endif
  722. }
  723.