From: Willy Tarreau Date: Mon, 2 Nov 2020 16:30:17 +0000 (+0100) Subject: MINOR: pattern: introduce pat_ref_delete_by_ptr() to delete a valid reference X-Git-Tag: v2.4-dev1~89 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1fd52f70e59ca87307d1599d63efae041e8f27f1;p=thirdparty%2Fhaproxy.git MINOR: pattern: introduce pat_ref_delete_by_ptr() to delete a valid reference Till now the only way to remove a known reference was via pat_ref_delete_by_id() which scans the whole list to find a matching pointer. Let's add pat_ref_delete_by_ptr() which takes a valid pointer. It can be called by the function above after the pointer is found, and can also be used to roll back a failed insertion much more efficiently. --- diff --git a/include/haproxy/pattern.h b/include/haproxy/pattern.h index b6f1a38560..112d5af487 100644 --- a/include/haproxy/pattern.h +++ b/include/haproxy/pattern.h @@ -187,6 +187,7 @@ int pat_ref_add(struct pat_ref *ref, const char *pattern, const char *sample, ch int pat_ref_set(struct pat_ref *ref, const char *pattern, const char *sample, char **err); 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); int pat_ref_delete_by_id(struct pat_ref *ref, struct pat_ref_elt *refelt); int pat_ref_prune(struct pat_ref *ref); int pat_ref_load(struct pat_ref *ref, struct pattern_expr *expr, int patflags, int soe, char **err); diff --git a/src/pattern.c b/src/pattern.c index 6659364c78..7f4f44958b 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -1485,100 +1485,78 @@ struct pat_ref *pat_ref_lookupid(int unique_id) return NULL; } +/* This function removes from the pattern reference all the patterns + * attached to the reference element , and the element itself. The + * reference must be locked. + */ +void pat_ref_delete_by_ptr(struct pat_ref *ref, struct pat_ref_elt *elt) +{ + struct pattern_expr *expr; + struct bref *bref, *back; + + /* + * we have to unlink all watchers from this reference pattern. We must + * not relink them if this elt was the last one in the list. + */ + list_for_each_entry_safe(bref, back, &elt->back_refs, users) { + LIST_DEL(&bref->users); + LIST_INIT(&bref->users); + if (elt->list.n != &ref->head) + LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users); + bref->ref = elt->list.n; + } + + /* delete all entries from all expressions for this pattern */ + list_for_each_entry(expr, &ref->pat, list) + HA_RWLOCK_WRLOCK(PATEXP_LOCK, &expr->lock); + + pat_delete_gen(ref, elt); + + list_for_each_entry(expr, &ref->pat, list) + HA_RWLOCK_WRUNLOCK(PATEXP_LOCK, &expr->lock); + + LIST_DEL(&elt->list); + free(elt->sample); + free(elt->pattern); + free(elt); +} + /* This function removes all the patterns matching the pointer from * the reference and from each expr member of this reference. This function * returns 1 if the entry was found and deleted, otherwise zero. */ int pat_ref_delete_by_id(struct pat_ref *ref, struct pat_ref_elt *refelt) { - struct pattern_expr *expr; struct pat_ref_elt *elt, *safe; - struct bref *bref, *back; /* delete pattern from reference */ list_for_each_entry_safe(elt, safe, &ref->head, list) { if (elt == refelt) { - list_for_each_entry_safe(bref, back, &elt->back_refs, users) { - /* - * we have to unlink all watchers. We must not relink them if - * this elt was the last one in the list. - */ - LIST_DEL(&bref->users); - LIST_INIT(&bref->users); - if (elt->list.n != &ref->head) - LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users); - bref->ref = elt->list.n; - } - - /* delete all entries from all expressions for this pattern */ - list_for_each_entry(expr, &ref->pat, list) - HA_RWLOCK_WRLOCK(PATEXP_LOCK, &expr->lock); - - pat_delete_gen(ref, elt); - - list_for_each_entry(expr, &ref->pat, list) - HA_RWLOCK_WRUNLOCK(PATEXP_LOCK, &expr->lock); - - /* pat_ref_elt is trashed once all expr - are cleaned and there is no ref remaining */ - LIST_DEL(&elt->list); - free(elt->sample); - free(elt->pattern); - free(elt); + pat_ref_delete_by_ptr(ref, elt); return 1; } } return 0; } -/* This function remove all pattern match from the the reference +/* This function removes all patterns matching from the reference * and from each expr member of the reference. This function returns 1 - * if the deletion is done and return 0 is the entry is not found. + * if the deletion is done and returns 0 is the entry is not found. */ int pat_ref_delete(struct pat_ref *ref, const char *key) { - struct pattern_expr *expr; struct pat_ref_elt *elt, *safe; - struct bref *bref, *back; int found = 0; /* delete pattern from reference */ list_for_each_entry_safe(elt, safe, &ref->head, list) { if (strcmp(key, elt->pattern) == 0) { - list_for_each_entry_safe(bref, back, &elt->back_refs, users) { - /* - * we have to unlink all watchers. We must not relink them if - * this elt was the last one in the list. - */ - LIST_DEL(&bref->users); - LIST_INIT(&bref->users); - if (elt->list.n != &ref->head) - LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users); - bref->ref = elt->list.n; - } - - list_for_each_entry(expr, &ref->pat, list) - HA_RWLOCK_WRLOCK(PATEXP_LOCK, &expr->lock); - - pat_delete_gen(ref, elt); - - list_for_each_entry(expr, &ref->pat, list) - HA_RWLOCK_WRUNLOCK(PATEXP_LOCK, &expr->lock); - - /* pat_ref_elt is trashed once all expr - are cleaned and there is no ref remaining */ - LIST_DEL(&elt->list); - free(elt->sample); - free(elt->pattern); - free(elt); - + pat_ref_delete_by_ptr(ref, elt); found = 1; } } - if (!found) - return 0; - return 1; + return found; } /* @@ -1897,7 +1875,7 @@ int pat_ref_add(struct pat_ref *ref, list_for_each_entry(expr, &ref->pat, list) { if (!pat_ref_push(elt, expr, 0, err)) { /* If the insertion fails, try to delete all the added entries. */ - pat_ref_delete_by_id(ref, elt); + pat_ref_delete_by_ptr(ref, elt); return 0; } }