Blame SOURCES/bz1162216-gfs2_edit_savemeta_speed_up_is_block_in_per_node.patch

db8e98
commit 342ab070d42625e6e4b65caf66f7b7117f7d4509
db8e98
Author: Andrew Price <anprice@redhat.com>
db8e98
Date:   Wed Sep 2 14:12:31 2015 -0500
db8e98
db8e98
    gfs2_edit savemeta: speed up is_block_in_per_node()
db8e98
    
db8e98
    Previously is_block_in_per_node() called lgfs2_inode_read() and
db8e98
    do_dinode_extended() for each block and savemeta was spending the vast
db8e98
    majority of its time in this function according to perf. This patch
db8e98
    speeds up the lookups by keeping a tree of per_node block addresses
db8e98
    which can be quickly consulted. In my tests with a full 700G filesystem
db8e98
    this patch cuts the run time in half.
db8e98
    
db8e98
    Resolves: rhbz#1162216
db8e98
    Signed-off-by: Andrew Price <anprice@redhat.com>
db8e98
db8e98
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
db8e98
index b68b0ff..b08eb5e 100644
db8e98
--- a/gfs2/edit/savemeta.c
db8e98
+++ b/gfs2/edit/savemeta.c
db8e98
@@ -74,8 +74,70 @@ static int block_is_a_journal(void)
db8e98
 	return FALSE;
db8e98
 }
db8e98
 
db8e98
+struct osi_root per_node_tree;
db8e98
+struct per_node_node {
db8e98
+	struct osi_node node;
db8e98
+	uint64_t block;
db8e98
+};
db8e98
+
db8e98
+static void destroy_per_node_lookup(void)
db8e98
+{
db8e98
+	struct osi_node *n;
db8e98
+	struct per_node_node *pnp;
db8e98
+
db8e98
+	while ((n = osi_first(&per_node_tree))) {
db8e98
+		pnp = (struct per_node_node *)n;
db8e98
+		osi_erase(n, &per_node_tree);
db8e98
+		free(pnp);
db8e98
+	}
db8e98
+}
db8e98
+
db8e98
 static int block_is_in_per_node(void)
db8e98
 {
db8e98
+	struct per_node_node *pnp = (struct per_node_node *)per_node_tree.osi_node;
db8e98
+
db8e98
+	while (pnp) {
db8e98
+		if (block < pnp->block)
db8e98
+			pnp = (struct per_node_node *)pnp->node.osi_left;
db8e98
+		else if (block > pnp->block)
db8e98
+			pnp = (struct per_node_node *)pnp->node.osi_right;
db8e98
+		else
db8e98
+			return 1;
db8e98
+	}
db8e98
+
db8e98
+	return 0;
db8e98
+}
db8e98
+
db8e98
+static int insert_per_node_lookup(uint64_t blk)
db8e98
+{
db8e98
+	struct osi_node **newn = &per_node_tree.osi_node, *parent = NULL;
db8e98
+	struct per_node_node *pnp;
db8e98
+
db8e98
+	while (*newn) {
db8e98
+		struct per_node_node *cur = (struct per_node_node *)*newn;
db8e98
+
db8e98
+		parent = *newn;
db8e98
+		if (blk < cur->block)
db8e98
+			newn = &((*newn)->osi_left);
db8e98
+		else if (blk > cur->block)
db8e98
+			newn = &((*newn)->osi_right);
db8e98
+		else
db8e98
+			return 0;
db8e98
+	}
db8e98
+
db8e98
+	pnp = calloc(1, sizeof(struct per_node_node));
db8e98
+	if (pnp == NULL) {
db8e98
+		perror("Failed to insert per_node lookup entry");
db8e98
+		return 1;
db8e98
+	}
db8e98
+	pnp->block = blk;
db8e98
+	osi_link_node(&pnp->node, parent, newn);
db8e98
+	osi_insert_color(&pnp->node, &per_node_tree);
db8e98
+	return 0;
db8e98
+}
db8e98
+
db8e98
+static int init_per_node_lookup(void)
db8e98
+{
db8e98
 	int i;
db8e98
 	struct gfs2_inode *per_node_di;
db8e98
 
db8e98
@@ -85,7 +147,7 @@ static int block_is_in_per_node(void)
db8e98
 	per_node_di = lgfs2_inode_read(&sbd, masterblock("per_node"));
db8e98
 	if (per_node_di == NULL) {
db8e98
 		fprintf(stderr, "Failed to read per_node: %s\n", strerror(errno));
db8e98
-		exit(1);
db8e98
+		return 1;
db8e98
 	}
db8e98
 
db8e98
 	do_dinode_extended(&per_node_di->i_di, per_node_di->i_bh);
db8e98
@@ -94,11 +156,12 @@ static int block_is_in_per_node(void)
db8e98
 	for (i = 0; i < indirect_blocks; i++) {
db8e98
 		int d;
db8e98
 		for (d = 0; d < indirect->ii[i].dirents; d++) {
db8e98
-			if (block == indirect->ii[i].dirent[d].block)
db8e98
-				return TRUE;
db8e98
+			int ret = insert_per_node_lookup(indirect->ii[i].dirent[d].block);
db8e98
+			if (ret != 0)
db8e98
+				return ret;
db8e98
 		}
db8e98
 	}
db8e98
-	return FALSE;
db8e98
+	return 0;
db8e98
 }
db8e98
 
db8e98
 static int block_is_systemfile(void)
db8e98
@@ -749,6 +812,10 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
db8e98
 	printf("Filesystem size: %s\n", anthropomorphize(sbd.fssize * sbd.bsize));
db8e98
 	get_journal_inode_blocks();
db8e98
 
db8e98
+	err = init_per_node_lookup();
db8e98
+	if (err)
db8e98
+		exit(1);
db8e98
+
db8e98
 	/* Write the savemeta file header */
db8e98
 	err = save_header(&mfd, sbd.fssize * sbd.bsize);
db8e98
 	if (err) {
db8e98
@@ -810,6 +877,7 @@ void savemeta(char *out_fn, int saveoption, int gziplevel)
db8e98
 	}
db8e98
 	savemetaclose(&mfd;;
db8e98
 	close(sbd.device_fd);
db8e98
+	destroy_per_node_lookup();
db8e98
 	free(indirect);
db8e98
 	gfs2_rgrp_free(&sbd.rgtree);
db8e98
 	exit(0);