Module Name:    src
Committed By:   reinoud
Date:           Tue Jul  7 10:23:36 UTC 2009

Modified Files:
        src/sys/fs/udf: udf.h udf_subr.c udf_subr.h udf_vfsops.c udf_vnops.c

Log Message:
Replace the old hashtable and sorted list implemenation by a RB-tree.

Benefits are significant speed improvements on node creation/insertion while
keeping the lookup times low and still allowing sequential iteration over the
nodes.


To generate a diff of this commit:
cvs rdiff -u -r1.35 -r1.36 src/sys/fs/udf/udf.h
cvs rdiff -u -r1.97 -r1.98 src/sys/fs/udf/udf_subr.c
cvs rdiff -u -r1.16 -r1.17 src/sys/fs/udf/udf_subr.h
cvs rdiff -u -r1.58 -r1.59 src/sys/fs/udf/udf_vfsops.c
cvs rdiff -u -r1.50 -r1.51 src/sys/fs/udf/udf_vnops.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/fs/udf/udf.h
diff -u src/sys/fs/udf/udf.h:1.35 src/sys/fs/udf/udf.h:1.36
--- src/sys/fs/udf/udf.h:1.35	Mon Jul  6 17:08:04 2009
+++ src/sys/fs/udf/udf.h	Tue Jul  7 10:23:36 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf.h,v 1.35 2009/07/06 17:08:04 reinoud Exp $ */
+/* $NetBSD: udf.h,v 1.36 2009/07/07 10:23:36 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -30,6 +30,7 @@
 #define _FS_UDF_UDF_H_
 
 #include <sys/queue.h>
+#include <sys/rb.h>
 #include <sys/uio.h>
 #include <sys/mutex.h>
 
@@ -333,8 +334,7 @@
 	/* hash table to lookup icb -> udf_node and sorted list for sync */
 	kmutex_t	ihash_lock;
 	kmutex_t	get_node_lock;
-	LIST_HEAD(, udf_node) udf_nodes[UDF_INODE_HASHSIZE];
-	LIST_HEAD(, udf_node) sorted_udf_nodes;		/* sorted sync list  */
+	struct rb_tree	udf_node_tree;
 
 	/* syncing */
 	int		syncing;			/* are we syncing?   */
@@ -354,6 +354,11 @@
 };
 
 
+#define RBTOUDFNODE(node) \
+	((node) ? \
+	 (void *)((uintptr_t)(node) - offsetof(struct udf_node, rbnode)) \
+	 : NULL)
+
 /*
  * UDF node describing a file/directory.
  *
@@ -369,6 +374,9 @@
 	char const		*lock_fname;
 	int			 lock_lineno;
 
+	/* rb_node for fast lookup and fast sequentual visiting */
+	struct rb_node		 rbnode;
+
 	/* one of `fe' or `efe' can be set, not both (UDF file entry dscr.)  */
 	struct file_entry	*fe;
 	struct extfile_entry	*efe;

Index: src/sys/fs/udf/udf_subr.c
diff -u src/sys/fs/udf/udf_subr.c:1.97 src/sys/fs/udf/udf_subr.c:1.98
--- src/sys/fs/udf/udf_subr.c:1.97	Mon Jul  6 17:06:57 2009
+++ src/sys/fs/udf/udf_subr.c	Tue Jul  7 10:23:36 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_subr.c,v 1.97 2009/07/06 17:06:57 reinoud Exp $ */
+/* $NetBSD: udf_subr.c,v 1.98 2009/07/07 10:23:36 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -29,7 +29,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.97 2009/07/06 17:06:57 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.98 2009/07/07 10:23:36 reinoud Exp $");
 #endif /* not lint */
 
 
@@ -3366,7 +3366,7 @@
 /* To make absolutely sure we are NOT returning zero, add one :) */
 
 long
-udf_calchash(struct long_ad *icbptr)
+udf_get_node_id(const struct long_ad *icbptr)
 {
 	/* ought to be enough since each mountpoint has its own chain */
 	return udf_rw32(icbptr->loc.lb_num) + 1;
@@ -3374,120 +3374,102 @@
 
 
 int
-udf_check_icb_equal(struct long_ad *a, struct long_ad *b)
+udf_compare_icb(const struct long_ad *a, const struct long_ad *b)
 {
-	return (a->loc.lb_num   == b->loc.lb_num &&
-	    a->loc.part_num == b->loc.part_num);
+	if (udf_rw16(a->loc.part_num) < udf_rw16(b->loc.part_num))
+		return -1;
+	if (udf_rw16(a->loc.part_num) > udf_rw16(b->loc.part_num))
+		return 1;
+
+	if (udf_rw32(a->loc.lb_num) < udf_rw32(b->loc.lb_num))
+		return -1;
+	if (udf_rw32(a->loc.lb_num) > udf_rw32(b->loc.lb_num))
+		return 1;
+
+	return 0;
 }
 
 
-static struct udf_node *
-udf_hash_lookup(struct udf_mount *ump, struct long_ad *icbptr)
+static int
+udf_compare_rbnodes(const struct rb_node *a, const struct rb_node *b)
 {
-	struct udf_node *node;
-	struct vnode *vp;
-	uint32_t hashline;
-
-loop:
-	mutex_enter(&ump->ihash_lock);
+	struct udf_node *a_node = RBTOUDFNODE(a);
+	struct udf_node *b_node = RBTOUDFNODE(b);
 
-	hashline = udf_calchash(icbptr) & UDF_INODE_HASHMASK;
-	LIST_FOREACH(node, &ump->udf_nodes[hashline], hashchain) {
-		assert(node);
-		if (udf_check_icb_equal(&node->loc, icbptr)) {
-			vp = node->vnode;
-			assert(vp);
-			mutex_enter(&vp->v_interlock);
-			mutex_exit(&ump->ihash_lock);
-			if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
-				goto loop;
-			return node;
-		}
-	}
-	mutex_exit(&ump->ihash_lock);
-
-	return NULL;
+	return udf_compare_icb(&a_node->loc, &b_node->loc);
 }
 
 
-static void
-udf_sorted_list_insert(struct udf_node *node)
+static int
+udf_compare_rbnode_icb(const struct rb_node *a, const void *key)
 {
-	struct udf_mount *ump;
-	struct udf_node  *s_node, *last_node;
-	uint32_t loc, s_loc;
+	struct udf_node *a_node = RBTOUDFNODE(a);
+	const struct long_ad * const icb = key;
 
-	ump = node->ump;
-	last_node = NULL;	/* XXX gcc */
+	return udf_compare_icb(&a_node->loc, icb);
+}
 
-	if (LIST_EMPTY(&ump->sorted_udf_nodes)) {
-		LIST_INSERT_HEAD(&ump->sorted_udf_nodes, node, sortchain);
-		return;
-	}
 
-	/*
-	 * We sort on logical block number here and not on physical block
-	 * number here. Ideally we should go for the physical block nr to get
-	 * better sync performance though this sort will ensure that packets
-	 * won't get spit up unnessisarily.
-	 */
+static const struct rb_tree_ops udf_node_rbtree_ops = {
+	.rbto_compare_nodes = udf_compare_rbnodes,
+	.rbto_compare_key   = udf_compare_rbnode_icb,
+};
 
-	loc = udf_rw32(node->loc.loc.lb_num);
-	LIST_FOREACH(s_node, &ump->sorted_udf_nodes, sortchain) {
-		s_loc = udf_rw32(s_node->loc.loc.lb_num);
-		if (s_loc > loc) {
-			LIST_INSERT_BEFORE(s_node, node, sortchain);
-			return;
-		}
-		last_node = s_node;
-	}
-	LIST_INSERT_AFTER(last_node, node, sortchain);
+
+void
+udf_init_nodes_tree(struct udf_mount *ump)
+{
+	rb_tree_init(&ump->udf_node_tree, &udf_node_rbtree_ops);
 }
 
 
-static void
-udf_register_node(struct udf_node *node)
+static struct udf_node *
+udf_node_lookup(struct udf_mount *ump, struct long_ad *icbptr)
 {
-	struct udf_mount *ump;
-	struct udf_node *chk;
-	uint32_t hashline;
+	struct rb_node  *rb_node;
+	struct udf_node *udf_node;
+	struct vnode *vp;
 
-	ump = node->ump;
+loop:
 	mutex_enter(&ump->ihash_lock);
 
-	/* add to our hash table */
-	hashline = udf_calchash(&node->loc) & UDF_INODE_HASHMASK;
-#ifdef DEBUG
-	LIST_FOREACH(chk, &ump->udf_nodes[hashline], hashchain) {
-		assert(chk);
-		if (chk->loc.loc.lb_num   == node->loc.loc.lb_num &&
-		    chk->loc.loc.part_num == node->loc.loc.part_num)
-			panic("Double node entered\n");
+	rb_node = rb_tree_find_node(&ump->udf_node_tree, icbptr);
+	if (rb_node) {
+		udf_node = RBTOUDFNODE(rb_node);
+		vp = udf_node->vnode;
+		assert(vp);
+		mutex_enter(&vp->v_interlock);
+		mutex_exit(&ump->ihash_lock);
+		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
+			goto loop;
+		return udf_node;
 	}
-#else
-	chk = NULL;
-#endif
-	LIST_INSERT_HEAD(&ump->udf_nodes[hashline], node, hashchain);
-
-	/* add to our sorted list */
-	udf_sorted_list_insert(node);
-
 	mutex_exit(&ump->ihash_lock);
+
+	return NULL;
 }
 
 
 static void
-udf_deregister_node(struct udf_node *node) 
+udf_register_node(struct udf_node *udf_node)
 {
-	struct udf_mount *ump;
+	struct udf_mount *ump = udf_node->ump;
 
-	ump = node->ump;
+	/* add node to the rb tree */
 	mutex_enter(&ump->ihash_lock);
+		rb_tree_insert_node(&ump->udf_node_tree, &udf_node->rbnode);
+	mutex_exit(&ump->ihash_lock);
+}
 
-	/* from hash and sorted list */
-	LIST_REMOVE(node, hashchain);
-	LIST_REMOVE(node, sortchain);
 
+static void
+udf_deregister_node(struct udf_node *udf_node) 
+{
+	struct udf_mount *ump = udf_node->ump;
+
+	/* remove node from the rb tree */
+	mutex_enter(&ump->ihash_lock);
+		rb_tree_remove_node(&ump->udf_node_tree, &udf_node->rbnode);
 	mutex_exit(&ump->ihash_lock);
 }
 
@@ -5274,7 +5256,7 @@
 	/* lookup in hash table */
 	assert(ump);
 	assert(node_icb_loc);
-	udf_node = udf_hash_lookup(ump, node_icb_loc);
+	udf_node = udf_node_lookup(ump, node_icb_loc);
 	if (udf_node) {
 		DPRINTF(NODE, ("\tgot it from the hash!\n"));
 		/* vnode is returned locked */
@@ -6319,7 +6301,7 @@
 	if (fid->file_char & UDF_FILE_CHAR_PAR)
 		strcpy(dirent->d_name, "..");
 
-	dirent->d_fileno = udf_calchash(&fid->icb);	/* inode hash XXX */
+	dirent->d_fileno = udf_get_node_id(&fid->icb);	/* inode hash XXX */
 	dirent->d_namlen = strlen(dirent->d_name);
 	dirent->d_reclen = _DIRENT_SIZE(dirent);
 
@@ -6355,7 +6337,7 @@
 	KASSERT(mutex_owned(&mntvnode_lock));
 
 	DPRINTF(SYNC, ("sync_pass %d\n", pass));
-	udf_node = LIST_FIRST(&ump->sorted_udf_nodes);
+	udf_node = RBTOUDFNODE(RB_TREE_MIN(&ump->udf_node_tree));
 	for (;udf_node; udf_node = n_udf_node) {
 		DPRINTF(SYNC, ("."));
 
@@ -6363,7 +6345,10 @@
 		vp = udf_node->vnode;
 
 		mutex_enter(&vp->v_interlock);
-		n_udf_node = LIST_NEXT(udf_node, sortchain);
+		n_udf_node = RBTOUDFNODE(rb_tree_iterate(
+			&ump->udf_node_tree, &udf_node->rbnode,
+			RB_DIR_RIGHT));
+
 		if (n_udf_node)
 			n_udf_node->i_flags |= IN_SYNCED;
 

Index: src/sys/fs/udf/udf_subr.h
diff -u src/sys/fs/udf/udf_subr.h:1.16 src/sys/fs/udf/udf_subr.h:1.17
--- src/sys/fs/udf/udf_subr.h:1.16	Thu Jun 25 17:16:33 2009
+++ src/sys/fs/udf/udf_subr.h	Tue Jul  7 10:23:36 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_subr.h,v 1.16 2009/06/25 17:16:33 reinoud Exp $ */
+/* $NetBSD: udf_subr.h,v 1.17 2009/07/07 10:23:36 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -182,8 +182,9 @@
 	struct timespec *mod, struct timespec *birth, int updflags);
 
 /* helpers and converters */
-long udf_calchash(struct long_ad *icbptr);    /* for `inode' numbering */
-int udf_check_icb_equal(struct long_ad *a, struct long_ad *b);
+void udf_init_nodes_tree(struct udf_mount *ump);
+long udf_get_node_id(const struct long_ad *icbptr);    /* for `inode' numbering */
+int udf_compare_icb(const struct long_ad *a, const struct long_ad *b);
 uint32_t udf_getaccessmode(struct udf_node *node);
 void udf_setaccessmode(struct udf_node *udf_node, mode_t mode);
 void udf_getownership(struct udf_node *udf_node, uid_t *uidp, gid_t *gidp);

Index: src/sys/fs/udf/udf_vfsops.c
diff -u src/sys/fs/udf/udf_vfsops.c:1.58 src/sys/fs/udf/udf_vfsops.c:1.59
--- src/sys/fs/udf/udf_vfsops.c:1.58	Mon Jun 29 05:08:17 2009
+++ src/sys/fs/udf/udf_vfsops.c	Tue Jul  7 10:23:36 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_vfsops.c,v 1.58 2009/06/29 05:08:17 dholland Exp $ */
+/* $NetBSD: udf_vfsops.c,v 1.59 2009/07/07 10:23:36 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.58 2009/06/29 05:08:17 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.59 2009/07/07 10:23:36 reinoud Exp $");
 #endif /* not lint */
 
 
@@ -565,7 +565,7 @@
 	struct udf_mount     *ump;
 	uint32_t sector_size, lb_size, bshift;
 	uint32_t logvol_integrity;
-	int    num_anchors, error, lst;
+	int    num_anchors, error;
 
 	/* flush out any old buffers remaining from a previous use. */
 	if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)))
@@ -578,6 +578,7 @@
 	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
 	mp->mnt_stat.f_namemax = UDF_MAX_NAMELEN;
 	mp->mnt_flag |= MNT_LOCAL;
+//	mp->mnt_iflag |= IMNT_MPSAFE;
 
 	/* allocate udf part of mount structure; malloc always succeeds */
 	ump = malloc(sizeof(struct udf_mount), M_UDFMNT, M_WAITOK | M_ZERO);
@@ -589,10 +590,8 @@
 	mutex_init(&ump->allocate_mutex, MUTEX_DEFAULT, IPL_NONE);
 	cv_init(&ump->dirtynodes_cv, "udfsync2");
 
-	/* init `ino_t' to udf_node hash table and other lists */
-	for (lst = 0; lst < UDF_INODE_HASHSIZE; lst++) {
-		LIST_INIT(&ump->udf_nodes[lst]);
-	}
+	/* init rbtree for nodes, ordered by their icb address (long_ad) */
+	udf_init_nodes_tree(ump);
 
 	/* set up linkage */
 	mp->mnt_data    = ump;

Index: src/sys/fs/udf/udf_vnops.c
diff -u src/sys/fs/udf/udf_vnops.c:1.50 src/sys/fs/udf/udf_vnops.c:1.51
--- src/sys/fs/udf/udf_vnops.c:1.50	Mon Jul  6 17:06:57 2009
+++ src/sys/fs/udf/udf_vnops.c	Tue Jul  7 10:23:36 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_vnops.c,v 1.50 2009/07/06 17:06:57 reinoud Exp $ */
+/* $NetBSD: udf_vnops.c,v 1.51 2009/07/07 10:23:36 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -32,7 +32,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.50 2009/07/06 17:06:57 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.51 2009/07/07 10:23:36 reinoud Exp $");
 #endif /* not lint */
 
 
@@ -561,7 +561,7 @@
 	if (uio->uio_offset == 0) {
 		DPRINTF(READDIR, ("\t'.' inserted\n"));
 		strcpy(dirent->d_name, ".");
-		dirent->d_fileno = udf_calchash(&udf_node->loc);
+		dirent->d_fileno = udf_get_node_id(&udf_node->loc);
 		dirent->d_type = DT_DIR;
 		dirent->d_namlen = strlen(dirent->d_name);
 		dirent->d_reclen = _DIRENT_SIZE(dirent);
@@ -889,7 +889,7 @@
 	vap->va_uid       = uid;
 	vap->va_gid       = gid;
 	vap->va_fsid      = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
-	vap->va_fileid    = udf_calchash(&udf_node->loc);   /* inode hash XXX */
+	vap->va_fileid    = udf_get_node_id(&udf_node->loc);   /* inode hash XXX */
 	vap->va_size      = filesize;
 	vap->va_blocksize = udf_node->ump->discinfo.sector_size;  /* wise? */
 
@@ -1871,13 +1871,13 @@
 	root_icb   = &ump->fileset_desc->rootdir_icb;
 
 	/* if nodes are equal, it is no use looking */
-	if (udf_check_icb_equal(&source->loc, &target->loc)) {
+	if (udf_compare_icb(&source->loc, &target->loc) == 0) {
 		error = EEXIST;
 		goto out;
 	}
 
 	/* nothing can exist before the root */
-	if (udf_check_icb_equal(root_icb, &target->loc)) {
+	if (udf_compare_icb(root_icb, &target->loc) == 0) {
 		error = 0;
 		goto out;
 	}
@@ -1905,13 +1905,13 @@
 			goto out;
 
 		/* did we encounter source node? */
-		if (udf_check_icb_equal(&icb_loc, &source->loc)) {
+		if (udf_compare_icb(&icb_loc, &source->loc) == 0) {
 			error = EINVAL;
 			goto out;
 		}
 
 		/* did we encounter the root node? */
-		if (udf_check_icb_equal(&icb_loc, root_icb)) {
+		if (udf_compare_icb(&icb_loc, root_icb) == 0) {
 			error = 0;
 			goto out;
 		}

Reply via email to