diff --git a/include/haproxy/hlua-t.h b/include/haproxy/hlua-t.h index 9716868f8..ac0b7d541 100644 --- a/include/haproxy/hlua-t.h +++ b/include/haproxy/hlua-t.h @@ -255,6 +255,7 @@ struct hlua_patref_iterator_context { struct hlua_patref *ref; struct bref bref; /* back-reference from the pat_ref_elt being accessed * during listing */ + struct pat_ref_gen *gen; /* the generation we are iterating over */ }; #else /* USE_LUA */ diff --git a/include/haproxy/pattern-t.h b/include/haproxy/pattern-t.h index a78c98443..42da6ed33 100644 --- a/include/haproxy/pattern-t.h +++ b/include/haproxy/pattern-t.h @@ -107,6 +107,7 @@ struct pat_ref { struct list list; /* Used to chain refs. */ char *reference; /* The reference name. */ char *display; /* String displayed to identify the pattern origin. */ + struct ceb_root *gen_root; /* The tree mapping generation IDs to pattern reference elements */ struct list head; /* The head of the list of struct pat_ref_elt. */ struct ceb_root *ceb_root; /* The tree where pattern reference elements are attached. */ struct list pat; /* The head of the list of struct pattern_expr. */ @@ -121,6 +122,16 @@ struct pat_ref { event_hdl_sub_list e_subs; /* event_hdl: pat_ref's subscribers list (atomically updated) */ }; +/* This struct represents all the elements in a pattern reference generation. The tree + * is used most of the time, but we also maintain a list for when order matters. + */ +struct pat_ref_gen { + struct list head; /* The head of the list of struct pat_ref_elt. */ + struct ceb_root *elt_root; /* The tree where pattern reference elements are attached. */ + struct ceb_node gen_node; /* Linkage for the gen_root cebtree in struct pat_ref */ + unsigned int gen_id; +}; + /* This is a part of struct pat_ref. Each entry contains one pattern and one * associated value as original string. All derivative forms (via exprs) are * accessed from list_head or tree_head. Be careful, it's variable-sized! diff --git a/include/haproxy/pattern.h b/include/haproxy/pattern.h index 1f3fdf164..73245096b 100644 --- a/include/haproxy/pattern.h +++ b/include/haproxy/pattern.h @@ -191,6 +191,8 @@ struct pat_ref_elt *pat_ref_find_elt(struct pat_ref *ref, const char *key); struct pat_ref_elt *pat_ref_gen_find_elt(struct pat_ref *ref, unsigned int gen_id, const char *key); struct pat_ref_elt *pat_ref_append(struct pat_ref *ref, const char *pattern, const char *sample, int line); struct pat_ref_elt *pat_ref_load(struct pat_ref *ref, unsigned int gen, const char *pattern, const char *sample, int line, char **err); +struct pat_ref_gen *pat_ref_gen_new(struct pat_ref *ref, unsigned int gen_id); +struct pat_ref_gen *pat_ref_gen_get(struct pat_ref *ref, unsigned int gen_id); 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); diff --git a/src/map.c b/src/map.c index 7a6bd36f6..b02224d8d 100644 --- a/src/map.c +++ b/src/map.c @@ -362,6 +362,7 @@ struct show_map_ctx { unsigned int display_flags; unsigned int curr_gen; /* current/latest generation, for show/clear */ unsigned int prev_gen; /* prev generation, for clear */ + struct pat_ref_gen *gen; /* link to the generation being displayed, for show */ enum { STATE_INIT = 0, /* initialize list and backrefs */ STATE_LIST, /* list entries */ diff --git a/src/pattern.c b/src/pattern.c index 0c662a989..8270d3640 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,18 @@ #include +/* Convenience macros for iterating over generations. */ +#define pat_ref_gen_foreach(gen, ref) \ + for (gen = cebu32_item_first(&ref->gen_root, gen_node, gen_id, struct pat_ref_gen); \ + gen; \ + gen = cebu32_item_next(&ref->gen_root, gen_node, gen_id, gen)) + +/* Safe variant that allows deleting an entry in the body of the loop. */ +#define pat_ref_gen_foreach_safe(gen, next, ref) \ + for (gen = cebu32_item_first(&ref->gen_root, gen_node, gen_id, struct pat_ref_gen); \ + gen && (next = cebu32_item_next(&ref->gen_root, gen_node, gen_id, gen), 1); \ + gen = next) + const char *const pat_match_names[PAT_MATCH_NUM] = { [PAT_MATCH_FOUND] = "found", [PAT_MATCH_BOOL] = "bool", @@ -1621,6 +1634,37 @@ int pat_ref_delete_by_id(struct pat_ref *ref, struct pat_ref_elt *refelt) return 0; } +/* Create a new generation object. + * + * Returns NULL in case of memory allocation failure. + */ +struct pat_ref_gen *pat_ref_gen_new(struct pat_ref *ref, unsigned int gen_id) +{ + struct pat_ref_gen *gen, *old; + + gen = calloc(1, sizeof(struct pat_ref_gen)); + if (!gen) + return NULL; + + LIST_INIT(&gen->head); + ceb_init_root(&gen->elt_root); + gen->gen_id = gen_id; + + old = cebu32_item_insert(&ref->gen_root, gen_node, gen_id, gen); + BUG_ON(old != gen, "Generation ID already exists"); + + return gen; +} + +/* Find the generation in the pattern reference . + * + * Returns NULL if the generation cannot be found. + */ +struct pat_ref_gen *pat_ref_gen_get(struct pat_ref *ref, unsigned int gen_id) +{ + return cebu32_item_lookup(&ref->gen_root, gen_node, gen_id, gen_id, struct pat_ref_gen); +} + /* This function removes all elements belonging to and matching * from the reference . * This function returns 1 if the deletion is done and returns 0 if