mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
368 lines
8.2 KiB
368 lines
8.2 KiB
/*
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2012 Andrew Mortensen
|
|
*
|
|
* This file is part of the sca module for sip-router, a free SIP server.
|
|
*
|
|
* The sca module is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version
|
|
*
|
|
* The sca module is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*
|
|
*/
|
|
#include "sca_common.h"
|
|
|
|
#include <assert.h>
|
|
|
|
#include "sca.h"
|
|
#include "sca_hash.h"
|
|
|
|
int
|
|
sca_hash_table_create( sca_hash_table **ht, unsigned int size )
|
|
{
|
|
int i;
|
|
|
|
assert( ht != NULL );
|
|
|
|
*ht = shm_malloc( sizeof( sca_hash_table ));
|
|
if ( *ht == NULL ) {
|
|
LM_ERR( "Failed to shm_malloc space for hash table" );
|
|
return( -1 );
|
|
}
|
|
|
|
(*ht)->size = size;
|
|
(*ht)->slots = (sca_hash_slot *)shm_malloc( size * sizeof(sca_hash_slot));
|
|
if ((*ht)->slots == NULL ) {
|
|
LM_ERR( "Failed to shm_malloc hash table slots" );
|
|
shm_free( *ht ); *ht = NULL;
|
|
return( -1 );
|
|
}
|
|
memset((*ht)->slots, 0, size * sizeof( sca_hash_slot ));
|
|
|
|
for ( i = 0; i < (*ht)->size; i++ ) {
|
|
if ( lock_init( &(*ht)->slots[ i ].lock ) == NULL ) {
|
|
LM_ERR( "Failed to initialized lock in hash table slot %d", i );
|
|
shm_free( *ht ); *ht = NULL;
|
|
return( -1 );
|
|
}
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
int
|
|
sca_hash_table_slot_kv_insert_unsafe( sca_hash_slot *slot, void *value,
|
|
int (*e_compare)( str *, void * ), void (*e_description)( void * ),
|
|
void (*e_free)( void * ))
|
|
{
|
|
sca_hash_entry *new_entry;
|
|
sca_hash_entry **cur_entry;
|
|
|
|
assert( slot != NULL );
|
|
assert( value != NULL );
|
|
assert( e_free != NULL );
|
|
|
|
new_entry = (sca_hash_entry *)shm_malloc( sizeof( sca_hash_entry ));
|
|
if ( new_entry == NULL ) {
|
|
LM_ERR( "Failed to shm_malloc new hash table entry for slot %p", slot );
|
|
return( -1 );
|
|
}
|
|
new_entry->value = value;
|
|
new_entry->compare = e_compare;
|
|
new_entry->description = e_description;
|
|
new_entry->free_entry = e_free;
|
|
new_entry->slot = slot;
|
|
|
|
cur_entry = &slot->entries;
|
|
new_entry->next = *cur_entry;
|
|
*cur_entry = new_entry;
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
int
|
|
sca_hash_table_slot_kv_insert( sca_hash_slot *slot, void *value,
|
|
int (*e_compare)( str *, void * ), void (*e_description)( void * ),
|
|
void (*e_free)( void * ))
|
|
{
|
|
int rc;
|
|
|
|
lock_get( &slot->lock );
|
|
|
|
rc = sca_hash_table_slot_kv_insert_unsafe( slot, value, e_compare,
|
|
e_description, e_free );
|
|
|
|
lock_release( &slot->lock );
|
|
|
|
return( rc );
|
|
}
|
|
|
|
|
|
int
|
|
sca_hash_table_index_kv_insert( sca_hash_table *ht, int slot_idx, void *value,
|
|
int (*e_compare)( str *, void * ), void (*e_description)( void * ),
|
|
void (*e_free)( void * ))
|
|
{
|
|
assert( ht != NULL );
|
|
assert( ht->slots != NULL );
|
|
assert( slot_idx >= 0 && slot_idx < ht->size );
|
|
|
|
return( sca_hash_table_slot_kv_insert( &ht->slots[ slot_idx ], value,
|
|
e_compare, e_description,
|
|
e_free ));
|
|
}
|
|
|
|
|
|
int
|
|
sca_hash_table_kv_insert( sca_hash_table *ht, str *key, void *value,
|
|
int (*e_compare)(str *, void *), void (*e_description)(void *),
|
|
void (*e_free)(void *))
|
|
{
|
|
int hash_idx;
|
|
int rc;
|
|
|
|
assert( ht != NULL && !SCA_STR_EMPTY( key ) && value != NULL );
|
|
|
|
hash_idx = sca_hash_table_index_for_key( ht, key );
|
|
rc = sca_hash_table_index_kv_insert( ht, hash_idx, value, e_compare,
|
|
e_description, e_free );
|
|
|
|
return( rc );
|
|
}
|
|
|
|
void *
|
|
sca_hash_table_slot_kv_find_unsafe( sca_hash_slot *slot, str *key )
|
|
{
|
|
sca_hash_entry *e;
|
|
void *value = NULL;
|
|
|
|
assert( slot != NULL && !SCA_STR_EMPTY( key ));
|
|
|
|
for ( e = slot->entries; e != NULL; e = e->next ) {
|
|
if ( e->compare( key, e->value ) == 0 ) {
|
|
value = e->value;
|
|
}
|
|
}
|
|
|
|
return( value );
|
|
}
|
|
|
|
void *
|
|
sca_hash_table_slot_kv_find( sca_hash_slot *slot, str *key )
|
|
{
|
|
void *value;
|
|
|
|
lock_get( &slot->lock );
|
|
value = sca_hash_table_slot_kv_find_unsafe( slot, key );
|
|
lock_release( &slot->lock );
|
|
|
|
return( value );
|
|
}
|
|
|
|
void *
|
|
sca_hash_table_index_kv_find_unsafe(sca_hash_table *ht, int slot_idx, str *key)
|
|
{
|
|
assert( ht != NULL && !SCA_STR_EMPTY( key ));
|
|
assert( slot_idx >= 0 && slot_idx < ht->size );
|
|
|
|
return( sca_hash_table_slot_kv_find_unsafe( &ht->slots[ slot_idx ], key ));
|
|
}
|
|
|
|
void *
|
|
sca_hash_table_index_kv_find( sca_hash_table *ht, int slot_idx, str *key )
|
|
{
|
|
assert( ht != NULL && !SCA_STR_EMPTY( key ));
|
|
assert( slot_idx >= 0 && slot_idx < ht->size );
|
|
|
|
return( sca_hash_table_slot_kv_find( &ht->slots[ slot_idx ], key ));
|
|
}
|
|
|
|
void *
|
|
sca_hash_table_kv_find( sca_hash_table *ht, str *key )
|
|
{
|
|
int slot_idx;
|
|
|
|
slot_idx = sca_hash_table_index_for_key( ht, key );
|
|
|
|
return( sca_hash_table_index_kv_find( ht, slot_idx, key ));
|
|
}
|
|
|
|
sca_hash_entry *
|
|
sca_hash_table_slot_kv_find_entry_unsafe( sca_hash_slot *slot, str *key )
|
|
{
|
|
sca_hash_entry *e = NULL;
|
|
|
|
assert( slot != NULL && !SCA_STR_EMPTY( key ));
|
|
|
|
for ( e = slot->entries; e != NULL; e = e->next ) {
|
|
if ( e->compare( key, e->value ) == 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( e );
|
|
}
|
|
|
|
sca_hash_entry *
|
|
sca_hash_table_slot_kv_find_entry( sca_hash_slot *slot, str *key )
|
|
{
|
|
sca_hash_entry *e;
|
|
|
|
lock_get( &slot->lock );
|
|
e = sca_hash_table_slot_kv_find_entry( slot, key );
|
|
lock_release( &slot->lock );
|
|
|
|
return( e );
|
|
}
|
|
|
|
void
|
|
sca_hash_entry_free( sca_hash_entry *e )
|
|
{
|
|
assert( e != NULL );
|
|
|
|
e->free_entry( e->value );
|
|
shm_free( e );
|
|
}
|
|
|
|
sca_hash_entry *
|
|
sca_hash_table_slot_unlink_entry_unsafe( sca_hash_slot *slot,
|
|
sca_hash_entry *e )
|
|
{
|
|
sca_hash_entry **cur_e;
|
|
|
|
assert( slot != NULL );
|
|
assert( e != NULL );
|
|
|
|
for ( cur_e = &slot->entries; *cur_e != NULL; cur_e = &(*cur_e)->next ) {
|
|
if ( *cur_e == e ) {
|
|
*cur_e = e->next;
|
|
|
|
/* ensure any attempted traversal using this entry goes nowhere */
|
|
e->next = NULL;
|
|
e->slot = NULL;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( e );
|
|
}
|
|
|
|
int
|
|
sca_hash_table_slot_kv_delete_unsafe( sca_hash_slot *slot, str *key )
|
|
{
|
|
sca_hash_entry *e;
|
|
|
|
e = sca_hash_table_slot_kv_find_unsafe( slot, key );
|
|
if ( e == NULL ) {
|
|
return( -1 );
|
|
}
|
|
|
|
e = sca_hash_table_slot_unlink_entry_unsafe( slot, e );
|
|
if ( e ) {
|
|
e->free_entry( e->value );
|
|
shm_free( e );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
int
|
|
sca_hash_table_slot_kv_delete( sca_hash_slot *slot, str *key )
|
|
{
|
|
int rc;
|
|
|
|
lock_get( &slot->lock );
|
|
rc = sca_hash_table_slot_kv_delete_unsafe( slot, key );
|
|
lock_release( &slot->lock );
|
|
|
|
return( rc );
|
|
}
|
|
|
|
int
|
|
sca_hash_table_index_kv_delete( sca_hash_table *ht, int slot_idx, str *key )
|
|
{
|
|
return( sca_hash_table_slot_kv_delete( &ht->slots[ slot_idx ], key ));
|
|
}
|
|
|
|
int
|
|
sca_hash_table_kv_delete( sca_hash_table *ht, str *key )
|
|
{
|
|
int slot_idx;
|
|
|
|
slot_idx = sca_hash_table_index_for_key( ht, key );
|
|
|
|
return( sca_hash_table_index_kv_delete( ht, slot_idx, key ));
|
|
}
|
|
|
|
static void
|
|
sca_hash_slot_print( sca_hash_slot *hs )
|
|
{
|
|
sca_hash_entry *e;
|
|
|
|
for ( e = hs->entries; e != NULL; e = e->next ) {
|
|
if ( e->description != NULL ) {
|
|
e->description( e->value );
|
|
} else {
|
|
LM_DBG( "0x%p", e->value );
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
sca_hash_table_print( sca_hash_table *ht )
|
|
{
|
|
unsigned int i;
|
|
|
|
for ( i = 0; i < ht->size; i++ ) {
|
|
LM_DBG( "SLOT %d:", i );
|
|
sca_hash_slot_print( &ht->slots[ i ] );
|
|
}
|
|
}
|
|
|
|
void
|
|
sca_hash_table_free( sca_hash_table *ht )
|
|
{
|
|
sca_hash_entry *e, *e_tmp;
|
|
unsigned int i;
|
|
|
|
if ( ht == NULL ) {
|
|
return;
|
|
}
|
|
|
|
for ( i = 0; i < ht->size; i++ ) {
|
|
if ( ht->slots[ i ].entries == NULL ) {
|
|
continue;
|
|
}
|
|
|
|
sca_hash_table_lock_index( ht, i );
|
|
|
|
for ( e = ht->slots[ i ].entries; e != NULL; e = e_tmp ) {
|
|
e_tmp = e->next;
|
|
|
|
e->free_entry( e->value );
|
|
|
|
shm_free( e );
|
|
}
|
|
|
|
sca_hash_table_unlock_index( ht, i );
|
|
|
|
lock_destroy( &ht->slots[ i ].lock );
|
|
lock_dealloc( &ht->slots[ i ].lock );
|
|
}
|
|
|
|
shm_free( ht->slots );
|
|
shm_free( ht );
|
|
}
|