Reimplemented mem pool to support multiple leases for a single identity

This commit is contained in:
Martin Willi
2010-08-04 09:49:59 +02:00
parent 6e4f4d2fdf
commit e82186fb5a
+174 -131
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2010 Tobias Brunner * Copyright (C) 2010 Tobias Brunner
* Copyright (C) 2008 Martin Willi * Copyright (C) 2008-2010 Martin Willi
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -18,7 +18,8 @@
#include <debug.h> #include <debug.h>
#include <utils/hashtable.h> #include <utils/hashtable.h>
#include <threading/rwlock.h> #include <utils/linked_list.h>
#include <threading/mutex.h>
#define POOL_LIMIT (sizeof(uintptr_t)*8) #define POOL_LIMIT (sizeof(uintptr_t)*8)
@@ -54,26 +55,28 @@ struct private_mem_pool_t {
u_int unused; u_int unused;
/** /**
* hashtable [identity => offset], for online leases * lease hashtable [identity => entry]
*/ */
hashtable_t *online; hashtable_t *leases;
/**
* hashtable [identity => offset], for offline leases
*/
hashtable_t *offline;
/**
* hashtable [identity => identity], handles identity references
*/
hashtable_t *ids;
/** /**
* lock to safely access the pool * lock to safely access the pool
*/ */
rwlock_t *lock; mutex_t *mutex;
}; };
/**
* Lease entry.
*/
typedef struct {
/* identitiy reference */
identification_t *id;
/* list of online leases, as offset */
linked_list_t *online;
/* list of offline leases, as offset */
linked_list_t *offline;
} entry_t;
/** /**
* hashtable hash function for identities * hashtable hash function for identities
*/ */
@@ -154,43 +157,61 @@ static int host2offset(private_mem_pool_t *pool, host_t *addr)
} }
METHOD(mem_pool_t, get_name, const char*, METHOD(mem_pool_t, get_name, const char*,
private_mem_pool_t *this) private_mem_pool_t *this)
{ {
return this->name; return this->name;
} }
METHOD(mem_pool_t, get_size, u_int, METHOD(mem_pool_t, get_size, u_int,
private_mem_pool_t *this) private_mem_pool_t *this)
{ {
return this->size; return this->size;
} }
METHOD(mem_pool_t, get_online, u_int, METHOD(mem_pool_t, get_online, u_int,
private_mem_pool_t *this) private_mem_pool_t *this)
{ {
u_int count; enumerator_t *enumerator;
this->lock->read_lock(this->lock); entry_t *entry;
count = this->online->get_count(this->online); u_int count = 0;
this->lock->unlock(this->lock);
this->mutex->lock(this->mutex);
enumerator = this->leases->create_enumerator(this->leases);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
count += entry->online->get_count(entry->online);
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
return count; return count;
} }
METHOD(mem_pool_t, get_offline, u_int, METHOD(mem_pool_t, get_offline, u_int,
private_mem_pool_t *this) private_mem_pool_t *this)
{ {
u_int count; enumerator_t *enumerator;
this->lock->read_lock(this->lock); entry_t *entry;
count = this->offline->get_count(this->offline); u_int count = 0;
this->lock->unlock(this->lock);
this->mutex->lock(this->mutex);
enumerator = this->leases->create_enumerator(this->leases);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
count += entry->offline->get_count(entry->offline);
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
return count; return count;
} }
METHOD(mem_pool_t, acquire_address, host_t*, METHOD(mem_pool_t, acquire_address, host_t*,
private_mem_pool_t *this, identification_t *id, host_t *requested) private_mem_pool_t *this, identification_t *id, host_t *requested)
{ {
uintptr_t offset = 0; uintptr_t offset = 0, current;
enumerator_t *enumerator; enumerator_t *enumerator;
identification_t *old_id; entry_t *entry, *old;
/* if the pool is empty (e.g. in the %config case) we simply return the /* if the pool is empty (e.g. in the %config case) we simply return the
* requested address */ * requested address */
@@ -207,108 +228,114 @@ METHOD(mem_pool_t, acquire_address, host_t*,
return NULL; return NULL;
} }
this->lock->write_lock(this->lock); this->mutex->lock(this->mutex);
while (TRUE) while (TRUE)
{ {
/* check for a valid offline lease, refresh */ entry = this->leases->get(this->leases, id);
offset = (uintptr_t)this->offline->remove(this->offline, id); if (entry)
if (offset)
{ {
id = this->ids->get(this->ids, id); /* check for a valid offline lease, refresh */
if (id) enumerator = entry->offline->create_enumerator(entry->offline);
if (enumerator->enumerate(enumerator, &current))
{
entry->offline->remove_at(entry->offline, enumerator);
entry->online->insert_last(entry->online, (void*)current);
offset = current;
}
enumerator->destroy(enumerator);
if (offset)
{ {
DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id); DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id);
this->online->put(this->online, id, (void*)offset); break;
}
/* check for a valid online lease to reassign */
enumerator = entry->online->create_enumerator(entry->online);
while (enumerator->enumerate(enumerator, &current))
{
if (current == host2offset(this, requested))
{
offset = current;
break;
}
}
enumerator->destroy(enumerator);
if (offset)
{
DBG1(DBG_CFG, "reassigning online lease to '%Y'", id);
break; break;
} }
} }
else
/* check for a valid online lease, reassign */
offset = (uintptr_t)this->online->get(this->online, id);
if (offset)
{ {
if (offset == host2offset(this, requested)) INIT(entry,
{ .id = id->clone(id),
DBG1(DBG_CFG, "reassigning online lease to '%Y'", id); .online = linked_list_create(),
} .offline = linked_list_create(),
else );
{ this->leases->put(this->leases, entry->id, entry);
DBG1(DBG_CFG, "'%Y' already has an online lease, "
"unable to assign address", id);
offset = 0;
}
break;
} }
if (this->unused < this->size) if (this->unused < this->size)
{ {
/* assigning offset, starting by 1. Handling 0 in hashtable /* assigning offset, starting by 1 */
* is difficult. */
offset = ++this->unused; offset = ++this->unused;
id = id->clone(id); entry->online->insert_last(entry->online, (void*)offset);
this->ids->put(this->ids, id, id);
this->online->put(this->online, id, (void*)offset);
DBG1(DBG_CFG, "assigning new lease to '%Y'", id); DBG1(DBG_CFG, "assigning new lease to '%Y'", id);
break; break;
} }
/* no more addresses, replace the first found offline lease */ /* no more addresses, replace the first found offline lease */
enumerator = this->offline->create_enumerator(this->offline); enumerator = this->leases->create_enumerator(this->leases);
if (enumerator->enumerate(enumerator, &old_id, &offset)) while (enumerator->enumerate(enumerator, NULL, &old))
{ {
offset = (uintptr_t)this->offline->remove(this->offline, old_id); if (old->offline->remove_first(old->offline,
if (offset) (void**)&current) == SUCCESS)
{ {
/* destroy reference to old ID */ offset = current;
old_id = this->ids->remove(this->ids, old_id); entry->online->insert_last(entry->online, (void*)offset);
DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'" DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'"
" to '%Y'", old_id, id); " to '%Y'", old->id, id);
if (old_id)
{
old_id->destroy(old_id);
}
id = id->clone(id);
this->ids->put(this->ids, id, id);
this->online->put(this->online, id, (void*)offset);
enumerator->destroy(enumerator);
break; break;
} }
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
DBG1(DBG_CFG, "pool '%s' is full, unable to assign address",
this->name);
break; break;
} }
this->lock->unlock(this->lock); this->mutex->unlock(this->mutex);
if (offset) if (offset)
{ {
return offset2host(this, offset); return offset2host(this, offset);
} }
else
{
DBG1(DBG_CFG, "pool '%s' is full, unable to assign address",
this->name);
}
return NULL; return NULL;
} }
METHOD(mem_pool_t, release_address, bool, METHOD(mem_pool_t, release_address, bool,
private_mem_pool_t *this, host_t *address, identification_t *id) private_mem_pool_t *this, host_t *address, identification_t *id)
{ {
bool found = FALSE; bool found = FALSE;
entry_t *entry;
uintptr_t offset;
if (this->size != 0) if (this->size != 0)
{ {
uintptr_t offset; this->mutex->lock(this->mutex);
this->lock->write_lock(this->lock); entry = this->leases->get(this->leases, id);
offset = (uintptr_t)this->online->remove(this->online, id); if (entry)
if (offset)
{ {
id = this->ids->get(this->ids, id); offset = host2offset(this, address);
if (id) if (entry->online->remove(entry->online, (void*)offset, NULL) > 0)
{ {
DBG1(DBG_CFG, "lease %H by '%Y' went offline", address, id); DBG1(DBG_CFG, "lease %H by '%Y' went offline", address, id);
this->offline->put(this->offline, id, (void*)offset); entry->offline->insert_last(entry->offline, (void*)offset);
found = TRUE; found = TRUE;
} }
} }
this->lock->unlock(this->lock); this->mutex->unlock(this->mutex);
} }
return found; return found;
} }
@@ -319,52 +346,69 @@ METHOD(mem_pool_t, release_address, bool,
typedef struct { typedef struct {
/** implemented enumerator interface */ /** implemented enumerator interface */
enumerator_t public; enumerator_t public;
/** inner hash-table enumerator */ /** hash-table enumerator */
enumerator_t *inner; enumerator_t *entries;
/** online enumerator */
enumerator_t *online;
/** offline enumerator */
enumerator_t *offline;
/** enumerated pool */ /** enumerated pool */
private_mem_pool_t *pool; private_mem_pool_t *pool;
/** currently enumerated entry */
entry_t *entry;
/** currently enumerated lease address */ /** currently enumerated lease address */
host_t *current; host_t *addr;
} lease_enumerator_t; } lease_enumerator_t;
METHOD(enumerator_t, lease_enumerate, bool, METHOD(enumerator_t, lease_enumerate, bool,
lease_enumerator_t *this, identification_t **id_out, host_t **addr_out, lease_enumerator_t *this, identification_t **id, host_t **addr, bool *online)
bool *online)
{ {
identification_t *id;
uintptr_t offset; uintptr_t offset;
DESTROY_IF(this->current); DESTROY_IF(this->addr);
this->current = NULL; this->addr = NULL;
if (this->inner->enumerate(this->inner, &id, NULL)) while (TRUE)
{ {
offset = (uintptr_t)this->pool->online->get(this->pool->online, id); if (this->entry)
if (offset)
{ {
*id_out = id; if (this->online->enumerate(this->online, (void**)&offset))
*addr_out = this->current = offset2host(this->pool, offset); {
*online = TRUE; *id = this->entry->id;
return TRUE; *addr = this->addr = offset2host(this->pool, offset);
*online = TRUE;
return TRUE;
}
if (this->offline->enumerate(this->offline, (void**)&offset))
{
*id = this->entry->id;
*addr = this->addr = offset2host(this->pool, offset);
*online = FALSE;
return TRUE;
}
this->online->destroy(this->online);
this->offline->destroy(this->offline);
this->online = this->offline = NULL;
} }
offset = (uintptr_t)this->pool->offline->get(this->pool->offline, id); if (!this->entries->enumerate(this->entries, NULL, &this->entry))
if (offset)
{ {
*id_out = id; return FALSE;
*addr_out = this->current = offset2host(this->pool, offset);
*online = FALSE;
return TRUE;
} }
this->online = this->entry->online->create_enumerator(
this->entry->online);
this->offline = this->entry->offline->create_enumerator(
this->entry->offline);
} }
return FALSE;
} }
METHOD(enumerator_t, lease_enumerator_destroy, void, METHOD(enumerator_t, lease_enumerator_destroy, void,
lease_enumerator_t *this) lease_enumerator_t *this)
{ {
DESTROY_IF(this->current); DESTROY_IF(this->addr);
this->inner->destroy(this->inner); DESTROY_IF(this->online);
this->pool->lock->unlock(this->pool->lock); DESTROY_IF(this->offline);
this->entries->destroy(this->entries);
this->pool->mutex->unlock(this->pool->mutex);
free(this); free(this);
} }
@@ -372,35 +416,37 @@ METHOD(mem_pool_t, create_lease_enumerator, enumerator_t*,
private_mem_pool_t *this) private_mem_pool_t *this)
{ {
lease_enumerator_t *enumerator; lease_enumerator_t *enumerator;
this->lock->read_lock(this->lock);
this->mutex->lock(this->mutex);
INIT(enumerator, INIT(enumerator,
.public = { .public = {
.enumerate = (void*)_lease_enumerate, .enumerate = (void*)_lease_enumerate,
.destroy = (void*)_lease_enumerator_destroy, .destroy = _lease_enumerator_destroy,
}, },
.pool = this, .pool = this,
.inner = this->ids->create_enumerator(this->ids), .entries = this->leases->create_enumerator(this->leases),
); );
return &enumerator->public; return &enumerator->public;
} }
METHOD(mem_pool_t, destroy, void, METHOD(mem_pool_t, destroy, void,
private_mem_pool_t *this) private_mem_pool_t *this)
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
identification_t *id; entry_t *entry;
enumerator = this->ids->create_enumerator(this->ids); enumerator = this->leases->create_enumerator(this->leases);
while (enumerator->enumerate(enumerator, &id, NULL)) while (enumerator->enumerate(enumerator, NULL, &entry))
{ {
id->destroy(id); entry->id->destroy(entry->id);
entry->online->destroy(entry->online);
entry->offline->destroy(entry->offline);
free(entry);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
this->ids->destroy(this->ids); this->leases->destroy(this->leases);
this->online->destroy(this->online); this->mutex->destroy(this->mutex);
this->offline->destroy(this->offline);
this->lock->destroy(this->lock);
DESTROY_IF(this->base); DESTROY_IF(this->base);
free(this->name); free(this->name);
free(this); free(this);
@@ -412,6 +458,7 @@ METHOD(mem_pool_t, destroy, void,
mem_pool_t *mem_pool_create(char *name, host_t *base, int bits) mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
{ {
private_mem_pool_t *this; private_mem_pool_t *this;
int addr_bits;
INIT(this, INIT(this,
.public = { .public = {
@@ -425,18 +472,14 @@ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
.destroy = _destroy, .destroy = _destroy,
}, },
.name = strdup(name), .name = strdup(name),
.online = hashtable_create((hashtable_hash_t)id_hash, .leases = hashtable_create((hashtable_hash_t)id_hash,
(hashtable_equals_t)id_equals, 16), (hashtable_equals_t)id_equals, 16),
.offline = hashtable_create((hashtable_hash_t)id_hash, .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
(hashtable_equals_t)id_equals, 16),
.ids = hashtable_create((hashtable_hash_t)id_hash,
(hashtable_equals_t)id_equals, 16),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
); );
if (base) if (base)
{ {
int addr_bits = base->get_family(base) == AF_INET ? 32 : 128; addr_bits = base->get_family(base) == AF_INET ? 32 : 128;
/* net bits -> host bits */ /* net bits -> host bits */
bits = addr_bits - bits; bits = addr_bits - bits;
if (bits > POOL_LIMIT) if (bits > POOL_LIMIT)