We have a huge amount of WAL files at backup site. A listing of the
directory takes several seconds. During startup pg_receivewal checks size
of all theus files.  It does not check file integrity or gaps between
files. It takes several hours for our setup.
I have add an options that skip this file size checking. Default behavior
remains the same.
A patch looks huge due to large code block ident. Actually it consists of
option add and one if-branch.
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index d0a4079d50..6b8cf8fd58 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -51,6 +51,7 @@ static bool slot_exists_ok = false;
 static bool do_drop_slot = false;
 static bool do_sync = true;
 static bool synchronous = false;
+static bool skip_filesize_check = false;
 static char *replication_slot = NULL;
 static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
 static XLogRecPtr endpos = InvalidXLogRecPtr;
@@ -103,6 +104,7 @@ usage(void)
 	printf(_("\nOptional actions:\n"));
 	printf(_("      --create-slot      create a new replication slot (for the slot's name see --slot)\n"));
 	printf(_("      --drop-slot        drop the replication slot (for the slot's name see --slot)\n"));
+	printf(_("      --skip-filesize-check    Don't check file sizes at directory specified by -D option \n"));
 	printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
 	printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
 }
@@ -291,169 +293,172 @@ FindStreamingStart(uint32 *tli)
 		 */
 		XLogFromFileName(dirent->d_name, &tli, &segno, WalSegSz);
 
-		/*
-		 * Check that the segment has the right size, if it's supposed to be
-		 * completed.  For non-compressed segments just check the on-disk size
-		 * and see if it matches a completed segment.  For gzip-compressed
-		 * segments, look at the last 4 bytes of the compressed file, which is
-		 * where the uncompressed size is located for files with a size lower
-		 * than 4GB, and then compare it to the size of a completed segment.
-		 * The 4 last bytes correspond to the ISIZE member according to
-		 * http://www.zlib.org/rfc-gzip.html.
-		 *
-		 * For LZ4-compressed segments, uncompress the file in a throw-away
-		 * buffer keeping track of the uncompressed size, then compare it to
-		 * the size of a completed segment.  Per its protocol, LZ4 does not
-		 * store the uncompressed size of an object by default.  contentSize
-		 * is one possible way to do that, but we need to rely on a method
-		 * where WAL segments could have been compressed by a different source
-		 * than pg_receivewal, like an archive_command with lz4.
-		 */
-		if (!ispartial && wal_compression_algorithm == PG_COMPRESSION_NONE)
-		{
-			struct stat statbuf;
-			char		fullpath[MAXPGPATH * 2];
+		if(!skip_filesize_check)
+		{	
+			/*
+			 * Check that the segment has the right size, if it's supposed to be
+			 * completed.  For non-compressed segments just check the on-disk size
+			 * and see if it matches a completed segment.  For gzip-compressed
+			 * segments, look at the last 4 bytes of the compressed file, which is
+			 * where the uncompressed size is located for files with a size lower
+			 * than 4GB, and then compare it to the size of a completed segment.
+			 * The 4 last bytes correspond to the ISIZE member according to
+			 * http://www.zlib.org/rfc-gzip.html.
+			 *
+			 * For LZ4-compressed segments, uncompress the file in a throw-away
+			 * buffer keeping track of the uncompressed size, then compare it to
+			 * the size of a completed segment.  Per its protocol, LZ4 does not
+			 * store the uncompressed size of an object by default.  contentSize
+			 * is one possible way to do that, but we need to rely on a method
+			 * where WAL segments could have been compressed by a different source
+			 * than pg_receivewal, like an archive_command with lz4.
+			 */
+			if (!ispartial && wal_compression_algorithm == PG_COMPRESSION_NONE)
+			{
+				struct stat statbuf;
+				char		fullpath[MAXPGPATH * 2];
 
-			snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
-			if (stat(fullpath, &statbuf) != 0)
-				pg_fatal("could not stat file \"%s\": %m", fullpath);
+				snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
+				if (stat(fullpath, &statbuf) != 0)
+					pg_fatal("could not stat file \"%s\": %m", fullpath);
 
-			if (statbuf.st_size != WalSegSz)
-			{
-				pg_log_warning("segment file \"%s\" has incorrect size %lld, skipping",
-							   dirent->d_name, (long long int) statbuf.st_size);
-				continue;
+				if (statbuf.st_size != WalSegSz)
+				{
+					pg_log_warning("segment file \"%s\" has incorrect size %lld, skipping",
+								   dirent->d_name, (long long int) statbuf.st_size);
+					continue;
+				}
 			}
-		}
-		else if (!ispartial && wal_compression_algorithm == PG_COMPRESSION_GZIP)
-		{
-			int			fd;
-			char		buf[4];
-			int			bytes_out;
-			char		fullpath[MAXPGPATH * 2];
-			int			r;
-
-			snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
-
-			fd = open(fullpath, O_RDONLY | PG_BINARY, 0);
-			if (fd < 0)
-				pg_fatal("could not open compressed file \"%s\": %m",
-						 fullpath);
-			if (lseek(fd, (off_t) (-4), SEEK_END) < 0)
-				pg_fatal("could not seek in compressed file \"%s\": %m",
-						 fullpath);
-			r = read(fd, (char *) buf, sizeof(buf));
-			if (r != sizeof(buf))
+			else if (!ispartial && wal_compression_algorithm == PG_COMPRESSION_GZIP)
 			{
-				if (r < 0)
-					pg_fatal("could not read compressed file \"%s\": %m",
+				int			fd;
+				char		buf[4];
+				int			bytes_out;
+				char		fullpath[MAXPGPATH * 2];
+				int			r;
+
+				snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
+
+				fd = open(fullpath, O_RDONLY | PG_BINARY, 0);
+				if (fd < 0)
+					pg_fatal("could not open compressed file \"%s\": %m",
 							 fullpath);
-				else
-					pg_fatal("could not read compressed file \"%s\": read %d of %zu",
-							 fullpath, r, sizeof(buf));
-			}
+				if (lseek(fd, (off_t) (-4), SEEK_END) < 0)
+					pg_fatal("could not seek in compressed file \"%s\": %m",
+							 fullpath);
+				r = read(fd, (char *) buf, sizeof(buf));
+				if (r != sizeof(buf))
+				{
+					if (r < 0)
+						pg_fatal("could not read compressed file \"%s\": %m",
+								 fullpath);
+					else
+						pg_fatal("could not read compressed file \"%s\": read %d of %zu",
+								 fullpath, r, sizeof(buf));
+				}
 
-			close(fd);
-			bytes_out = (buf[3] << 24) | (buf[2] << 16) |
-				(buf[1] << 8) | buf[0];
+				close(fd);
+				bytes_out = (buf[3] << 24) | (buf[2] << 16) |
+					(buf[1] << 8) | buf[0];
 
-			if (bytes_out != WalSegSz)
-			{
-				pg_log_warning("compressed segment file \"%s\" has incorrect uncompressed size %d, skipping",
-							   dirent->d_name, bytes_out);
-				continue;
+				if (bytes_out != WalSegSz)
+				{
+					pg_log_warning("compressed segment file \"%s\" has incorrect uncompressed size %d, skipping",
+								   dirent->d_name, bytes_out);
+					continue;
+				}
 			}
-		}
-		else if (!ispartial && wal_compression_algorithm == PG_COMPRESSION_LZ4)
-		{
+			else if (!ispartial && wal_compression_algorithm == PG_COMPRESSION_LZ4)
+			{
 #ifdef USE_LZ4
 #define LZ4_CHUNK_SZ	64 * 1024	/* 64kB as maximum chunk size read */
-			int			fd;
-			ssize_t		r;
-			size_t		uncompressed_size = 0;
-			char		fullpath[MAXPGPATH * 2];
-			char	   *outbuf;
-			char	   *readbuf;
-			LZ4F_decompressionContext_t ctx = NULL;
-			LZ4F_decompressOptions_t dec_opt;
-			LZ4F_errorCode_t status;
-
-			memset(&dec_opt, 0, sizeof(dec_opt));
-			snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
-
-			fd = open(fullpath, O_RDONLY | PG_BINARY, 0);
-			if (fd < 0)
-				pg_fatal("could not open file \"%s\": %m", fullpath);
-
-			status = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
-			if (LZ4F_isError(status))
-				pg_fatal("could not create LZ4 decompression context: %s",
-						 LZ4F_getErrorName(status));
-
-			outbuf = pg_malloc0(LZ4_CHUNK_SZ);
-			readbuf = pg_malloc0(LZ4_CHUNK_SZ);
-			do
-			{
-				char	   *readp;
-				char	   *readend;
-
-				r = read(fd, readbuf, LZ4_CHUNK_SZ);
-				if (r < 0)
-					pg_fatal("could not read file \"%s\": %m", fullpath);
-
-				/* Done reading the file */
-				if (r == 0)
-					break;
-
-				/* Process one chunk */
-				readp = readbuf;
-				readend = readbuf + r;
-				while (readp < readend)
+				int			fd;
+				ssize_t		r;
+				size_t		uncompressed_size = 0;
+				char		fullpath[MAXPGPATH * 2];
+				char	   *outbuf;
+				char	   *readbuf;
+				LZ4F_decompressionContext_t ctx = NULL;
+				LZ4F_decompressOptions_t dec_opt;
+				LZ4F_errorCode_t status;
+
+				memset(&dec_opt, 0, sizeof(dec_opt));
+				snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
+
+				fd = open(fullpath, O_RDONLY | PG_BINARY, 0);
+				if (fd < 0)
+					pg_fatal("could not open file \"%s\": %m", fullpath);
+
+				status = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
+				if (LZ4F_isError(status))
+					pg_fatal("could not create LZ4 decompression context: %s",
+							 LZ4F_getErrorName(status));
+
+				outbuf = pg_malloc0(LZ4_CHUNK_SZ);
+				readbuf = pg_malloc0(LZ4_CHUNK_SZ);
+				do
 				{
-					size_t		out_size = LZ4_CHUNK_SZ;
-					size_t		read_size = readend - readp;
-
-					memset(outbuf, 0, LZ4_CHUNK_SZ);
-					status = LZ4F_decompress(ctx, outbuf, &out_size,
-											 readp, &read_size, &dec_opt);
-					if (LZ4F_isError(status))
-						pg_fatal("could not decompress file \"%s\": %s",
-								 fullpath,
-								 LZ4F_getErrorName(status));
-
-					readp += read_size;
-					uncompressed_size += out_size;
+					char	   *readp;
+					char	   *readend;
+
+					r = read(fd, readbuf, LZ4_CHUNK_SZ);
+					if (r < 0)
+						pg_fatal("could not read file \"%s\": %m", fullpath);
+
+					/* Done reading the file */
+					if (r == 0)
+						break;
+
+					/* Process one chunk */
+					readp = readbuf;
+					readend = readbuf + r;
+					while (readp < readend)
+					{
+						size_t		out_size = LZ4_CHUNK_SZ;
+						size_t		read_size = readend - readp;
+
+						memset(outbuf, 0, LZ4_CHUNK_SZ);
+						status = LZ4F_decompress(ctx, outbuf, &out_size,
+												 readp, &read_size, &dec_opt);
+						if (LZ4F_isError(status))
+							pg_fatal("could not decompress file \"%s\": %s",
+									 fullpath,
+									 LZ4F_getErrorName(status));
+
+						readp += read_size;
+						uncompressed_size += out_size;
+					}
+
+					/*
+					 * No need to continue reading the file when the
+					 * uncompressed_size exceeds WalSegSz, even if there are still
+					 * data left to read. However, if uncompressed_size is equal
+					 * to WalSegSz, it should verify that there is no more data to
+					 * read.
+					 */
+				} while (uncompressed_size <= WalSegSz && r > 0);
+
+				close(fd);
+				pg_free(outbuf);
+				pg_free(readbuf);
+
+				status = LZ4F_freeDecompressionContext(ctx);
+				if (LZ4F_isError(status))
+					pg_fatal("could not free LZ4 decompression context: %s",
+							 LZ4F_getErrorName(status));
+
+				if (uncompressed_size != WalSegSz)
+				{
+					pg_log_warning("compressed segment file \"%s\" has incorrect uncompressed size %zu, skipping",
+								   dirent->d_name, uncompressed_size);
+					continue;
 				}
-
-				/*
-				 * No need to continue reading the file when the
-				 * uncompressed_size exceeds WalSegSz, even if there are still
-				 * data left to read. However, if uncompressed_size is equal
-				 * to WalSegSz, it should verify that there is no more data to
-				 * read.
-				 */
-			} while (uncompressed_size <= WalSegSz && r > 0);
-
-			close(fd);
-			pg_free(outbuf);
-			pg_free(readbuf);
-
-			status = LZ4F_freeDecompressionContext(ctx);
-			if (LZ4F_isError(status))
-				pg_fatal("could not free LZ4 decompression context: %s",
-						 LZ4F_getErrorName(status));
-
-			if (uncompressed_size != WalSegSz)
-			{
-				pg_log_warning("compressed segment file \"%s\" has incorrect uncompressed size %zu, skipping",
-							   dirent->d_name, uncompressed_size);
-				continue;
-			}
 #else
-			pg_log_error("cannot check file \"%s\": compression with %s not supported by this build",
-						 dirent->d_name, "LZ4");
-			exit(1);
+				pg_log_error("cannot check file \"%s\": compression with %s not supported by this build",
+							 dirent->d_name, "LZ4");
+				exit(1);
 #endif
+			}
 		}
 
 		/* Looks like a valid segment. Remember that we saw it. */
@@ -645,6 +650,7 @@ main(int argc, char **argv)
 		{"if-not-exists", no_argument, NULL, 3},
 		{"synchronous", no_argument, NULL, 4},
 		{"no-sync", no_argument, NULL, 5},
+		{"skip-filesize-check", no_argument, NULL, 6},
 		{NULL, 0, NULL, 0}
 	};
 
@@ -743,6 +749,9 @@ main(int argc, char **argv)
 			case 5:
 				do_sync = false;
 				break;
+			case 6:
+				skip_filesize_check = true;
+				break;
 			default:
 				/* getopt_long already emitted a complaint */
 				pg_log_error_hint("Try \"%s --help\" for more information.", progname);

Reply via email to