All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrey Sidorov <qrxd43@motorola.com>
To: linux-ext4@vger.kernel.org
Subject: [PATCH 4/5] libext2fs: ffz/ffs for rb_tree bitmap
Date: Tue, 19 Mar 2013 20:06:03 +0400	[thread overview]
Message-ID: <1363709164-3210-5-git-send-email-qrxd43@motorola.com> (raw)
In-Reply-To: <1363709164-3210-1-git-send-email-qrxd43@motorola.com>

find_first_zero / find_first_set Implementation for
rb_tree bitmap. Use of rcursor / rcursor_next makes
successive ffs/ffz/ffs/... calls to be equivalent of
iterating tree via ext2fs_rb_next.

Signed-off-by: Andrey Sidorov <qrxd43@motorola.com>
---
 lib/ext2fs/blkmap64_rb.c |  164 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 156 insertions(+), 8 deletions(-)

diff --git a/lib/ext2fs/blkmap64_rb.c b/lib/ext2fs/blkmap64_rb.c
index 702187f..76c525e 100644
--- a/lib/ext2fs/blkmap64_rb.c
+++ b/lib/ext2fs/blkmap64_rb.c
@@ -51,6 +51,21 @@ static int rb_insert_extent(__u64 start, __u64 count,
 			    struct ext2fs_rb_private *);
 static void rb_get_new_extent(struct bmap_rb_extent **, __u64, __u64);
 
+static inline struct bmap_rb_extent *
+rb_load_next_cursor(struct ext2fs_rb_private *bp)
+{
+	if (!bp->rcursor_next && bp->rcursor) {
+		struct rb_node *node;
+		node = ext2fs_rb_next(&bp->rcursor->node);
+		if (!node)
+			return NULL;
+		bp->rcursor_next = ext2fs_rb_entry(node,
+						   struct bmap_rb_extent,
+						   node);
+	}
+	return bp->rcursor_next;
+}
+
 /* #define DEBUG_RB */
 
 #ifdef DEBUG_RB
@@ -324,14 +339,7 @@ rb_test_bit(struct ext2fs_rb_private *bp, __u64 bit)
 		return 1;
 	}
 
-	next_ext = bp->rcursor_next;
-	if (!next_ext) {
-		next = ext2fs_rb_next(&rcursor->node);
-		if (next)
-			next_ext = ext2fs_rb_entry(next, struct bmap_rb_extent,
-						   node);
-		bp->rcursor_next = next_ext;
-	}
+	next_ext = rb_load_next_cursor(bp);
 	if (next_ext) {
 		if ((bit >= rcursor->start + rcursor->count) &&
 		    (bit < next_ext->start)) {
@@ -855,6 +863,144 @@ static void rb_print_stats(ext2fs_generic_bitmap bitmap)
 static void rb_print_stats(ext2fs_generic_bitmap bitmap){}
 #endif
 
+/* Find the first zero bit between start and end, inclusive. */
+static errcode_t rb_find_first_zero(ext2fs_generic_bitmap bitmap,
+				    __u64 start, __u64 end, __u64 *out)
+{
+	struct ext2fs_rb_private *bp = bitmap->private;
+	struct rb_node *parent = NULL;
+	struct rb_node **n = &bp->root.rb_node;
+	struct bmap_rb_extent *ext = bp->rcursor;
+
+	start -= bitmap->start;
+	end -= bitmap->start;
+
+	if (!ext)
+		goto search_tree;
+
+	if (start >= ext->start) {
+		if (start <= ext->start + ext->count) {
+			goto match;
+		}
+		ext = rb_load_next_cursor(bp);
+		if (ext && start <= ext->start + ext->count) {
+			if (start >= ext->start) {
+				bp->rcursor = ext;
+				bp->rcursor_next = NULL;
+			}
+			goto match;
+		}
+	}
+
+search_tree:
+	while (*n) {
+		parent = *n;
+		ext = ext2fs_rb_entry(parent, struct bmap_rb_extent, node);
+
+		if (start < ext->start) {
+			n = &(*n)->rb_left;
+		} else if (start >= (ext->start + ext->count)) {
+			n = &(*n)->rb_right;
+		} else {
+			break;
+		}
+	}
+	bp->rcursor = ext;
+	bp->rcursor_next = NULL;
+
+match:
+	if (ext) {
+		if (start >= ext->start && start <= ext->start + ext->count) {
+			if (ext->start + ext->count <= end) {
+				*out = bitmap->start + ext->start + ext->count;
+				return 0;
+			}
+			else {
+				return ENOENT;
+			}
+		}
+		else {
+			*out = bitmap->start + start;
+			return 0;
+		}
+	}
+
+	*out = bitmap->start;
+	return 0;
+}
+
+/* Find the first set bit between start and end, inclusive. */
+static errcode_t rb_find_first_set(ext2fs_generic_bitmap bitmap,
+				   __u64 start, __u64 end, __u64 *out)
+{
+	struct ext2fs_rb_private *bp = bitmap->private;
+	struct rb_node *parent = NULL;
+	struct rb_node **n = &bp->root.rb_node;
+	struct bmap_rb_extent *ext = bp->rcursor;
+
+	start -= bitmap->start;
+	end -= bitmap->start;
+
+	if (!ext)
+		goto search_tree;
+
+	if (start >= ext->start) {
+		if (start < ext->start + ext->count) {
+			*out = bitmap->start + start;
+			return 0;
+		}
+
+		ext = rb_load_next_cursor(bp);
+		if (!ext)
+			return ENOENT;
+		if (start < ext->start + ext->count) {
+			bp->rcursor = ext;
+			bp->rcursor_next = NULL;
+			goto match;
+		}
+	}
+
+search_tree:
+	while (*n) {
+		parent = *n;
+		ext = ext2fs_rb_entry(parent, struct bmap_rb_extent, node);
+
+		if (start < ext->start) {
+			n = &(*n)->rb_left;
+		} else if (start >= (ext->start + ext->count)) {
+			n = &(*n)->rb_right;
+		} else {
+			break;
+		}
+	}
+
+	if (ext && start >= ext->start + ext->count) {
+		struct rb_node *next = ext2fs_rb_next(parent);
+		if (next)
+			ext = ext2fs_rb_entry(next, struct bmap_rb_extent,
+					      node);
+	}
+
+	bp->rcursor = ext;
+	bp->rcursor_next = NULL;
+
+match:
+	if (ext) {
+		if (start < ext->start) {
+			if (ext->start <= end) {
+				*out = bitmap->start + ext->start;
+				return 0;
+			}
+		}
+		else if (start < ext->start + ext->count) {
+			*out = bitmap->start + start;
+			return 0;
+		}
+	}
+
+	return ENOENT;
+}
+
 struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = {
 	.type = EXT2FS_BMAP64_RBTREE,
 	.new_bmap = rb_new_bmap,
@@ -871,4 +1017,6 @@ struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = {
 	.get_bmap_range = rb_get_bmap_range,
 	.clear_bmap = rb_clear_bmap,
 	.print_stats = rb_print_stats,
+	.find_first_zero = rb_find_first_zero,
+	.find_first_set = rb_find_first_set,
 };
-- 
1.7.10.4


  parent reply	other threads:[~2013-03-19 16:06 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-03-19 16:05 [PATCH 0/5] mke2fs/e2fsck optimizations Andrey Sidorov
2013-03-19 16:06 ` [PATCH 1/5] libext2fs: Optimize ext2fs_allocate_group_table() Andrey Sidorov
2013-03-19 16:06 ` [PATCH 2/5] libext2fs: find_first_set() for bitmaps Andrey Sidorov
2013-03-19 16:06 ` [PATCH 3/5] libext2fs: find_first_set() for bitarray bitmap Andrey Sidorov
2013-03-19 16:06 ` Andrey Sidorov [this message]
2013-03-19 16:06 ` [PATCH 5/5] libext2fs: Optimize ext2fs_convert_subcluster_bitmap() Andrey Sidorov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1363709164-3210-5-git-send-email-qrxd43@motorola.com \
    --to=qrxd43@motorola.com \
    --cc=linux-ext4@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.