⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 siptranshashtable.cxx

📁 SIP(Session Initiation Protocol)是由IETF定义
💻 CXX
字号:
/* ==================================================================== * The Vovida Software License, Version 1.0  *  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved. *  * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: *  * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. *  * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in *    the documentation and/or other materials provided with the *    distribution. *  * 3. The names "VOCAL", "Vovida Open Communication Application Library", *    and "Vovida Open Communication Application Library (VOCAL)" must *    not be used to endorse or promote products derived from this *    software without prior written permission. For written *    permission, please contact vocal@vovida.org. * * 4. Products derived from this software may not be called "VOCAL", nor *    may "VOCAL" appear in their name, without prior written *    permission of Vovida Networks, Inc. *  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. *  * ==================================================================== *  * This software consists of voluntary contributions made by Vovida * Networks, Inc. and many individuals on behalf of Vovida Networks, * Inc.  For more information on Vovida Networks, Inc., please see * <http://www.vovida.org/>. * */static const char* const SipTransHashTable_cxx_version =    "$Id: SipTransHashTable.cxx,v 1.6 2002/03/19 21:39:55 jason Exp $";#include "global.h"#ifdef __linux__#include <malloc.h>#endif#include "SipTransHashTable.hxx"#include "SipTransDebugger.hxx"using namespace Vocal;#ifndef TARGET_CPS#define TARGET_CPS 50#endif#ifndef SOFTSTATE_SECS#define SOFTSTATE_SECS 20#endif/// this is 2x 'coz of GC's implementation (of swapping)#define OPTIMUM_SIZE 12289static const SipTransHashTable::SizeType primeList[] ={  1,    1543,       3079,         6151,        12289,     24593,  49157,      98317,        0};SipTransHashTable::SipTransHashTable()    :buckets(0),     size(0),     count(0),#ifdef REHASH_THREAD     rehashFlag(false),#endif     rwLock(){#ifdef __linux__    mallopt(M_MMAP_THRESHOLD, 1000*1000);#endif    size = nextSize(OPTIMUM_SIZE);    buckets = new Bucket[size];}SipTransHashTable::~SipTransHashTable(){///// this is NOT clean, will need to GC all the level3 nodes...///// (or may be transaction DB will do it)    for(unsigned int i=0; i<size;i++)    {	Node *curr, *prev;	curr=prev=buckets[i].first;	while(curr)	{	    prev=curr->next;	    delete curr;	    curr=prev;	}    }    delete[] buckets;}SipTransHashTable::SipTransHashTable(SizeType sizeHint)    :buckets(0),     size(0),     count(0),#ifdef REHASH_THREAD     rehashFlag(false),#endif     rwLock(){    size = nextSize(sizeHint);    buckets = new Bucket[size];}SipTransHashTable::SizeTypeSipTransHashTable::nextSize(SizeType sizeHint){    SizeType newSize = primeList[0];     for(int i=1; primeList[i];i++)	if((newSize = primeList[i]) > sizeHint)	    break;    return newSize;}SipTransHashTable::SizeTypeSipTransHashTable::hash(const SipTransactionId::KeyTypeI& key, SizeType size){    // write the hashing function...    // using stl hash function, replace by CLR or something...  SizeType h = 0;   /*******  const char* s = static_cast<const char*>(key.getCStr());  for ( ; *s; ++s)      h = 5*h + *s;  **********/  for(int i=0; i<key.length();i++)    h = 5*h + key.getChar(i);  if(!h) h++; // to ensure size-1  return (h%size);}SipTransHashTable::Node*SipTransHashTable::find(const KeyType& key#ifdef USE_NODE_LOCK			,SipTransRWLockHelper* rwHelper /*defualt arg*/#endif    ){    if(!count) return 0;#ifdef REHASH_THREAD    while(rehashFlag);#endif    SizeType index;    rwLock.ReadLock();    index = hash(key, size);    buckets[index].rwLock.ReadLock();    rwLock.Unlock();    Node* currNode = buckets[index].first;    for(;currNode;currNode=currNode->next)    {	if(key == currNode->keyCopy)	{#ifdef USE_NODE_LOCK	    if(rwHelper)		rwHelper->readLock(&(currNode->rwLock));	    else		currNode->rwLock.ReadLock();#endif	    break;	}    }    buckets[index].rwLock.Unlock();    return currNode;}SipTransHashTable::Node*SipTransHashTable::findOrInsert(const KeyType& key#ifdef USE_NODE_LOCK			,SipTransRWLockHelper* rwHelper /*defualt arg*/#endif    ){#ifdef REHASH_THREAD    while(rehashFlag);#endif    SizeType index;    rwLock.ReadLock();    index = hash(key,size);    buckets[index].rwLock.ReadLock();    rwLock.Unlock();    Node* currNode = buckets[index].first;    int coCount = 0;    for(;currNode;currNode=currNode->next)    {        coCount++;	if(key == currNode->keyCopy)	{#ifdef USE_NODE_LOCK	    if(rwHelper)		rwHelper->readLock(&(currNode->rwLock));	    else		currNode->rwLock.ReadLock();#endif	    break;	}    }    if(!currNode)    {	/// release all the read locks and then try again from hashtable level	/// to acquire write locks	buckets[index].rwLock.Unlock();	rwLock.WriteLock();#ifdef REHASH_THREAD	if(++count >= (size-REHASH_THREASHOLD))#else	if(++count >= size)#endif	{	    rehash(count);	    index = hash(key, size);	}        coCount++;	buckets[index].rwLock.WriteLock();	rwLock.Unlock();	currNode = new Node(key);	currNode->next = buckets[index].first;	currNode->myBucket = buckets+index;	currNode->myTable = this;	buckets[index].first = currNode;#ifdef USE_NODE_LOCK	if(rwHelper)	    rwHelper->writeLock(&(currNode->rwLock));	else	    currNode->rwLock.WriteLock();#endif        if(coCount > 1)        {	   cpLog(LOG_DEBUG,"%s[%s] at bucket #%d, contention list size:%d",	      "contention for Level-I key",	      currNode->keyCopy.logData(),index, coCount);        }    }    buckets[index].rwLock.Unlock();    return currNode;} SipTransHashTable::Node&SipTransHashTable::operator[](const KeyType& key){#ifdef USE_NODE_LOCK    SipTransRWLockHelper helper;    return *findOrInsert(key, &helper);#else    return *findOrInsert(key);#endif}#ifdef USE_NODE_LOCKvoidSipTransHashTable::release(Node* node){    node->rwLock.Unlock();}#endifvoidSipTransHashTable::unLock(Node* node){    node->myBucket->rwLock.Unlock();}voidSipTransHashTable::lock(Node* node, SipTransRWLockHelper *helper /*default*/){    rwLock.WriteLock();    Bucket* bucketPtr = node->myBucket;    if(helper)	helper->writeLock(&bucketPtr->rwLock);    else	bucketPtr->rwLock.WriteLock();#ifdef REHASH_THREAD    /// we do another read of bucketPtr to refresh the latest value    /// after getting the lock.    /// (it might have been changed by rehash while we were waiting    /// on the old value)    if( bucketPtr != node->myBucket)    {//////////// this whole thing is wrong, works with dangling pointers!!!////////////////////////////////////////////////////////////////////////	if(helper)	{	    helper->rwLockPtr=0;	}	bucketPtr->rwLock.Unlock();		bucketPtr = node->myBucket;	if(helper)	    helper->writeLock(&bucketPtr->rwLock);	else	    bucketPtr->rwLock.WriteLock();    }#endif    rwLock.Unlock();}voidSipTransHashTable::erase(Node* node){    if(!node || !count) return;    rwLock.WriteLock();/**************************************************************************\ * this being done in two steps, so lock does the job...    Bucket* bucketPtr = node->myBucket;    bucketPtr->rwLock.WriteLock();#ifdef REHASH_THREAD    /// we do another read of bucketPtr to refresh the latest value    /// after getting the lock.    /// (it might have been changed by rehash while we were waiting    /// on the old value)    if( bucketPtr != node->myBucket)    {	bucketPtr->rwLock.Unlock();	bucketPtr = node->myBucket;	bucketPtr->rwLock.WriteLock();    }#endif\**************************************************************************/    /// we assume that most of the erase would be legal calls, hence we    /// decrement the count in advance. note that it is safe to do this    /// 'coz this is the only method that decreases count value (and in    /// case of bad call it restores). this helps in avoiding an extra    /// hash table lock    count--;    rwLock.Unlock();    Node** prevNodePtr = &(node->myBucket->first);    Node* currNode = *prevNodePtr;    for(;currNode;)    {	/// yes this is a direct address comparision!!!	if(currNode == node)	{	    *prevNodePtr = currNode->next;	    cpLog(DEBUG_NEW_STACK,"erasing top node[%s]",		  node->keyCopy.logData());	    delete node;	    break;	}	else	{	    prevNodePtr = &(currNode->next);	    currNode = currNode->next;	}    }/****************************************************************\    bucketPtr->rwLock.Unlock();\****************************************************************/    /// if this was a BAD call    if(!currNode)    {	cpLog(DEBUG_NEW_STACK,"*********** BAD CALL TO ERASE #$%!");	rwLock.WriteLock();	count++;	rwLock.Unlock();    }}voidSipTransHashTable::rehash(SizeType sizeHint){#ifdef REHASH_THREAD    if(rehashFlag != true)    {	rehashFlag = true;	/// spawn the rehash thread...    }#else    rehashFunc(sizeHint);#endif}voidSipTransHashTable::rehashFunc(SizeType sizeHint){/*************************************************************************\ * for now this is fine, 'coz the whole table is locked during the whole * operation. but with threaded rehash *might* have to lock the node also * to avoid incorrect execution with lock. */    sizeHint = nextSize(sizeHint);    if(sizeHint <= size) return;    cpLog(DEBUG_NEW_STACK,"%srehashing from %d (old size) to %d...%s",	  "##########################################\n",	  size,sizeHint,	  "\n##########################################");    Bucket* newBuckets = new Bucket[sizeHint];    unsigned int i;    for(i=0;i<size;i++)    {	Node* currNode;	Node** prevNodePtr;	SizeType newIndex;#ifdef REHASH_THREAD		/// lock table when its a thread, to take care of race conditions	rwLock.WriteLock();#endif	/// this allways needs to be there, even when this is not a thread,	/// to take care of slow execution sequences of other methods	buckets[i].rwLock.WriteLock();#ifdef REHASH_THREAD	rwLock.Unlock();#endif	prevNodePtr = &(buckets[i].first);	currNode = *prevNodePtr;	for(;currNode;)	{	    *prevNodePtr = currNode->next;	    newIndex = hash(currNode->keyCopy,sizeHint);#ifdef REHASH_THREAD	    /// this is to take care of any conflicts with erase	    /// but will only be useful if rehash is implemented as	    /// a sperate thread. otherwise the whole table is locked anyway	    /// by the caller. another option is to lock all initially	     newBuckets[newIndex].rwLock.WriteLock();#endif	    currNode->next = newBuckets[newIndex].first;	    currNode->myBucket = newBuckets+newIndex;	    newBuckets[newIndex].first = currNode;#ifdef REHASH_THREAD	    newBuckets[newIndex].rwLock.Unlock();#endif	    currNode = *prevNodePtr;	}	buckets[i].rwLock.Unlock();    }#ifdef REHASH_THREAD    rwLock.WriteLock();#endif    delete[] buckets;    buckets = newBuckets;    size = sizeHint;#ifdef REHASH_THREAD    rehashFlag = false;    rwLock.Unlock();#endif}DataSipTransHashTable::giveDetails(){    return SipTransDebugger::printDebug(this);}/* Local Variables: *//* c-file-style: "stroustrup" *//* indent-tabs-mode: nil *//* c-file-offsets: ((access-label . -) (inclass . ++)) *//* c-basic-offset: 4 *//* End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -