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 <[email protected]>
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