From 83f2624dffe2312d303d42720959bb82e0bf6adf Mon Sep 17 00:00:00 2001 From: Joel Rosdahl Date: Thu, 7 Oct 2010 21:50:29 +0200 Subject: [PATCH] Only create parent directories when needed to save stat() calls --- ccache.c | 47 ++++++++++------------------------------------- ccache.h | 2 +- lockfile.c | 14 ++++++++++++++ manifest.c | 14 ++------------ stats.c | 15 +++++---------- util.c | 17 +++++++++++------ 6 files changed, 43 insertions(+), 66 deletions(-) diff --git a/ccache.c b/ccache.c index 43525c9b4..e4b6239e3 100644 --- a/ccache.c +++ b/ccache.c @@ -256,24 +256,12 @@ temp_dir() if (!path) { path = format("%s/tmp", cache_dir); } - - /* make sure the temp dir exists */ - if (create_dir(path) != 0) { - fprintf(stderr, - "ccache: failed to create %s (%s)\n", - path, strerror(errno)); - exit(1); - } return path; } /* * 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) @@ -281,9 +269,7 @@ 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]); @@ -291,21 +277,6 @@ get_path_in_cache(const char *name, const char *suffix) path = p; } - /* 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; @@ -537,6 +508,7 @@ to_cache(struct args *args) size_t added_bytes = 0; unsigned added_files = 0; + create_parent_dirs(cached_obj); tmp_stdout = format("%s.tmp.stdout.%s", cached_obj, tmp_string()); tmp_stderr = format("%s.tmp.stderr.%s", cached_obj, tmp_string()); tmp_obj = format("%s.tmp.%s", cached_obj, tmp_string()); @@ -737,6 +709,15 @@ get_object_name_from_cpp(struct args *args, struct mdfour *hash) temp_dir(), input_base, tmp_string(), i_extension); path_stderr = format("%s/tmp.cpp_stderr.%s", temp_dir(), tmp_string()); + if (create_parent_dirs(path_stdout) != 0) { + char *parent = dirname(path_stdout); + fprintf(stderr, + "ccache: failed to create %s (%s)\n", + parent, strerror(errno)); + free(parent); + exit(1); + } + time_of_compilation = time(NULL); if (!direct_i_file) { @@ -2154,14 +2135,6 @@ ccache_main(int argc, char *argv[]) setup_uncached_err(); - /* make sure the cache dir exists */ - if (create_dir(cache_dir) != 0) { - fprintf(stderr, - "ccache: failed to create %s (%s)\n", - cache_dir, strerror(errno)); - exit(1); - } - ccache(argc, argv); return 1; } diff --git a/ccache.h b/ccache.h index 8611429e5..c306ddfc7 100644 --- a/ccache.h +++ b/ccache.h @@ -127,7 +127,7 @@ char *dirname(const char *path); const char *get_extension(const char *path); char *remove_extension(const char *path); size_t file_size(struct stat *st); -int safe_open(const char *fname); +int safe_create_wronly(const char *fname); char *x_realpath(const char *path); char *gnu_getcwd(void); int create_empty_file(const char *fname); diff --git a/lockfile.c b/lockfile.c index e62aac4be..14b0cbb8d 100644 --- a/lockfile.c +++ b/lockfile.c @@ -51,6 +51,13 @@ lockfile_acquire(const char *path, unsigned staleness_limit) fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0666); if (fd == -1) { cc_log("lockfile_acquire: open WRONLY %s: %s", lockfile, strerror(errno)); + if (errno == ENOENT) { + /* Directory doesn't exist? */ + if (create_parent_dirs(lockfile) == 0) { + /* OK. Retry. */ + continue; + } + } if (errno != EEXIST) { /* Directory doesn't exist or isn't writable? */ goto out; @@ -99,6 +106,13 @@ lockfile_acquire(const char *path, unsigned staleness_limit) goto out; } cc_log("lockfile_acquire: symlink %s: %s", lockfile, strerror(errno)); + if (errno == ENOENT) { + /* Directory doesn't exist? */ + if (create_parent_dirs(lockfile) == 0) { + /* OK. Retry. */ + continue; + } + } if (errno != EEXIST) { /* Directory doesn't exist or isn't writable? */ goto out; diff --git a/manifest.c b/manifest.c index bb809ba57..1e2c53041 100644 --- a/manifest.c +++ b/manifest.c @@ -580,7 +580,6 @@ manifest_put(const char *manifest_path, struct file_hash *object_hash, int ret = 0; int fd1; int fd2; - struct stat st; gzFile f1 = NULL; gzFile f2 = NULL; struct manifest *mf = NULL; @@ -592,17 +591,8 @@ manifest_put(const char *manifest_path, struct file_hash *object_hash, * not a big deal, and it's also very unlikely. */ - fd1 = safe_open(manifest_path); + fd1 = open(manifest_path, O_RDONLY | O_BINARY); if (fd1 == -1) { - cc_log("Failed to open manifest file"); - goto out; - } - if (fstat(fd1, &st) != 0) { - cc_log("Failed to stat manifest file"); - close(fd1); - goto out; - } - if (st.st_size == 0) { /* New file. */ mf = create_empty_manifest(); } else { @@ -646,7 +636,7 @@ manifest_put(const char *manifest_path, struct file_hash *object_hash, } tmp_file = format("%s.tmp.%s", manifest_path, tmp_string()); - fd2 = safe_open(tmp_file); + fd2 = safe_create_wronly(tmp_file); if (fd2 == -1) { cc_log("Failed to open %s", tmp_file); goto out; diff --git a/stats.c b/stats.c index ac6d1008c..c98b25b9a 100644 --- a/stats.c +++ b/stats.c @@ -128,6 +128,11 @@ stats_write(const char *path, struct counters *counters) tmp_file = format("%s.tmp.%s", path, tmp_string()); f = fopen(tmp_file, "wb"); + if (!f && errno == ENOENT) { + if (create_parent_dirs(path) == 0) { + f = fopen(tmp_file, "wb"); + } + } if (!f) { cc_log("Failed to open %s", tmp_file); goto end; @@ -221,7 +226,6 @@ stats_flush(void) if (!cache_dir) return; stats_dir = format("%s/%x", cache_dir, hash_from_int(getpid()) % 16); stats_file = format("%s/stats", stats_dir); - create_dir(stats_dir); free(stats_dir); } @@ -382,19 +386,11 @@ stats_set_limits(long maxfiles, long maxsize) maxsize /= 16; } - if (create_dir(cache_dir) != 0) { - return 1; - } - /* set the limits in each directory */ for (dir = 0; dir <= 0xF; dir++) { char *fname, *cdir; cdir = format("%s/%1x", cache_dir, dir); - if (create_dir(cdir) != 0) { - free(cdir); - return 1; - } fname = format("%s/stats", cdir); free(cdir); @@ -424,7 +420,6 @@ stats_set_sizes(const char *dir, size_t num_files, size_t total_size) struct counters *counters = counters_init(STATS_END); char *statsfile; - create_dir(dir); statsfile = format("%s/stats", dir); if (lockfile_acquire(statsfile, lock_staleness_limit)) { diff --git a/util.c b/util.c index 5a5b7dc86..ce36f07c4 100644 --- a/util.c +++ b/util.c @@ -770,15 +770,20 @@ file_size(struct stat *st) #endif } -/* a safe open/create for read-write */ +/* + * Create a file for writing. Creates parent directories if they don't exist. + */ int -safe_open(const char *fname) +safe_create_wronly(const char *fname) { - int fd = open(fname, O_RDWR|O_BINARY); + int fd = open(fname, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0666); if (fd == -1 && errno == ENOENT) { - fd = open(fname, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0666); - if (fd == -1 && errno == EEXIST) { - fd = open(fname, O_RDWR|O_BINARY); + /* + * Only make sure parent directories exist when have failed to open the + * file -- this saves stat() calls. + */ + if (create_parent_dirs(fname) == 0) { + fd = open(fname, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0666); } } return fd; -- 2.47.3