diff options
author | Bill Kendall <wkendall@sgi.com> | 2010-11-16 15:05:05 +0000 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-11-29 14:56:03 -0600 |
commit | 8fb917acc1fe21d53009f2f740f2d09c7bbcbdf9 (patch) | |
tree | 5d1d4400931c69340286ff8f0bb4ca935f9f404f | |
parent | 93ff73de80fa03c9793642cab975f1210145df4b (diff) | |
download | xfsdump-dev-8fb917acc1fe21d53009f2f740f2d09c7bbcbdf9.tar.gz |
xfsrestore: cache path lookups
In order to resolve a pathname, xfsrestore must work from an inode
number (from the dump) and recurse up the directory entry tree that
it has constructed. Each level of recursion requires a seek and read
to get the name of the dirent, and possibly a mmap of a section of
the directory entry tree if it is not already mapped (and in that
case, possibly a munmap of another section). It's quite common to
resolve pathnames in the same directory consecutively, so simply
caching the parent directory pathname from the previous lookup saves
quite a bit of overhead.
Signed-off-by: Bill Kendall <wkendall@sgi.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
-rw-r--r-- | restore/tree.c | 42 |
1 files changed, 37 insertions, 5 deletions
diff --git a/restore/tree.c b/restore/tree.c index 66798847..25652e94 100644 --- a/restore/tree.c +++ b/restore/tree.c @@ -236,6 +236,14 @@ struct link_iter_context { }; typedef struct link_iter_context link_iter_context_t; +/* used for caching parent pathname from previous Node2path result + */ +struct path_cache { + nh_t nh; + intgen_t len; + char buf[MAXPATHLEN]; +}; +typedef struct path_cache path_cache_t; /* declarations of externally defined global symbols *************************/ @@ -254,7 +262,8 @@ static nh_t Node_alloc( xfs_ino_t ino, static void Node_free( nh_t *nhp ); static node_t * Node_map( nh_t nh ); static void Node_unmap( nh_t nh, node_t **npp ); -static intgen_t Node2path_recurse( nh_t nh, char *buf, intgen_t bufsz ); +static intgen_t Node2path_recurse( nh_t nh, char *buf, + intgen_t bufsz, intgen_t level ); static void adopt( nh_t parh, nh_t cldh, nrh_t nrh ); static nrh_t disown( nh_t cldh ); static void selsubtree( nh_t nh, bool_t sensepr ); @@ -3435,7 +3444,7 @@ Node2path( nh_t nh, char *path, char *errmsg ) { intgen_t remainingcnt; path[ 0 ] = 0; /* in case root node passed in */ - remainingcnt = Node2path_recurse( nh, path, MAXPATHLEN ); + remainingcnt = Node2path_recurse( nh, path, MAXPATHLEN, 0 ); if ( remainingcnt <= 0 ) { node_t *np = Node_map( nh ); xfs_ino_t ino = np->n_ino; @@ -3459,13 +3468,15 @@ Node2path( nh_t nh, char *path, char *errmsg ) * works because the buffer size is secretly 2 * MAXPATHLEN. */ static intgen_t -Node2path_recurse( nh_t nh, char *buf, intgen_t bufsz ) +Node2path_recurse( nh_t nh, char *buf, intgen_t bufsz, intgen_t level ) { + static path_cache_t cache = { NH_NULL, 0, "" }; node_t *np; nh_t parh; xfs_ino_t ino; gen_t gen; nrh_t nrh; + char *oldbuf; intgen_t oldbufsz; intgen_t namelen; @@ -3475,6 +3486,14 @@ Node2path_recurse( nh_t nh, char *buf, intgen_t bufsz ) return bufsz; } + /* if we have a cache hit, no need to recurse any further + */ + if ( nh == cache.nh ) { + ASSERT( bufsz > cache.len ); + strcpy( buf, cache.buf ); + return bufsz - cache.len; + } + /* extract useful node members */ np = Node_map( nh ); @@ -3486,8 +3505,9 @@ Node2path_recurse( nh_t nh, char *buf, intgen_t bufsz ) /* build path to parent */ + oldbuf = buf; oldbufsz = bufsz; - bufsz = Node2path_recurse( parh, buf, bufsz ); /* RECURSION */ + bufsz = Node2path_recurse( parh, buf, bufsz, level+1 ); /* RECURSION */ if ( bufsz <= 0 ) { return bufsz; } @@ -3517,10 +3537,22 @@ Node2path_recurse( nh_t nh, char *buf, intgen_t bufsz ) ASSERT( namelen > 0 ); } - /* return remaining buffer size + /* update remaining buffer size */ bufsz -= namelen; ASSERT( bufsz + MAXPATHLEN > 0 ); + + /* update the cache if we're the target's parent + * (and the pathname is not too long) + */ + if ( level == 1 && bufsz > 0 ) { + cache.nh = nh; + strcpy( cache.buf, oldbuf ); + cache.len = oldbufsz - bufsz; + } + + /* return remaining buffer size + */ return bufsz; } |