Organize reference to pattern element of map (struct pat_ref_elt) into an ebtree:
- add an eb_root member to the map (pat_ref struct) and an ebpt_node to its
element (pat_ref_elt struct),
- modify the code to insert these nodes into their ebtrees each time they are
allocated. This is done in pat_ref_append().
Note that ->head member (struct list) of map (struct pat_ref) is not removed
could have been removed. This is not the case because still necessary to dump
the map contents from the CLI in the order the map elememnts have been inserted.
This patch also modifies http_action_set_map() which is the callback at least
used by "set-map" action. The pat_ref_elt element returned by pat_ref_find_elt()
is no more ignored, but reused if not NULL by pat_ref_set() as first element to
lookup from. This latter is also modified to use the ebtree attached to the map
in place of the ->head list attached to each map element (pat_ref_elt struct).
Also modify pat_ref_find_elt() to makes it use ->eb_root map ebtree added to the
map by this patch in place of inspecting all the elements with a strcmp() call.
char *reference; /* The reference name. */
char *display; /* String displayed to identify the pattern origin. */
struct list head; /* The head of the list of struct pat_ref_elt. */
+ struct eb_root ebpt_root; /* The tree where pattern reference elements are attached. */
struct list pat; /* The head of the list of struct pattern_expr. */
unsigned int flags; /* flags PAT_REF_*. */
unsigned int curr_gen; /* current generation number (anything below can be removed) */
*/
struct pat_ref_elt {
struct list list; /* Used to chain elements. */
+ struct ebpt_node node; /* Node to attach this element to its <pat_ref> ebtree. */
struct list back_refs; /* list of users tracking this pat ref */
void *list_head; /* all &pattern_list->from_ref derived from this reference, ends with NULL */
void *tree_head; /* all &pattern_tree->from_ref derived from this reference, ends with NULL */
struct pat_ref_elt *pat_ref_load(struct pat_ref *ref, unsigned int gen, const char *pattern, const char *sample, int line, char **err);
int pat_ref_push(struct pat_ref_elt *elt, struct pattern_expr *expr, int patflags, char **err);
int pat_ref_add(struct pat_ref *ref, const char *pattern, const char *sample, char **err);
-int pat_ref_set(struct pat_ref *ref, const char *pattern, const char *sample, char **err);
+int pat_ref_set(struct pat_ref *ref, const char *pattern, const char *sample, char **err, struct pat_ref_elt *elt);
int pat_ref_set_by_id(struct pat_ref *ref, struct pat_ref_elt *refelt, const char *value, char **err);
int pat_ref_delete(struct pat_ref *ref, const char *key);
void pat_ref_delete_by_ptr(struct pat_ref *ref, struct pat_ref_elt *elt);
HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
if (pat_ref_find_elt(ref, key) != NULL)
- pat_ref_set(ref, key, value, NULL);
+ pat_ref_set(ref, key, value, NULL, NULL);
else
pat_ref_add(ref, key, value, NULL);
HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
break;
case 1: // set-map
+ {
+ struct pat_ref_elt *elt;
+
/* allocate value */
value = alloc_trash_chunk();
if (!value)
value->area[value->data] = '\0';
HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
- if (pat_ref_find_elt(ref, key->area) != NULL) {
+ elt = pat_ref_find_elt(ref, key->area);
+ if (elt) {
/* update entry if it exists */
- pat_ref_set(ref, key->area, value->area, NULL);
+ pat_ref_set(ref, key->area, value->area, NULL, elt);
}
else {
/* insert a new entry */
}
HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
break;
+ }
case 2: // del-acl
case 3: // del-map
*/
err = NULL;
HA_SPIN_LOCK(PATREF_LOCK, &ctx->ref->lock);
- if (!pat_ref_set(ctx->ref, args[3], args[4], &err)) {
+ if (!pat_ref_set(ctx->ref, args[3], args[4], &err, NULL)) {
HA_SPIN_UNLOCK(PATREF_LOCK, &ctx->ref->lock);
if (err)
return cli_dynerr(appctx, memprintf(&err, "%s.\n", err));
#include <stdio.h>
#include <errno.h>
+#include <import/ebistree.h>
+#include <import/ebpttree.h>
#include <import/ebsttree.h>
#include <import/lru.h>
HA_RWLOCK_WRUNLOCK(PATEXP_LOCK, &expr->lock);
LIST_DELETE(&elt->list);
+ ebpt_delete(&elt->node);
free(elt->sample);
free(elt->pattern);
free(elt);
*/
struct pat_ref_elt *pat_ref_find_elt(struct pat_ref *ref, const char *key)
{
- struct pat_ref_elt *elt;
+ struct ebpt_node *node;
- list_for_each_entry(elt, &ref->head, list) {
- if (strcmp(key, elt->pattern) == 0)
- return elt;
- }
+ node = ebis_lookup(&ref->ebpt_root, key);
+ if (node)
+ return ebpt_entry(node, struct pat_ref_elt, node);
return NULL;
}
/* This function modifies to <value> the sample of all patterns matching <key>
* under <ref>.
*/
-int pat_ref_set(struct pat_ref *ref, const char *key, const char *value, char **err)
+int pat_ref_set(struct pat_ref *ref, const char *key, const char *value, char **err, struct pat_ref_elt *elt)
{
- struct pat_ref_elt *elt;
int found = 0;
char *_merr;
char **merr;
+ struct ebpt_node *node;
if (err) {
merr = &_merr;
else
merr = NULL;
- /* Look for pattern in the reference. */
- list_for_each_entry(elt, &ref->head, list) {
- if (strcmp(key, elt->pattern) == 0) {
- if (!pat_ref_set_elt(ref, elt, value, merr)) {
- if (err && merr) {
- if (!found) {
- *err = *merr;
- } else {
- memprintf(err, "%s, %s", *err, *merr);
- ha_free(merr);
- }
+ if (elt) {
+ node = &elt->node;
+ }
+ else {
+ /* Look for pattern in the reference. */
+ node = ebis_lookup(&ref->ebpt_root, key);
+ }
+
+ while (node) {
+ elt = ebpt_entry(node, struct pat_ref_elt, node);
+ node = ebpt_next_dup(node);
+ if (!pat_ref_set_elt(ref, elt, value, merr)) {
+ if (err && merr) {
+ if (!found) {
+ *err = *merr;
+ } else {
+ memprintf(err, "%s, %s", *err, *merr);
+ ha_free(merr);
}
}
- found = 1;
}
+ found = 1;
}
if (!found) {
ref->entry_cnt = 0;
LIST_INIT(&ref->head);
+ ref->ebpt_root = EB_ROOT;
LIST_INIT(&ref->pat);
HA_SPIN_INIT(&ref->lock);
LIST_APPEND(&pattern_reference, &ref->list);
ref->next_gen = 0;
ref->unique_id = unique_id;
LIST_INIT(&ref->head);
+ ref->ebpt_root = EB_ROOT;
LIST_INIT(&ref->pat);
HA_SPIN_INIT(&ref->lock);
LIST_APPEND(&pattern_reference, &ref->list);
elt->list_head = NULL;
elt->tree_head = NULL;
LIST_APPEND(&ref->head, &elt->list);
+ elt->node.key = elt->pattern;
+ ebis_insert(&ref->ebpt_root, &elt->node);
return elt;
fail:
if (elt)
pat_delete_gen(ref, elt);
LIST_DELETE(&elt->list);
+ ebpt_delete(&elt->node);
free(elt->pattern);
free(elt->sample);
free(elt);