aboutsummaryrefslogtreecommitdiff
path: root/lib/libc/gen/telldir.c
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2017-04-17 19:03:31 +0000
committerAlexander Motin <mav@FreeBSD.org>2017-04-17 19:03:31 +0000
commitf9243265757d3dbec35d92ec7d0872f6db587da1 (patch)
treebad63125c1142a568eb8ebecb292c4fb7db7da8e /lib/libc/gen/telldir.c
parentf0e56c1f62d62a6a48e56e16e62313a6631ec160 (diff)
downloadsrc-f9243265757d3dbec35d92ec7d0872f6db587da1.tar.gz
src-f9243265757d3dbec35d92ec7d0872f6db587da1.zip
Optimize pathologic case of telldir() for Samba.
When application reads large directory, calling telldir() for each entry, like Samba does, it creates exponential performance drop as number of entries reach tenths to hundreds of thousands. It is caused by full search through the internal list, that never finds matches in that scenario, but creates O(n^2) delays. This patch optimizes that search, limiting it to entries of the same buffer, turning time closer to O(n) in case of linear directory scan. PR: 218622 Reviewed by: jhb, jilles MFC after: 2 weeks Sponsored by: iXsystems, Inc. Differential Revision: https://reviews.freebsd.org/D10408
Notes
Notes: svn path=/head/; revision=317064
Diffstat (limited to 'lib/libc/gen/telldir.c')
-rw-r--r--lib/libc/gen/telldir.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c
index c7b60e23f18a..370fb8b6fa9f 100644
--- a/lib/libc/gen/telldir.c
+++ b/lib/libc/gen/telldir.c
@@ -52,15 +52,22 @@ __FBSDID("$FreeBSD$");
long
telldir(DIR *dirp)
{
- struct ddloc *lp;
+ struct ddloc *lp, *flp;
long idx;
if (__isthreaded)
_pthread_mutex_lock(&dirp->dd_lock);
+ flp = NULL;
LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) {
- if (lp->loc_seek == dirp->dd_seek &&
- lp->loc_loc == dirp->dd_loc)
+ if (lp->loc_seek == dirp->dd_seek) {
+ if (flp == NULL)
+ flp = lp;
+ if (lp->loc_loc == dirp->dd_loc)
+ break;
+ } else if (flp != NULL) {
+ lp = NULL;
break;
+ }
}
if (lp == NULL) {
lp = malloc(sizeof(struct ddloc));
@@ -72,7 +79,10 @@ telldir(DIR *dirp)
lp->loc_index = dirp->dd_td->td_loccnt++;
lp->loc_seek = dirp->dd_seek;
lp->loc_loc = dirp->dd_loc;
- LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
+ if (flp != NULL)
+ LIST_INSERT_BEFORE(flp, lp, loc_lqe);
+ else
+ LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
}
idx = lp->loc_index;
if (__isthreaded)