From: Wilson Snyder Date: Mon, 4 Oct 2010 21:08:35 +0000 (-0400) Subject: Reduce stat() calls on multilevel caches X-Git-Tag: v3.2~311 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b2a420ee514fea824306ed135fcb2c95e498b09d;p=thirdparty%2Fccache.git Reduce stat() calls on multilevel caches --- diff --git a/ccache.c b/ccache.c index 76c47319d..b0b38cad6 100644 --- a/ccache.c +++ b/ccache.c @@ -253,6 +253,10 @@ clean_up_tmp_files() /* * Transform a name to a full path into the cache directory, creating needed * sublevels if needed. Caller frees. + * + * stat() calls can be expensive on the cache, so we both avoid checking a + * single path multiple times, and also avoid stat()ing each level in a + * many level cache. */ static char * get_path_in_cache(const char *name, const char *suffix) @@ -260,17 +264,32 @@ get_path_in_cache(const char *name, const char *suffix) int i; char *path; char *result; + struct stat st; + /* Form the entire path */ path = x_strdup(cache_dir); for (i = 0; i < nlevels; ++i) { char *p = format("%s/%c", path, name[i]); free(path); path = p; - if (create_dir(path) != 0) { - cc_log("Failed to create %s", path); - failed(); + } + + /* First see if whole path exists, so can avoid directory one-by-one check */ + if (!(stat(path, &st) == 0 + && S_ISDIR(st.st_mode))) { + free(path); + path = x_strdup(cache_dir); + for (i = 0; i < nlevels; ++i) { + char *p = format("%s/%c", path, name[i]); + free(path); + path = p; + if (create_dir(path) != 0) { + cc_log("Failed to create %s", path); + failed(); + } } } + result = format("%s/%s%s", path, name + nlevels, suffix); free(path); return result;