hashTable.c

Go to the documentation of this file.
00001 /*
00002  * $Id: hashTable.c 4764 2008-08-28 14:41:06Z henningw $
00003  *
00004  * SNMPStats Module 
00005  * Copyright (C) 2006 SOMA Networks, INC.
00006  * Written by: Jeffrey Magder (jmagder@somanetworks.com)
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify it
00011  * under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023  * USA
00024  *
00025  * History:
00026  * --------
00027  * 2006-11-23 initial version (jmagder)
00028  *
00029  * Hash Stuff;
00030  */
00031 
00032 /*!
00033  * \file
00034  * \brief SNMP statistic module, hash table
00035  *
00036  * For an overview of its structures, please see hashTable.h
00037  *
00038  * Potential Performance Improvements: Pass the length of the aor strings around
00039  * everywhere, so we don't have to calculate it ourselves.
00040  * \ingroup snmpstats
00041  * - Module: \ref snmpstats
00042  */
00043 
00044 #include <stdlib.h>
00045 #include <string.h>
00046 
00047 #include "hashTable.h"
00048 #include "../../dprint.h"
00049 #include "../../mem/mem.h"
00050 
00051 #include <net-snmp/net-snmp-config.h>
00052 #include <net-snmp/net-snmp-includes.h>
00053 #include <net-snmp/agent/net-snmp-agent-includes.h>
00054 #include "openserSIPRegUserTable.h"
00055 
00056 
00057 /*! Calculates and returns a hash index to a hash table.  The index is calculated
00058  * by summing up all the characters specified with theString, and using the
00059  * hashTableSize as the modulus.  */
00060 int calculateHashSlot(char *theString, int hashTableSize) 
00061 {
00062    char *currentCharacter = theString;
00063    int   runningTotal     = 0;
00064 
00065    while (*currentCharacter != '\0') {
00066       runningTotal += *currentCharacter;
00067       currentCharacter++;
00068    }
00069 
00070    return runningTotal % hashTableSize;
00071 }
00072 
00073 /*! Searches the hash table specified as theTable, of size 'size', for a record
00074  * indexed with 'aor'.  If a match is found, then an aorToIndextStruct_t
00075  * structure is returned. 
00076  *
00077  * This function is called to discover the map between OpenSER's "aor" 
00078  * (Address of Records) indexing scheme, and the SNMPStats modules integer
00079  * indexing scheme for its contact/user data. 
00080  *
00081  * Returns: the aorToIndexStruct_t mapping structure if a match was found, 
00082  *          or NULL otherwise.
00083  */
00084 aorToIndexStruct_t *findHashRecord(hashSlot_t *theTable, char *aor, int size)
00085 {
00086    int hashIndex = calculateHashSlot(aor, size);
00087    int aorStringLength = strlen(aor);
00088 
00089    aorToIndexStruct_t *currentRecord = theTable[hashIndex].first;
00090 
00091    while (currentRecord != NULL) {
00092       
00093       /* If the strings are the same length and the same in every
00094        * other way, then return the given record. */
00095       if (currentRecord->aorLength == aorStringLength &&
00096           memcmp(currentRecord->aor, aor, aorStringLength)==0) {
00097          return currentRecord;
00098       }
00099 
00100       currentRecord = currentRecord->next;
00101    }
00102 
00103    return NULL;
00104 }
00105 
00106 
00107 /*! Returns a chunk of memory large enough to store 'size' hashSlot's.  The
00108  * table will contain mappings between OpenSER's "aor" user/contact indexing
00109  * scheme, and SNMPStats integer indexing scheme */
00110 hashSlot_t  *createHashTable(int size) 
00111 {
00112    hashSlot_t *hashTable     = NULL;
00113    int         numberOfBytes = sizeof(hashSlot_t)*size;
00114 
00115    hashTable = pkg_malloc(numberOfBytes);
00116 
00117    if (!hashTable)
00118    {
00119       LM_ERR("no more pkg memory");
00120       return NULL;
00121    }
00122 
00123    memset(hashTable, 0, numberOfBytes);
00124 
00125    return hashTable;
00126 }
00127 
00128 
00129 /*! Inserts the record specified with 'theRecord' into our hash table. */
00130 void insertHashRecord(hashSlot_t *theTable, aorToIndexStruct_t *theRecord, 
00131       int size) 
00132 {
00133    int hashIndex = calculateHashSlot(theRecord->aor, size);
00134 
00135    /* Link up this record backward so that it points to whatever the last
00136     * 'last element' was.  */
00137    theRecord->prev = theTable[hashIndex].last;
00138 
00139    /* This is the first record in the hash table, so assign the first and
00140     * last pointers to this record. */
00141    if (theTable[hashIndex].last == NULL) {
00142       
00143       theTable[hashIndex].last  = theRecord;
00144       theTable[hashIndex].first = theRecord;
00145 
00146    } else {
00147       
00148       /* Make the element that was previously the last element point
00149        * to this new record, as its next element. */
00150       theTable[hashIndex].last->next = theRecord;
00151 
00152       /* Reassign the 'final element' pointer to this new record. */
00153       theTable[hashIndex].last = theRecord;
00154 
00155    }
00156    
00157 }
00158 
00159 /*!
00160  * This function will search the provided hash table for an entry indexed by
00161  * 'aor'.  If an entry is found then: 
00162  *
00163  *   - Its numContacts counter will be decremented.
00164  *   - If its numContacts counter reaches zero, then the entry will be removed
00165  *     from the hash table.
00166  *
00167  */
00168 void deleteUser(hashSlot_t *theTable, char *aor, int hashTableSize)
00169 {
00170    int hashIndex = calculateHashSlot(aor, hashTableSize);
00171    int searchStringLength = strlen(aor);
00172 
00173    aorToIndexStruct_t *previousRecord = theTable[hashIndex].first;
00174    aorToIndexStruct_t *currentRecord  = theTable[hashIndex].first;
00175 
00176    while (currentRecord != NULL) {
00177 
00178       /* First make sure both strings are the same length.  If so,
00179        * then compare all bytes.  If this succeeds, then we need to
00180        * link up the previous and next element together. */
00181       if (currentRecord->aorLength == searchStringLength &&
00182           memcmp(currentRecord->aor, aor, searchStringLength) == 0) {
00183 
00184          currentRecord->numContacts--;
00185 
00186          /* There are still contacts relying on this user, so
00187           * don't delete anything. */
00188          if (currentRecord->numContacts > 0) 
00189          {
00190             return;
00191          }
00192 
00193          /* There are no more contacts relying on this user, so
00194           * delete the row from the table. */
00195          deleteRegUserRow(currentRecord->userIndex);
00196 
00197 
00198          /* Maintenance of the hash table */
00199 
00200          if (currentRecord->prev == NULL) 
00201          {
00202                /* Edge Case: First element in list was just deleted, so set
00203                 * up the first element to point to the one after the one
00204                 * just deleted */
00205                theTable[hashIndex].first = currentRecord->next;
00206          }
00207          else
00208          {
00209                /* Not the first element, so hook up the previous node to
00210                 * the node after the one just deleted. */
00211                currentRecord->prev->next = currentRecord->next;
00212          }
00213 
00214          if (currentRecord->next == NULL)
00215          {
00216                /* Edge Case: The last element has been targetted for
00217                 * deletion.  So move the pointer to the node just before
00218                 * this one.  */
00219                theTable[hashIndex].last = currentRecord->prev;
00220          }
00221          else
00222          {
00223                /* Not the last element, so hook up next nodes previous
00224                 * element to this nodes previous.  */
00225                currentRecord->next->prev = currentRecord->prev;
00226          }
00227 
00228          pkg_free(currentRecord);
00229 
00230          /* We are done, so just return. */
00231          return;
00232       }
00233 
00234       /* Advance to the next records. */
00235       previousRecord = currentRecord;
00236       currentRecord = currentRecord->next;
00237    }
00238 
00239 }
00240 
00241 
00242 /*! Returns a aorToIndexStruct_t, holding the given 'userIndex' and 'aor'.  The
00243  * structure is used to map between the "aor" (OpenSER's way of indexing
00244  * users/contacts), and the SNMPStats user and contact integer indexes.  
00245  *
00246  * NOTE: that this record does not make a copy of aor, but instead points
00247  * directly to the parameter.  Therefore make sure that aor is not on the stack,
00248  * and is not going to disappear before this record is deleted. 
00249  */
00250 aorToIndexStruct_t *createHashRecord(int userIndex, char *aor) 
00251 {
00252    int aorLength =strlen(aor);
00253 
00254     aorToIndexStruct_t *theRecord = pkg_malloc(sizeof(aorToIndexStruct_t)+
00255             (aorLength+1)* sizeof(char));
00256    if (theRecord == NULL)
00257    {
00258       LM_ERR("failed to create a mapping record for %s", aor);
00259       return NULL;
00260    }
00261 
00262    memset(theRecord, 0, sizeof(aorToIndexStruct_t));
00263 
00264    theRecord->aor = (char*)theRecord + sizeof(aorToIndexStruct_t);
00265     memcpy(theRecord->aor, aor, aorLength );
00266    theRecord->aor[aorLength] = '\0';
00267     theRecord->aorLength = aorLength;
00268    theRecord->userIndex = userIndex;
00269    theRecord->numContacts = 1;
00270 
00271    return theRecord;
00272 }
00273 
00274 
00275 
00276 
00277 /*! Debugging function.  Prints off an entire hash slot. */
00278 void printHashSlot(hashSlot_t *theTable, int index) 
00279 {
00280    aorToIndexStruct_t *currentRecord = theTable[index].first;
00281 
00282    LM_ERR("dumping Hash Slot #%d\n", index);
00283 
00284    while (currentRecord != NULL) {
00285       LM_ERR( "\tString: %s - Index: %d\n", 
00286             currentRecord->aor, currentRecord->userIndex);
00287       currentRecord = currentRecord->next;
00288    }
00289 }

Generated on Wed May 23 06:00:46 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6