Hello hackers, You don't need to call stat() just to find out if a dirent is a file or directory, most of the time. Please see attached.
From cc2f0fd4a078728a67d862e2deec0332fb8b3555 Mon Sep 17 00:00:00 2001 From: Thomas Munro <thomas.mu...@gmail.com> Date: Wed, 2 Sep 2020 16:15:09 +1200 Subject: [PATCH] Skip unnecessary stat() calls in walkdir().
Often the kernel has already told us whether we have a file or a directory, so we can avoid a call to stat(). --- src/backend/storage/file/fd.c | 57 +++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index f376a97ed6..99562f1ec7 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -3340,8 +3340,9 @@ walkdir(const char *path, while ((de = ReadDirExtended(dir, path, elevel)) != NULL) { char subpath[MAXPGPATH * 2]; - struct stat fst; - int sret; + bool is_unknown = false; + bool is_reg = false; + bool is_dir = false; CHECK_FOR_INTERRUPTS(); @@ -3351,22 +3352,52 @@ walkdir(const char *path, snprintf(subpath, sizeof(subpath), "%s/%s", path, de->d_name); - if (process_symlinks) - sret = stat(subpath, &fst); - else - sret = lstat(subpath, &fst); + /* + * We want to know if it's a file or directory. Some systems can tell + * us that already without an extra system call, but that's a BSD/GNU + * extension not mandated by POSIX, and even when the interface is + * present, sometimes the type is unknown, depending on the filesystem + * in use or in some cases options used at filesystem creation time. + */ +#if defined(DT_UNKNOWN) && defined(DT_REG) && defined(DT_DIR) && defined(DT_LNK) + if (de->d_type == DT_UNKNOWN || + (de->d_type == DT_LNK && process_symlinks)) + is_unknown = true; + else if (de->d_type == DT_REG) + is_reg = true; + else if (de->d_type == DT_DIR) + is_dir = true; +#else + is_unknown = true; +#endif - if (sret < 0) + if (is_unknown) { - ereport(elevel, - (errcode_for_file_access(), - errmsg("could not stat file \"%s\": %m", subpath))); - continue; + struct stat fst; + int sret; + + + if (process_symlinks) + sret = stat(subpath, &fst); + else + sret = lstat(subpath, &fst); + + if (sret < 0) + { + ereport(elevel, + (errcode_for_file_access(), + errmsg("could not stat file \"%s\": %m", subpath))); + continue; + } + if (S_ISREG(fst.st_mode)) + is_reg = true; + else if (S_ISDIR(fst.st_mode)) + is_dir = true; } - if (S_ISREG(fst.st_mode)) + if (is_reg) (*action) (subpath, false, elevel); - else if (S_ISDIR(fst.st_mode)) + else if (is_dir) walkdir(subpath, action, false, elevel); } -- 2.20.1