Don't use linked_list_t for buckets in main IKE_SA hash table.

This commit is contained in:
Tobias Brunner 2012-03-01 12:51:34 +01:00
parent 894c52cba2
commit e49bb4e3e3

View File

@ -296,6 +296,20 @@ struct shareable_segment_t {
u_int count; u_int count;
}; };
typedef struct table_item_t table_item_t;
/**
* Instead of using linked_list_t for each bucket we store the data in our own
* list to save memory.
*/
struct table_item_t {
/** data of this item */
void *value;
/** next item in the overflow list */
table_item_t *next;
};
typedef struct private_ike_sa_manager_t private_ike_sa_manager_t; typedef struct private_ike_sa_manager_t private_ike_sa_manager_t;
/** /**
@ -310,7 +324,7 @@ struct private_ike_sa_manager_t {
/** /**
* Hash table with entries for the ike_sa_t objects. * Hash table with entries for the ike_sa_t objects.
*/ */
linked_list_t **ike_sa_table; table_item_t **ike_sa_table;
/** /**
* The size of the hash table. * The size of the hash table.
@ -387,10 +401,10 @@ struct private_ike_sa_manager_t {
* Acquire a lock to access the segment of the table row with the given index. * Acquire a lock to access the segment of the table row with the given index.
* It also works with the segment index directly. * It also works with the segment index directly.
*/ */
static void lock_single_segment(private_ike_sa_manager_t *this, u_int index) static inline void lock_single_segment(private_ike_sa_manager_t *this,
u_int index)
{ {
mutex_t *lock = this->segments[index & this->segment_mask].mutex; mutex_t *lock = this->segments[index & this->segment_mask].mutex;
lock->lock(lock); lock->lock(lock);
} }
@ -398,10 +412,10 @@ static void lock_single_segment(private_ike_sa_manager_t *this, u_int index)
* Release the lock required to access the segment of the table row with the given index. * Release the lock required to access the segment of the table row with the given index.
* It also works with the segment index directly. * It also works with the segment index directly.
*/ */
static void unlock_single_segment(private_ike_sa_manager_t *this, u_int index) static inline void unlock_single_segment(private_ike_sa_manager_t *this,
u_int index)
{ {
mutex_t *lock = this->segments[index & this->segment_mask].mutex; mutex_t *lock = this->segments[index & this->segment_mask].mutex;
lock->unlock(lock); lock->unlock(lock);
} }
@ -464,9 +478,14 @@ struct private_enumerator_t {
u_int row; u_int row;
/** /**
* enumerator for the current table row * current table item
*/ */
enumerator_t *current; table_item_t *current;
/**
* previous table item
*/
table_item_t *prev;
}; };
METHOD(enumerator_t, enumerate, bool, METHOD(enumerator_t, enumerate, bool,
@ -481,33 +500,23 @@ METHOD(enumerator_t, enumerate, bool,
{ {
while (this->row < this->manager->table_size) while (this->row < this->manager->table_size)
{ {
this->prev = this->current;
if (this->current) if (this->current)
{ {
entry_t *item; this->current = this->current->next;
if (this->current->enumerate(this->current, &item))
{
*entry = this->entry = item;
*segment = this->segment;
return TRUE;
}
this->current->destroy(this->current);
this->current = NULL;
unlock_single_segment(this->manager, this->segment);
} }
else else
{ {
linked_list_t *list;
lock_single_segment(this->manager, this->segment); lock_single_segment(this->manager, this->segment);
if ((list = this->manager->ike_sa_table[this->row]) != NULL && this->current = this->manager->ike_sa_table[this->row];
list->get_count(list))
{
this->current = list->create_enumerator(list);
continue;
}
unlock_single_segment(this->manager, this->segment);
} }
if (this->current)
{
*entry = this->entry = this->current->value;
*segment = this->segment;
return TRUE;
}
unlock_single_segment(this->manager, this->segment);
this->row += this->manager->segment_count; this->row += this->manager->segment_count;
} }
this->segment++; this->segment++;
@ -525,7 +534,6 @@ METHOD(enumerator_t, enumerator_destroy, void,
} }
if (this->current) if (this->current)
{ {
this->current->destroy(this->current);
unlock_single_segment(this->manager, this->segment); unlock_single_segment(this->manager, this->segment);
} }
free(this); free(this);
@ -554,19 +562,23 @@ static enumerator_t* create_table_enumerator(private_ike_sa_manager_t *this)
*/ */
static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry) static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry)
{ {
linked_list_t *list; table_item_t *current, *item;
u_int row, segment; u_int row, segment;
INIT(item,
.value = entry,
);
row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask;
segment = row & this->segment_mask; segment = row & this->segment_mask;
lock_single_segment(this, segment); lock_single_segment(this, segment);
list = this->ike_sa_table[row]; current = this->ike_sa_table[row];
if (!list) if (current)
{ { /* insert at the front of current bucket */
list = this->ike_sa_table[row] = linked_list_create(); item->next = current;
} }
list->insert_last(list, entry); this->ike_sa_table[row] = item;
this->segments[segment].count++; this->segments[segment].count++;
return segment; return segment;
} }
@ -577,28 +589,30 @@ static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry)
*/ */
static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry) static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry)
{ {
linked_list_t *list; table_item_t *item, *prev = NULL;
u_int row, segment; u_int row, segment;
row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask;
segment = row & this->segment_mask; segment = row & this->segment_mask;
list = this->ike_sa_table[row]; item = this->ike_sa_table[row];
if (list) while (item)
{ {
entry_t *current; if (item->value == entry)
enumerator_t *enumerator;
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &current))
{ {
if (current == entry) if (prev)
{ {
list->remove_at(list, enumerator); prev->next = item->next;
this->segments[segment].count--;
break;
} }
else
{
this->ike_sa_table[row] = item->next;
}
this->segments[segment].count--;
free(item);
break;
} }
enumerator->destroy(enumerator); prev = item;
item = item->next;
} }
} }
@ -610,9 +624,21 @@ static void remove_entry_at(private_enumerator_t *this)
this->entry = NULL; this->entry = NULL;
if (this->current) if (this->current)
{ {
linked_list_t *list = this->manager->ike_sa_table[this->row]; table_item_t *current = this->current;
list->remove_at(list, this->current);
this->manager->segments[this->segment].count--; this->manager->segments[this->segment].count--;
this->current = this->prev;
if (this->prev)
{
this->prev->next = current->next;
}
else
{
this->manager->ike_sa_table[this->row] = current->next;
unlock_single_segment(this->manager, this->segment);
}
free(current);
} }
} }
@ -624,24 +650,24 @@ static status_t get_entry_by_match_function(private_ike_sa_manager_t *this,
ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment, ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment,
linked_list_match_t match, void *p1, void *p2) linked_list_match_t match, void *p1, void *p2)
{ {
entry_t *current; table_item_t *item;
linked_list_t *list;
u_int row, seg; u_int row, seg;
row = ike_sa_id_hash(ike_sa_id) & this->table_mask; row = ike_sa_id_hash(ike_sa_id) & this->table_mask;
seg = row & this->segment_mask; seg = row & this->segment_mask;
lock_single_segment(this, seg); lock_single_segment(this, seg);
list = this->ike_sa_table[row]; item = this->ike_sa_table[row];
if (list) while (item)
{ {
if (list->find_first(list, match, (void**)&current, p1, p2) == SUCCESS) if (match(item->value, p1, p2))
{ {
*entry = current; *entry = item->value;
*segment = seg; *segment = seg;
/* the locked segment has to be unlocked by the caller */ /* the locked segment has to be unlocked by the caller */
return SUCCESS; return SUCCESS;
} }
item = item->next;
} }
unlock_single_segment(this, seg); unlock_single_segment(this, seg);
return NOT_FOUND; return NOT_FOUND;
@ -1846,7 +1872,6 @@ METHOD(ike_sa_manager_t, destroy, void,
for (i = 0; i < this->table_size; i++) for (i = 0; i < this->table_size; i++)
{ {
DESTROY_IF(this->ike_sa_table[i]);
DESTROY_IF(this->half_open_table[i]); DESTROY_IF(this->half_open_table[i]);
DESTROY_IF(this->connected_peers_table[i]); DESTROY_IF(this->connected_peers_table[i]);
DESTROY_IF(this->init_hashes_table[i]); DESTROY_IF(this->init_hashes_table[i]);
@ -1943,7 +1968,7 @@ ike_sa_manager_t *ike_sa_manager_create()
this->segment_count = max(1, min(this->segment_count, this->table_size)); this->segment_count = max(1, min(this->segment_count, this->table_size));
this->segment_mask = this->segment_count - 1; this->segment_mask = this->segment_count - 1;
this->ike_sa_table = calloc(this->table_size, sizeof(linked_list_t*)); this->ike_sa_table = calloc(this->table_size, sizeof(table_item_t*));
this->segments = (segment_t*)calloc(this->segment_count, sizeof(segment_t)); this->segments = (segment_t*)calloc(this->segment_count, sizeof(segment_t));
for (i = 0; i < this->segment_count; i++) for (i = 0; i < this->segment_count; i++)
{ {