/****************************************************************************/
/* */
/* Program name: MQIsdp protocol C Language implementation */
/* */
/* Description: This source file contains functions for managing hash */
/* tables and linked lists. */
/* */
/* Statement: Licensed Materials - Property of IBM */
/* */
/* MQSeries SupportPac IA93 */
/* (C) Copyright IBM Corp. 2002 */
/* */
/****************************************************************************/
/* Version @(#) IA93/ship/msphash.c, SupportPacs, S000 1.3 03/11/28 16:43:45 */
/* */
/* Function: */
/* */
/* Both queues for sending and receiving data to/from the broker are */
/* implemented as linked lists and are hashed. */
/* */
/****************************************************************************/
/* */
/* Change history: */
/* */
/* V1.0 19-02-2003 IRH Initial release */
/* */
/*==========================================================================*/
/* Module Name: msphash.c */
#include <mspdmn.h>
int mspCalcHashCode( MHASHT* pHash, short msgId );
/* Create a hash table with the specified number of keys */
MHASHT *mspInitHash( HCONNCB *pHconn, int nKeys ) {
MHASHT *pHash = NULL;
int hashSz = 0;
if ( nKeys > 0 ) {
hashSz = sizeof(MHASHT) + ((nKeys - 1 )*sizeof(MHASHENTRY*));
pHash = (MHASHT*)mspMalloc( &(pHconn->comParms), hashSz );
if ( pHash != NULL ) {
memset( pHash, 0, hashSz );
pHash->nKeys = nKeys;
}
}
return pHash;
}
/* Delete the identified hash table */
void mspTermHash( HCONNCB *pHconn, MHASHT *pHash ) {
MHASHENTRY *pCurEntry, *pNextEntry;
int k;
int hashSz = 0;
for ( k=0; k < pHash->nKeys; k++ ) {
pCurEntry = pHash->pKeys[k];
while ( pCurEntry != NULL ) {
pNextEntry = pCurEntry->Next;
mspFree( &(pHconn->comParms), pCurEntry, sizeof(MHASHENTRY) );
pCurEntry = pNextEntry;
}
}
hashSz = sizeof(MHASHT) + ((pHash->nKeys - 1 )*sizeof(MHASHENTRY*));
mspFree( &(pHconn->comParms), pHash, hashSz );
}
/* Add an entry to a hash table, where msgId is the hash key */
int mspAddToHash( HCONNCB *pHconn, MHASHT* pHash, short msgId, void *dataPtr ) {
int hCode;
MHASHENTRY *pCurEntry;
/* Avoid duplicate entries */
mspDelFromHash( pHconn, pHash, msgId );
/* Calculate the hash code */
hCode = mspCalcHashCode( pHash, msgId );
pCurEntry = (MHASHENTRY*)mspMalloc( &(pHconn->comParms), sizeof(MHASHENTRY) );
if ( pCurEntry == NULL ) {
return 1;
}
/* Add the current entry to the beginning of the list */
/* Set next of the new entry to be current beginning of the list */
/* Set the prev of current beginning of the list to be the new entry */
if ( pHash->pKeys[hCode] != NULL ) {
pCurEntry->Next = pHash->pKeys[hCode];
pHash->pKeys[hCode]->Prev = pCurEntry;
} else {
pCurEntry->Next = NULL;
}
/* Set the new entry to be the beginning of the list */
pHash->pKeys[hCode] = pCurEntry;
pCurEntry->msgId = msgId;
pCurEntry->dataPtr = dataPtr;
pCurEntry->Prev = NULL;
return 0;
}
/* Read an entry from a hash table, as identified by hash key msgId */
void* mspReadFromHash( MHASHT* pHash, short msgId ) {
MHASHENTRY* pCurEntry;
int hCode;
hCode = mspCalcHashCode( pHash, msgId );
for( pCurEntry = pHash->pKeys[hCode]; pCurEntry != NULL; pCurEntry = pCurEntry->Next )
{
if( pCurEntry->msgId == msgId ) {
return( pCurEntry->dataPtr );
}
}
return(NULL);
}
#if 0
/* This is a useful debug function if the contents of a hash table need to be dumped */
int mspDumpHash( MHASHT* pHash ) {
MHASHENTRY* pCurEntry;
int hCode;
for ( hCode = 0; hCode < pHash->nKeys; hCode++ ) {
for( pCurEntry = pHash->pKeys[hCode]; pCurEntry != NULL; pCurEntry = pCurEntry->Next )
{
printf( "MSGID :%d\n", pCurEntry->msgId );
printf( "DATAPTR:%p\n", pCurEntry->dataPtr );
}
}
return 0;
}
#endif
/* Get a complete entry from a hash table, as identified by hash key msgId */
MHASHENTRY* mspGetHashEntry( MHASHT* pHash, short msgId ) {
MHASHENTRY* pCurEntry;
int hCode;
hCode = mspCalcHashCode( pHash, msgId );
for( pCurEntry = pHash->pKeys[hCode]; pCurEntry != NULL; pCurEntry = pCurEntry->Next )
{
if( pCurEntry->msgId == msgId ) {
return( pCurEntry );
}
}
return(NULL);
}
/* Delete an entry from a hash table, as identified by hash key msgId */
void mspDelFromHash( HCONNCB *pHconn, MHASHT* pHash, short msgId ) {
MHASHENTRY *pCurEntry, *next, *prev;
int hCode;
hCode = mspCalcHashCode( pHash, msgId );
for( pCurEntry = pHash->pKeys[hCode]; pCurEntry != NULL; pCurEntry = pCurEntry->Next )
{
if( pCurEntry->msgId == msgId ) {
prev = pCurEntry->Prev;
next = pCurEntry->Next;
if ( prev != NULL ) {
prev->Next = next;
} else {
/* Deleting the first in the chain */
pHash->pKeys[hCode] = next;
}
if ( next != NULL ) {
next->Prev = prev;
}
mspFree( &(pHconn->comParms), pCurEntry, sizeof(MHASHENTRY) );
return;
}
}
}
/* Calculate the hash value from the key */
int mspCalcHashCode( MHASHT* pHash, short msgId ) {
int hc, j;
char* pcMsgId;
pcMsgId = (char*)&msgId;
/* For each byte of memory in data to be hashed */
for( hc=0, j=0; j < sizeof(short); pcMsgId++, j++ )
{
/* The hash code is the current value of the hash code multiplied */
/* by 131 plus the current value of the byte we are looking at */
hc = 131*hc + *pcMsgId;
}
/* hc is between 0 and the number of hashkeys - 1 */
hc = abs(hc)%pHash->nKeys;
return( hc );
}
/* Functions for Adding and Deleting an 'in progress message' to/from the InProgressQ linked list */
IPQ* mspAddIPMToList( HCONNCB *pHconn, long dataLen, void *msgData, short msgId ){
IPQ *ipqEntry = NULL;
ipqEntry = (IPQ*)mspMalloc( &(pHconn->comParms), sizeof(IPQ) );
if ( ipqEntry != NULL ) {
ipqEntry->msgData = msgData;
ipqEntry->msgLength = dataLen;
ipqEntry->msgId = msgId;
ipqEntry->flags = 0;
ipqEntry->msgStatus = MQISDP_IN_PROGRESS;
ipqEntry->Next = NULL;
switch ( (*(char*)msgData) & MSP_FH_GET_QOS ) {
case 0:
ipqEntry->flags |= MSP_IPQ_QOS_0 ;
break;
case 1:
ipqEntry->flags |= MSP_IPQ_QOS_1 ;
break;
case 2:
ipqEntry->flags |= MSP_IPQ_QOS_2 ;
break;
}
/* Add entries to the end of the list so that they are in the order sent */
/* incase any retries are required. */
if ( pHconn->outQ.inProgressQ == NULL ) {
pHconn->outQ.inProgressQ = ipqEntry;
ipqEntry->Prev = NULL;
} else {
ipqEntry->Prev = pHconn->outQ.pLastEntry;
pHconn->outQ.pLastEntry->Next = ipqEntry;
}
pHconn->outQ.pLastEntry = ipqEntry;
pHconn->outQ.ipEntries++;
pHconn->outQ.numBytesQueued += sizeof(IPQ) + ipqEntry->msgLength;
}
return ipqEntry;
}
int mspDeleteIPMFromList( HCONNCB *pHconn, IPQ* delEntry ){
IPQ *prev, *next;
if ( delEntry != NULL ) {
prev = delEntry->Prev;
next = delEntry->Next;
if ( prev != NULL ) {
prev->Next = next;
} else {
/* Deleting the first in the chain */
pHconn->outQ.inProgressQ = next;
}
if ( next != NULL ) {
next->Prev = prev;
} else {
/* Deleting the last entry, so move the last entry */
/* pointer to the previous entry */
pHconn->outQ.pLastEntry = prev;
}
pHconn->outQ.ipEntries--;
pHconn->outQ.numBytesQueued -= (delEntry->msgLength + sizeof(IPQ));
if ( pHconn->outQ.ipEntries == 0 ) {
pHconn->outQ.pLastEntry = NULL;
}
if ( delEntry->msgData != NULL ) {
mspFree( &(pHconn->comParms), delEntry->msgData, delEntry->msgLength );
}
mspFree( &(pHconn->comParms), delEntry, sizeof(IPQ) );
}
return 0;
}
/* Functions for Adding and Deleting a publication to/from the RcvdPubsQ linked list */
int mspAddRPMToList( HCONNCB *pHconn, RPQ *newEntry ){
int rc = 0;
if ( newEntry != NULL ) {
newEntry->Next = NULL;
/* Add entries to the end of the list so that they are in the order received */
if ( pHconn->inQ.rcvdPubsQ == NULL ) {
pHconn->inQ.rcvdPubsQ = newEntry;
newEntry->Prev = NULL;
} else {
newEntry->Prev = pHconn->inQ.pLastEntry;
pHconn->inQ.pLastEntry->Next = newEntry;
}
pHconn->inQ.pLastEntry = newEntry;
if ( newEntry->readyToPublish == MQISDP_RELEASED ) {
if ( pHconn->inQ.rtpEntries == 0 ) {
/* If the publications available to receive changes */
/* from 0 to 1 signal the receive semaphore. */
mspSignalSemaphore( pHconn->ipcCb.receiveSemaphore );
}
pHconn->inQ.rtpEntries++;
}
pHconn->inQ.numBytesQueued += sizeof(RPQ) + newEntry->bufferLength;
}
return rc;
}
int mspDeleteRPMFromList( HCONNCB *pHconn, RPQ* delEntry ){
RPQ *prev, *next;
if ( delEntry != NULL ) {
prev = delEntry->Prev;
next = delEntry->Next;
if ( prev != NULL ) {
prev->Next = next;
} else {
/* Deleting the first in the chain */
pHconn->inQ.rcvdPubsQ = next;
}
if ( next != NULL ) {
next->Prev = prev;
} else {
/* Deleting the last entry, so move the last entry */
/* pointer to the previous entry */
pHconn->inQ.pLastEntry = prev;
}
if ( delEntry->readyToPublish == MQISDP_RELEASED ) {
pHconn->inQ.rtpEntries--;
}
pHconn->inQ.numBytesQueued -= (delEntry->bufferLength + sizeof(RPQ));
if ( delEntry->buffer != NULL ) {
mspFree( &(pHconn->comParms), delEntry->buffer, delEntry->bufferLength );
}
mspFree( &(pHconn->comParms), delEntry, sizeof(RPQ) );
}
return 0;
}