settings: Implement subsections and key/value pairs with sorted arrays
Is a bit more memory efficient (also due to lazy instantiation) and lookups for sections with lots of subsections/keys (e.g. charon.plugins) are faster.
This commit is contained in:
@@ -86,12 +86,12 @@ struct section_t {
|
|||||||
/**
|
/**
|
||||||
* subsections, as section_t
|
* subsections, as section_t
|
||||||
*/
|
*/
|
||||||
linked_list_t *sections;
|
array_t *sections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* key value pairs, as kv_t
|
* key value pairs, as kv_t
|
||||||
*/
|
*/
|
||||||
linked_list_t *kv;
|
array_t *kv;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,8 +140,6 @@ static section_t *section_create(char *name)
|
|||||||
section_t *this;
|
section_t *this;
|
||||||
INIT(this,
|
INIT(this,
|
||||||
.name = strdupnull(name),
|
.name = strdupnull(name),
|
||||||
.sections = linked_list_create(),
|
|
||||||
.kv = linked_list_create(),
|
|
||||||
);
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -151,63 +149,73 @@ static section_t *section_create(char *name)
|
|||||||
*/
|
*/
|
||||||
static void section_destroy(section_t *this)
|
static void section_destroy(section_t *this)
|
||||||
{
|
{
|
||||||
this->kv->destroy_function(this->kv, (void*)kv_destroy);
|
array_destroy_function(this->sections, (void*)section_destroy, NULL);
|
||||||
this->sections->destroy_function(this->sections, (void*)section_destroy);
|
array_destroy_function(this->kv, (void*)kv_destroy, NULL);
|
||||||
array_destroy(this->fallbacks);
|
array_destroy(this->fallbacks);
|
||||||
free(this->name);
|
free(this->name);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* forward declaration
|
|
||||||
*/
|
|
||||||
static bool section_purge(section_t *this);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if it is safe to remove the given section.
|
* Purge contents of a section, returns if section can be safely removed.
|
||||||
*/
|
|
||||||
static bool section_remove(section_t *this)
|
|
||||||
{
|
|
||||||
if (section_purge(this))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
section_destroy(this);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Purge contents of a section, returns TRUE if section has to be kept due to
|
|
||||||
* any subsections.
|
|
||||||
*/
|
*/
|
||||||
static bool section_purge(section_t *this)
|
static bool section_purge(section_t *this)
|
||||||
{
|
{
|
||||||
int count, removed;
|
section_t *current;
|
||||||
|
int i;
|
||||||
|
|
||||||
this->kv->destroy_function(this->kv, (void*)kv_destroy);
|
array_destroy_function(this->kv, (void*)kv_destroy, NULL);
|
||||||
this->kv = linked_list_create();
|
this->kv = NULL;
|
||||||
/* we ensure sections used as fallback, or configured with fallbacks (or
|
/* we ensure sections used as fallback, or configured with fallbacks (or
|
||||||
* having any such subsections) are not removed */
|
* having any such subsections) are not removed */
|
||||||
count = this->sections->get_count(this->sections);
|
for (i = array_count(this->sections) - 1; i >= 0; i--)
|
||||||
removed = this->sections->remove(this->sections, NULL,
|
{
|
||||||
(void*)section_remove);
|
array_get(this->sections, i, ¤t);
|
||||||
return this->fallbacks || removed < count;
|
if (section_purge(current))
|
||||||
|
{
|
||||||
|
array_remove(this->sections, i, NULL);
|
||||||
|
section_destroy(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !this->fallbacks && !array_count(this->sections);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* callback to find a section by name
|
* callback to find a section by name
|
||||||
*/
|
*/
|
||||||
static bool section_find(section_t *this, char *name)
|
static int section_find(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
return streq(this->name, name);
|
const char *key = a;
|
||||||
|
const section_t *item = b;
|
||||||
|
return strcmp(key, item->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* callback to sort sections by name
|
||||||
|
*/
|
||||||
|
static int section_sort(const void *a, const void *b, void *user)
|
||||||
|
{
|
||||||
|
const section_t *sa = a, *sb = b;
|
||||||
|
return strcmp(sa->name, sb->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* callback to find a kv pair by key
|
* callback to find a kv pair by key
|
||||||
*/
|
*/
|
||||||
static bool kv_find(kv_t *this, char *key)
|
static int kv_find(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
return streq(this->key, key);
|
const char *key = a;
|
||||||
|
const kv_t *item = b;
|
||||||
|
return strcmp(key, item->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* callback to sort kv pairs by key
|
||||||
|
*/
|
||||||
|
static int kv_sort(const void *a, const void *b, void *user)
|
||||||
|
{
|
||||||
|
const kv_t *kva = a, *kvb = b;
|
||||||
|
return strcmp(kva->key, kvb->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -282,14 +290,13 @@ static section_t *find_section_buffered(section_t *section,
|
|||||||
{
|
{
|
||||||
found = section;
|
found = section;
|
||||||
}
|
}
|
||||||
else if (section->sections->find_first(section->sections,
|
else if (array_bsearch(section->sections, buf, section_find, &found) == -1)
|
||||||
(linked_list_match_t)section_find,
|
|
||||||
(void**)&found, buf) != SUCCESS)
|
|
||||||
{
|
{
|
||||||
if (ensure)
|
if (ensure)
|
||||||
{
|
{
|
||||||
found = section_create(buf);
|
found = section_create(buf);
|
||||||
section->sections->insert_last(section->sections, found);
|
array_insert_create(§ion->sections, ARRAY_TAIL, found);
|
||||||
|
array_sort(section->sections, section_sort, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found && pos)
|
if (found && pos)
|
||||||
@@ -430,14 +437,14 @@ static kv_t *find_value_buffered(section_t *section, char *start, char *key,
|
|||||||
{
|
{
|
||||||
found = section;
|
found = section;
|
||||||
}
|
}
|
||||||
else if (section->sections->find_first(section->sections,
|
else if (array_bsearch(section->sections, buf, section_find,
|
||||||
(linked_list_match_t)section_find,
|
&found) == -1)
|
||||||
(void**)&found, buf) != SUCCESS)
|
|
||||||
{
|
{
|
||||||
if (ensure)
|
if (ensure)
|
||||||
{
|
{
|
||||||
found = section_create(buf);
|
found = section_create(buf);
|
||||||
section->sections->insert_last(section->sections, found);
|
array_insert_create(§ion->sections, ARRAY_TAIL, found);
|
||||||
|
array_sort(section->sections, section_sort, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found)
|
if (found)
|
||||||
@@ -461,13 +468,13 @@ static kv_t *find_value_buffered(section_t *section, char *start, char *key,
|
|||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (section->kv->find_first(section->kv, (linked_list_match_t)kv_find,
|
if (array_bsearch(section->kv, buf, kv_find, &kv) == -1)
|
||||||
(void**)&kv, buf) != SUCCESS)
|
|
||||||
{
|
{
|
||||||
if (ensure)
|
if (ensure)
|
||||||
{
|
{
|
||||||
kv = kv_create(buf, NULL);
|
kv = kv_create(buf, NULL);
|
||||||
section->kv->insert_last(section->kv, kv);
|
array_insert_create(§ion->kv, ARRAY_TAIL, kv);
|
||||||
|
array_sort(section->kv, kv_sort, NULL);
|
||||||
}
|
}
|
||||||
else if (section->fallbacks)
|
else if (section->fallbacks)
|
||||||
{
|
{
|
||||||
@@ -803,7 +810,7 @@ METHOD(settings_t, create_section_enumerator, enumerator_t*,
|
|||||||
}
|
}
|
||||||
this->lock->read_lock(this->lock);
|
this->lock->read_lock(this->lock);
|
||||||
return enumerator_create_filter(
|
return enumerator_create_filter(
|
||||||
section->sections->create_enumerator(section->sections),
|
array_create_enumerator(section->sections),
|
||||||
(void*)section_filter, this->lock, (void*)this->lock->unlock);
|
(void*)section_filter, this->lock, (void*)this->lock->unlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -834,7 +841,7 @@ METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
|
|||||||
}
|
}
|
||||||
this->lock->read_lock(this->lock);
|
this->lock->read_lock(this->lock);
|
||||||
return enumerator_create_filter(
|
return enumerator_create_filter(
|
||||||
section->kv->create_enumerator(section->kv),
|
array_create_enumerator(section->kv),
|
||||||
(void*)kv_filter, this->lock, (void*)this->lock->unlock);
|
(void*)kv_filter, this->lock, (void*)this->lock->unlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1011,15 +1018,15 @@ static bool parse_section(linked_list_t *contents, char *file, int level,
|
|||||||
section->name);
|
section->name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (section->sections->find_first(section->sections,
|
if (array_bsearch(section->sections, key, section_find,
|
||||||
(linked_list_match_t)section_find,
|
&sub) == -1)
|
||||||
(void**)&sub, key) != SUCCESS)
|
|
||||||
{
|
{
|
||||||
sub = section_create(key);
|
sub = section_create(key);
|
||||||
if (parse_section(contents, file, level, &inner, sub))
|
if (parse_section(contents, file, level, &inner, sub))
|
||||||
{
|
{
|
||||||
section->sections->insert_last(section->sections,
|
array_insert_create(§ion->sections, ARRAY_TAIL,
|
||||||
sub);
|
sub);
|
||||||
|
array_sort(section->sections, section_sort, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
section_destroy(sub);
|
section_destroy(sub);
|
||||||
@@ -1046,12 +1053,11 @@ static bool parse_section(linked_list_t *contents, char *file, int level,
|
|||||||
section->name);
|
section->name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (section->kv->find_first(section->kv,
|
if (array_bsearch(section->kv, key, kv_find, &kv) == -1)
|
||||||
(linked_list_match_t)kv_find,
|
|
||||||
(void**)&kv, key) != SUCCESS)
|
|
||||||
{
|
{
|
||||||
kv = kv_create(key, value);
|
kv = kv_create(key, value);
|
||||||
section->kv->insert_last(section->kv, kv);
|
array_insert_create(§ion->kv, ARRAY_TAIL, kv);
|
||||||
|
array_sort(section->kv, kv_sort, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ /* replace with the most recently read value */
|
{ /* replace with the most recently read value */
|
||||||
@@ -1222,37 +1228,37 @@ static void section_extend(section_t *base, section_t *extension)
|
|||||||
section_t *sec;
|
section_t *sec;
|
||||||
kv_t *kv;
|
kv_t *kv;
|
||||||
|
|
||||||
enumerator = extension->sections->create_enumerator(extension->sections);
|
enumerator = array_create_enumerator(extension->sections);
|
||||||
while (enumerator->enumerate(enumerator, (void**)&sec))
|
while (enumerator->enumerate(enumerator, (void**)&sec))
|
||||||
{
|
{
|
||||||
section_t *found;
|
section_t *found;
|
||||||
if (base->sections->find_first(base->sections,
|
if (array_bsearch(base->sections, sec->name, section_find,
|
||||||
(linked_list_match_t)section_find, (void**)&found,
|
&found) != -1)
|
||||||
sec->name) == SUCCESS)
|
|
||||||
{
|
{
|
||||||
section_extend(found, sec);
|
section_extend(found, sec);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
extension->sections->remove_at(extension->sections, enumerator);
|
array_remove_at(extension->sections, enumerator);
|
||||||
base->sections->insert_last(base->sections, sec);
|
array_insert_create(&base->sections, ARRAY_TAIL, sec);
|
||||||
|
array_sort(base->sections, section_sort, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
enumerator = extension->kv->create_enumerator(extension->kv);
|
enumerator = array_create_enumerator(extension->kv);
|
||||||
while (enumerator->enumerate(enumerator, (void**)&kv))
|
while (enumerator->enumerate(enumerator, (void**)&kv))
|
||||||
{
|
{
|
||||||
kv_t *found;
|
kv_t *found;
|
||||||
if (base->kv->find_first(base->kv, (linked_list_match_t)kv_find,
|
if (array_bsearch(base->kv, kv->key, kv_find, &found) != -1)
|
||||||
(void**)&found, kv->key) == SUCCESS)
|
|
||||||
{
|
{
|
||||||
found->value = kv->value;
|
found->value = kv->value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
extension->kv->remove_at(extension->kv, enumerator);
|
array_remove_at(extension->kv, enumerator);
|
||||||
base->kv->insert_last(base->kv, kv);
|
array_insert_create(&base->kv, ARRAY_TAIL, kv);
|
||||||
|
array_sort(base->kv, kv_sort, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
|||||||
Reference in New Issue
Block a user