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

Reply via email to