mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-23 13:17:16 +00:00
BUG/MAJOR: ebtree/scope: fix insertion and removal of duplicates in scope-aware trees
Commit ca30839
and following ("MINOR: ebtree: implement the scope-aware
functions for eb32") improperly dealt with the scope in duplicate trees.
The insertion was too lenient in that it would always mark the whole
rightmost chain below the insertion point, and the removal could leave
marks of non-existing scopes causing next()/first() to visit the wrong
branch and return NULL.
For insertion, we must only tag the nodes between the head of the dup
tree and the insertion point which is the top of the lowest subtree. For
removal, the new scope must be be calculated by oring the scopes of the
two new branches and is irrelevant to the previous values.
No backport is needed, this is purely 1.8-specific.
This commit is contained in:
parent
fa5c812a6b
commit
d19ec7d502
@ -40,13 +40,23 @@ REGPRM1 struct eb32sc_node *eb32sc_insert_dup(struct eb_node *sub, struct eb_nod
|
||||
|
||||
head = container_of(eb_untag(head->branches.b[EB_RGHT], EB_NODE),
|
||||
struct eb_node, branches);
|
||||
|
||||
if (unlikely(head->bit > last->bit + 1)) {
|
||||
/* there's a hole here, we must assign the top of the
|
||||
* following sub-tree to <sub> and mark all intermediate
|
||||
* nodes with the scope mask.
|
||||
*/
|
||||
do {
|
||||
eb32 = container_of(sub, struct eb32sc_node, node);
|
||||
if (!(eb32->node_s & scope))
|
||||
eb32->node_s |= scope;
|
||||
|
||||
sub = container_of(eb_untag(sub->branches.b[EB_RGHT], EB_NODE),
|
||||
struct eb_node, branches);
|
||||
} while (sub != head);
|
||||
}
|
||||
|
||||
eb32 = container_of(head, struct eb32sc_node, node);
|
||||
|
||||
if (head->bit > last->bit + 1)
|
||||
sub = head; /* there's a hole here */
|
||||
|
||||
if ((eb32->node_s | scope) != eb32->node_s)
|
||||
eb32->node_s |= scope;
|
||||
}
|
||||
|
||||
/* Here we have a leaf attached to (head)->b[EB_RGHT] */
|
||||
@ -423,6 +433,7 @@ void eb32sc_delete(struct eb32sc_node *eb32)
|
||||
unsigned int pside, gpside, sibtype;
|
||||
struct eb_node *parent;
|
||||
struct eb_root *gparent;
|
||||
unsigned long scope;
|
||||
|
||||
if (!node->leaf_p)
|
||||
return;
|
||||
@ -486,7 +497,6 @@ void eb32sc_delete(struct eb32sc_node *eb32)
|
||||
parent->node_p = node->node_p;
|
||||
parent->branches = node->branches;
|
||||
parent->bit = node->bit;
|
||||
container_of(parent, struct eb32sc_node, node)->node_s |= eb32->node_s;
|
||||
|
||||
/* We must now update the new node's parent... */
|
||||
gpside = eb_gettag(parent->node_p);
|
||||
@ -494,15 +504,20 @@ void eb32sc_delete(struct eb32sc_node *eb32)
|
||||
gparent->b[gpside] = eb_dotag(&parent->branches, EB_NODE);
|
||||
|
||||
/* ... and its branches */
|
||||
scope = 0;
|
||||
for (pside = 0; pside <= 1; pside++) {
|
||||
if (eb_gettag(parent->branches.b[pside]) == EB_NODE) {
|
||||
eb_root_to_node(eb_untag(parent->branches.b[pside], EB_NODE))->node_p =
|
||||
eb_dotag(&parent->branches, pside);
|
||||
scope |= container_of(eb_untag(parent->branches.b[pside], EB_NODE), struct eb32sc_node, node.branches)->node_s;
|
||||
} else {
|
||||
eb_root_to_node(eb_untag(parent->branches.b[pside], EB_LEAF))->leaf_p =
|
||||
eb_dotag(&parent->branches, pside);
|
||||
scope |= container_of(eb_untag(parent->branches.b[pside], EB_LEAF), struct eb32sc_node, node.branches)->leaf_s;
|
||||
}
|
||||
}
|
||||
container_of(parent, struct eb32sc_node, node)->node_s = scope;
|
||||
|
||||
delete_unlink:
|
||||
/* Now the node has been completely unlinked */
|
||||
node->leaf_p = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user