blob: 260365375ed9e384ff48f31ca7f15a65009cc902 [file] [log] [blame]
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* pkix_pl_hashtable.c
*
* Hashtable Object Functions
*
*/
#include "pkix_pl_hashtable.h"
/* --Private-Structure-------------------------------------------- */
struct PKIX_PL_HashTableStruct {
pkix_pl_PrimHashTable *primHash;
PKIX_PL_Mutex *tableLock;
PKIX_UInt32 maxEntriesPerBucket;
};
/* --Private-Functions-------------------------------------------- */
#define PKIX_MUTEX_UNLOCK(mutex) \
do { \
if (mutex && lockedMutex == (PKIX_PL_Mutex *)(mutex)) { \
pkixTempResult = \
PKIX_PL_Mutex_Unlock((mutex), plContext); \
PORT_Assert(pkixTempResult == NULL); \
if (pkixTempResult) { \
PKIX_DoAddError(&stdVars, pkixTempResult, plContext); \
pkixTempResult = NULL; \
} \
lockedMutex = NULL; \
} else { \
PORT_Assert(lockedMutex == NULL); \
}\
} while (0)
#define PKIX_MUTEX_LOCK(mutex) \
do { \
if (mutex){ \
PORT_Assert(lockedMutex == NULL); \
PKIX_CHECK(PKIX_PL_Mutex_Lock((mutex), plContext), \
PKIX_MUTEXLOCKFAILED); \
lockedMutex = (mutex); \
} \
} while (0)
/*
* FUNCTION: pkix_pl_HashTable_Destroy
* (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_pl_HashTable_Destroy(
PKIX_PL_Object *object,
void *plContext)
{
PKIX_PL_HashTable *ht = NULL;
pkix_pl_HT_Elem *item = NULL;
PKIX_UInt32 i;
PKIX_ENTER(HASHTABLE, "pkix_pl_HashTable_Destroy");
PKIX_NULLCHECK_ONE(object);
PKIX_CHECK(pkix_CheckType(object, PKIX_HASHTABLE_TYPE, plContext),
PKIX_OBJECTNOTHASHTABLE);
ht = (PKIX_PL_HashTable*) object;
/* DecRef every object in the primitive hash table */
for (i = 0; i < ht->primHash->size; i++) {
for (item = ht->primHash->buckets[i];
item != NULL;
item = item->next) {
PKIX_DECREF(item->key);
PKIX_DECREF(item->value);
}
}
PKIX_CHECK(pkix_pl_PrimHashTable_Destroy(ht->primHash, plContext),
PKIX_PRIMHASHTABLEDESTROYFAILED);
PKIX_DECREF(ht->tableLock);
cleanup:
PKIX_RETURN(HASHTABLE);
}
/*
* FUNCTION: pkix_pl_HashTable_RegisterSelf
* DESCRIPTION:
* Registers PKIX_HASHTABLE_TYPE and its related functions with systemClasses[]
* THREAD SAFETY:
* Not Thread Safe - for performance and complexity reasons
*
* Since this function is only called by PKIX_PL_Initialize, which should
* only be called once, it is acceptable that this function is not
* thread-safe.
*/
PKIX_Error *
pkix_pl_HashTable_RegisterSelf(
void *plContext)
{
extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
pkix_ClassTable_Entry entry;
PKIX_ENTER(HASHTABLE, "pkix_pl_HashTable_RegisterSelf");
entry.description = "HashTable";
entry.objCounter = 0;
entry.typeObjectSize = sizeof(PKIX_PL_HashTable);
entry.destructor = pkix_pl_HashTable_Destroy;
entry.equalsFunction = NULL;
entry.hashcodeFunction = NULL;
entry.toStringFunction = NULL;
entry.comparator = NULL;
entry.duplicateFunction = NULL;
systemClasses[PKIX_HASHTABLE_TYPE] = entry;
PKIX_RETURN(HASHTABLE);
}
/* --Public-Functions------------------------------------------------------- */
/*
* FUNCTION: PKIX_PL_HashTable_Create (see comments in pkix_pl_system.h)
*/
PKIX_Error *
PKIX_PL_HashTable_Create(
PKIX_UInt32 numBuckets,
PKIX_UInt32 maxEntriesPerBucket,
PKIX_PL_HashTable **pResult,
void *plContext)
{
PKIX_PL_HashTable *hashTable = NULL;
PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Create");
PKIX_NULLCHECK_ONE(pResult);
if (numBuckets == 0) {
PKIX_ERROR(PKIX_NUMBUCKETSEQUALSZERO);
}
/* Allocate a new hashtable */
PKIX_CHECK(PKIX_PL_Object_Alloc
(PKIX_HASHTABLE_TYPE,
sizeof (PKIX_PL_HashTable),
(PKIX_PL_Object **)&hashTable,
plContext),
PKIX_COULDNOTCREATEHASHTABLEOBJECT);
/* Create the underlying primitive hash table type */
PKIX_CHECK(pkix_pl_PrimHashTable_Create
(numBuckets, &hashTable->primHash, plContext),
PKIX_PRIMHASHTABLECREATEFAILED);
/* Create a lock for this table */
PKIX_CHECK(PKIX_PL_Mutex_Create(&hashTable->tableLock, plContext),
PKIX_ERRORCREATINGTABLELOCK);
hashTable->maxEntriesPerBucket = maxEntriesPerBucket;
*pResult = hashTable;
cleanup:
if (PKIX_ERROR_RECEIVED){
PKIX_DECREF(hashTable);
}
PKIX_RETURN(HASHTABLE);
}
/*
* FUNCTION: PKIX_PL_HashTable_Add (see comments in pkix_pl_system.h)
*/
PKIX_Error *
PKIX_PL_HashTable_Add(
PKIX_PL_HashTable *ht,
PKIX_PL_Object *key,
PKIX_PL_Object *value,
void *plContext)
{
PKIX_PL_Mutex *lockedMutex = NULL;
PKIX_PL_Object *deletedKey = NULL;
PKIX_PL_Object *deletedValue = NULL;
PKIX_UInt32 hashCode;
PKIX_PL_EqualsCallback keyComp;
PKIX_UInt32 bucketSize = 0;
PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Add");
#if !defined(PKIX_OBJECT_LEAK_TEST)
PKIX_NULLCHECK_THREE(ht, key, value);
#else
PKIX_NULLCHECK_TWO(key, value);
if (ht == NULL) {
PKIX_RETURN(HASHTABLE);
}
#endif
/* Insert into primitive hashtable */
PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext),
PKIX_OBJECTHASHCODEFAILED);
PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback
(key, &keyComp, plContext),
PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED);
PKIX_MUTEX_LOCK(ht->tableLock);
PKIX_CHECK(pkix_pl_PrimHashTable_GetBucketSize
(ht->primHash,
hashCode,
&bucketSize,
plContext),
PKIX_PRIMHASHTABLEGETBUCKETSIZEFAILED);
if (ht->maxEntriesPerBucket != 0 &&
bucketSize >= ht->maxEntriesPerBucket) {
/* drop the last one in the bucket */
PKIX_CHECK(pkix_pl_PrimHashTable_RemoveFIFO
(ht->primHash,
hashCode,
(void **) &deletedKey,
(void **) &deletedValue,
plContext),
PKIX_PRIMHASHTABLEGETBUCKETSIZEFAILED);
PKIX_DECREF(deletedKey);
PKIX_DECREF(deletedValue);
}
PKIX_CHECK(pkix_pl_PrimHashTable_Add
(ht->primHash,
(void *)key,
(void *)value,
hashCode,
keyComp,
plContext),
PKIX_PRIMHASHTABLEADDFAILED);
PKIX_INCREF(key);
PKIX_INCREF(value);
PKIX_MUTEX_UNLOCK(ht->tableLock);
/*
* we don't call PKIX_PL_InvalidateCache here b/c we have
* not implemented toString or hashcode for this Object
*/
cleanup:
PKIX_MUTEX_UNLOCK(ht->tableLock);
PKIX_RETURN(HASHTABLE);
}
/*
* FUNCTION: PKIX_PL_HashTable_Remove (see comments in pkix_pl_system.h)
*/
PKIX_Error *
PKIX_PL_HashTable_Remove(
PKIX_PL_HashTable *ht,
PKIX_PL_Object *key,
void *plContext)
{
PKIX_PL_Mutex *lockedMutex = NULL;
PKIX_PL_Object *origKey = NULL;
PKIX_PL_Object *value = NULL;
PKIX_UInt32 hashCode;
PKIX_PL_EqualsCallback keyComp;
PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Remove");
#if !defined(PKIX_OBJECT_LEAK_TEST)
PKIX_NULLCHECK_TWO(ht, key);
#else
PKIX_NULLCHECK_ONE(key);
if (ht == NULL) {
PKIX_RETURN(HASHTABLE);
}
#endif
PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext),
PKIX_OBJECTHASHCODEFAILED);
PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback
(key, &keyComp, plContext),
PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED);
PKIX_MUTEX_LOCK(ht->tableLock);
/* Remove from primitive hashtable */
PKIX_CHECK(pkix_pl_PrimHashTable_Remove
(ht->primHash,
(void *)key,
hashCode,
keyComp,
(void **)&origKey,
(void **)&value,
plContext),
PKIX_PRIMHASHTABLEREMOVEFAILED);
PKIX_MUTEX_UNLOCK(ht->tableLock);
PKIX_DECREF(origKey);
PKIX_DECREF(value);
/*
* we don't call PKIX_PL_InvalidateCache here b/c we have
* not implemented toString or hashcode for this Object
*/
cleanup:
PKIX_MUTEX_UNLOCK(ht->tableLock);
PKIX_RETURN(HASHTABLE);
}
/*
* FUNCTION: PKIX_PL_HashTable_Lookup (see comments in pkix_pl_system.h)
*/
PKIX_Error *
PKIX_PL_HashTable_Lookup(
PKIX_PL_HashTable *ht,
PKIX_PL_Object *key,
PKIX_PL_Object **pResult,
void *plContext)
{
PKIX_PL_Mutex *lockedMutex = NULL;
PKIX_UInt32 hashCode;
PKIX_PL_EqualsCallback keyComp;
PKIX_PL_Object *result = NULL;
PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Lookup");
#if !defined(PKIX_OBJECT_LEAK_TEST)
PKIX_NULLCHECK_THREE(ht, key, pResult);
#else
PKIX_NULLCHECK_TWO(key, pResult);
if (ht == NULL) {
PKIX_RETURN(HASHTABLE);
}
#endif
PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext),
PKIX_OBJECTHASHCODEFAILED);
PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback
(key, &keyComp, plContext),
PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED);
PKIX_MUTEX_LOCK(ht->tableLock);
/* Lookup in primitive hashtable */
PKIX_CHECK(pkix_pl_PrimHashTable_Lookup
(ht->primHash,
(void *)key,
hashCode,
keyComp,
(void **)&result,
plContext),
PKIX_PRIMHASHTABLELOOKUPFAILED);
PKIX_INCREF(result);
PKIX_MUTEX_UNLOCK(ht->tableLock);
*pResult = result;
cleanup:
PKIX_MUTEX_UNLOCK(ht->tableLock);
PKIX_RETURN(HASHTABLE);
}