Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f05a4819 authored by Alexander Duyck's avatar Alexander Duyck Committed by David S. Miller
Browse files

fib_trie: Add functions should_inflate and should_halve



This change pulls the logic for if we should inflate/halve the nodes out
into separate functions.  It also addresses what I believe is a bug where 1
full node is all that is needed to keep a node from ever being halved.

Simple script to reproduce the issue:
	modprobe dummy;	ifconfig dummy0 up
	for i in `seq 0 255`; do ifconfig dummy0:$i 10.0.${i}.1/24 up; done
	ifconfig dummy0:256 10.0.255.33/16 up
	for i in `seq 0 254`; do ifconfig dummy0:$i down; done

Results from /proc/net/fib_triestat
Before:
	Local:
		Aver depth:     3.00
		Max depth:      4
		Leaves:         17
		Prefixes:       18
		Internal nodes: 11
		  1: 8  2: 2  10: 1
		Pointers: 1048
	Null ptrs: 1021
	Total size: 11  kB
After:
	Local:
		Aver depth:     3.41
		Max depth:      5
		Leaves:         17
		Prefixes:       18
		Internal nodes: 12
		  1: 8  2: 3  3: 1
		Pointers: 36
	Null ptrs: 8
	Total size: 3  kB

Signed-off-by: default avatarAlexander Duyck <alexander.h.duyck@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cf3637bb
Loading
Loading
Loading
Loading
+89 −86
Original line number Diff line number Diff line
@@ -647,34 +647,7 @@ static struct tnode *halve(struct trie *t, struct tnode *oldtnode)
	return ERR_PTR(-ENOMEM);
}

#define MAX_WORK 10
static struct tnode *resize(struct trie *t, struct tnode *tn)
{
	struct tnode *old_tn, *n = NULL;
	int inflate_threshold_use;
	int halve_threshold_use;
	int max_work;

	if (!tn)
		return NULL;

	pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
		 tn, inflate_threshold, halve_threshold);

	/* No children */
	if (tn->empty_children > (tnode_child_length(tn) - 1))
		goto no_children;

	/* One child */
	if (tn->empty_children == (tnode_child_length(tn) - 1))
		goto one_child;
	/*
	 * Double as long as the resulting node has a number of
	 * nonempty nodes that are above the threshold.
	 */

	/*
	 * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
/* From "Implementing a dynamic compressed trie" by Stefan Nilsson of
 * the Helsinki University of Technology and Matti Tikkanen of Nokia
 * Telecommunications, page 6:
 * "A node is doubled if the ratio of non-empty children to all
@@ -731,23 +704,58 @@ static struct tnode *resize(struct trie *t, struct tnode *tn)
 *    tnode_child_length(tn)
 *
 */
static bool should_inflate(const struct tnode *tn)
{
	unsigned long used = tnode_child_length(tn);
	unsigned long threshold = used;

	/* Keep root node larger */
	threshold *= node_parent(tn) ? inflate_threshold :
				       inflate_threshold_root;
	used += tn->full_children;
	used -= tn->empty_children;

	if (!node_parent(tn)) {
		inflate_threshold_use = inflate_threshold_root;
		halve_threshold_use = halve_threshold_root;
	} else {
		inflate_threshold_use = inflate_threshold;
		halve_threshold_use = halve_threshold;
	return tn->pos && ((50 * used) >= threshold);
}

	max_work = MAX_WORK;
	while ((tn->full_children > 0 &&  max_work-- &&
		50 * (tn->full_children + tnode_child_length(tn)
		      - tn->empty_children)
		>= inflate_threshold_use * tnode_child_length(tn))) {
static bool should_halve(const struct tnode *tn)
{
	unsigned long used = tnode_child_length(tn);
	unsigned long threshold = used;

	/* Keep root node larger */
	threshold *= node_parent(tn) ? halve_threshold :
				       halve_threshold_root;
	used -= tn->empty_children;

	return (tn->bits > 1) && ((100 * used) < threshold);
}

#define MAX_WORK 10
static struct tnode *resize(struct trie *t, struct tnode *tn)
{
	struct tnode *old_tn, *n = NULL;
	int max_work;

	if (!tn)
		return NULL;

	pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
		 tn, inflate_threshold, halve_threshold);

	/* No children */
	if (tn->empty_children > (tnode_child_length(tn) - 1))
		goto no_children;

	/* One child */
	if (tn->empty_children == (tnode_child_length(tn) - 1))
		goto one_child;

	/* Double as long as the resulting node has a number of
	 * nonempty nodes that are above the threshold.
	 */
	max_work = MAX_WORK;
	while (should_inflate(tn) && max_work--) {
		old_tn = tn;
		tn = inflate(t, tn);

@@ -764,16 +772,11 @@ static struct tnode *resize(struct trie *t, struct tnode *tn)
	if (max_work != MAX_WORK)
		return tn;

	/*
	 * Halve as long as the number of empty children in this
	/* Halve as long as the number of empty children in this
	 * node is above threshold.
	 */

	max_work = MAX_WORK;
	while (tn->bits > 1 &&  max_work-- &&
	       100 * (tnode_child_length(tn) - tn->empty_children) <
	       halve_threshold_use * tnode_child_length(tn)) {

	while (should_halve(tn) && max_work--) {
		old_tn = tn;
		tn = halve(t, tn);
		if (IS_ERR(tn)) {