From 78329f1a6b51639eb8f69426ef127091b44c3895 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Fri, 8 Oct 2021 20:22:23 +0000 Subject: [PATCH v6 2/2] WAL segment pre-allocation. --- doc/src/sgml/config.sgml | 23 +++ src/backend/access/transam/xlog.c | 60 ++++++- src/backend/postmaster/checkpointer.c | 234 ++++++++++++++++++++++++++ src/backend/replication/basebackup.c | 6 +- src/backend/storage/file/fd.c | 22 ++- src/backend/storage/lmgr/lwlocknames.txt | 1 + src/backend/utils/misc/guc.c | 11 ++ src/backend/utils/misc/postgresql.conf.sample | 1 + src/bin/initdb/initdb.c | 1 + src/bin/pg_basebackup/pg_basebackup.c | 19 ++- src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +- src/bin/pg_resetwal/pg_resetwal.c | 48 ++++++ src/include/postmaster/bgwriter.h | 5 + src/include/storage/fd.h | 2 +- 14 files changed, 417 insertions(+), 20 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 0a8e35c59f..0e66e415ff 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -3203,6 +3203,29 @@ include_dir 'conf.d' + + wal_preallocate_max_size (integer) + + wal_preallocate_max_size configuration parameter + + + + + The maximum amount of WAL to pre-allocate for use when a new WAL segment + must be initialized. Setting this parameter to a size less than the WAL + segment size disables this behavior. The default value is 64 megabytes + (64MB). This parameter can only be set in the + postgresql.conf file or on the server command line. + + + + WAL pre-allocation may improve performance in scenarios where new WAL + segments must be created (e.g., during checkpoints when WAL segments + cannot be recycled). + + + + wal_buffers (integer) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index d0be54bc9b..e0b84321fb 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -3287,6 +3287,8 @@ XLogFileInitInternal(XLogSegNo logsegno, bool *added, char *path) XLogSegNo installed_segno; XLogSegNo max_segno; int fd; + int prealloc_segs; + bool found_prealloc = false; XLogFilePath(path, ThisTimeLineID, logsegno, wal_segment_size); @@ -3306,15 +3308,45 @@ XLogFileInitInternal(XLogSegNo logsegno, bool *added, char *path) return fd; /* - * Initialize an empty (all zeroes) segment. NOTE: it is possible that - * another process is doing the same thing. If so, we will end up - * pre-creating an extra log segment. That seems OK, and better than - * holding the lock throughout this lengthy process. + * Try to use a pre-allocated segment, if one exists. If none are + * available, we fall back to creating a new segment on our own. + * + * Note that we still look for a pre-allocated segment even if the pre- + * allocation functionality is disabled via the GUCs. This ensures that any + * pre-allocated segments left over after turning off the pre-allocation + * functionality are still eligible for use. */ - elog(DEBUG2, "creating and filling new WAL file"); + LWLockAcquire(WALPreallocationLock, LW_EXCLUSIVE); + prealloc_segs = GetNumPreallocatedWalSegs(); + if (prealloc_segs > 0) + { + elog(DEBUG2, "using pre-allocated WAL file"); - snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid()); - CreateEmptyWalSegment(tmppath); + found_prealloc = true; + prealloc_segs--; + SetNumPreallocatedWalSegs(prealloc_segs); + snprintf(tmppath, MAXPGPATH, "%s/preallocated_segments/xlogtemp.%d", + XLOGDIR, prealloc_segs); + } + else + { + /* + * We're not using a pre-allocated segment, so there's no need to keep + * holding the WALPreallocationLock. + */ + LWLockRelease(WALPreallocationLock); + + /* + * Initialize an empty (all zeroes) segment. NOTE: it is possible that + * another process is doing the same thing. If so, we will end up + * pre-creating an extra log segment. That seems OK, and better than + * holding the lock throughout this lengthy process. + */ + elog(DEBUG2, "creating and filling new WAL file"); + + snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid()); + CreateEmptyWalSegment(tmppath, ERROR); + } /* * Now move the segment into place with its final name. Cope with @@ -3336,7 +3368,7 @@ XLogFileInitInternal(XLogSegNo logsegno, bool *added, char *path) if (InstallXLogFileSegment(&installed_segno, tmppath, true, max_segno)) { *added = true; - elog(DEBUG2, "done creating and filling new WAL file"); + elog(DEBUG2, "done installing new WAL file"); } else { @@ -3349,6 +3381,18 @@ XLogFileInitInternal(XLogSegNo logsegno, bool *added, char *path) elog(DEBUG2, "abandoned new WAL file"); } + /* + * If we are using a pre-allocated segment, we've been holding onto the + * WALPreallocationLock all this time so that the checkpointer process can't + * overwrite the file before we've installed it. + * + * While we're at it, also nudge the checkpointer process so that it pre- + * allocates new segments if possible. + */ + if (found_prealloc) + LWLockRelease(WALPreallocationLock); + RequestWalPreallocation(); + return -1; } diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index be7366379d..3237595dbf 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -127,6 +127,9 @@ typedef struct uint32 num_backend_writes; /* counts user backend buffer writes */ uint32 num_backend_fsync; /* counts user backend fsync calls */ + bool wal_prealloc_requested; /* protected by ckpt_lck */ + int num_prealloc_segs; /* protected by WALPreallocationLock */ + int num_requests; /* current # of requests */ int max_requests; /* allocated array size */ CheckpointerRequest requests[FLEXIBLE_ARRAY_MEMBER]; @@ -143,6 +146,7 @@ static CheckpointerShmemStruct *CheckpointerShmem; int CheckPointTimeout = 300; int CheckPointWarning = 30; double CheckPointCompletionTarget = 0.9; +int wal_prealloc_max_size_mb = 0; /* * Private state @@ -165,6 +169,10 @@ static bool IsCheckpointOnSchedule(double progress); static bool ImmediateCheckpointRequested(void); static bool CompactCheckpointerRequestQueue(void); static void UpdateSharedMemoryConfig(void); +static void ScanForExistingPreallocatedSegments(void); +static bool InstallPreallocatedWalSeg(const char *path); +static void DoWalPreAllocation(void); +static int GetMaxPreallocatedWalSegs(void); /* Signal handlers */ static void ReqCheckpointHandler(SIGNAL_ARGS); @@ -329,6 +337,11 @@ CheckpointerMain(void) */ ProcGlobal->checkpointerLatch = &MyProc->procLatch; + /* + * Look for any leftover pre-allocated segments we can use. + */ + ScanForExistingPreallocatedSegments(); + /* * Loop forever */ @@ -349,6 +362,11 @@ CheckpointerMain(void) AbsorbSyncRequests(); HandleCheckpointerInterrupts(); + /* + * First do WAL pre-allocation. + */ + DoWalPreAllocation(); + /* * Detect a pending checkpoint request by checking whether the flags * word in shared memory is nonzero. We shouldn't need to acquire the @@ -507,6 +525,12 @@ CheckpointerMain(void) if (((volatile CheckpointerShmemStruct *) CheckpointerShmem)->ckpt_flags) continue; + /* + * Also skip sleeping if WAL pre-allocation has been requested. + */ + if (((volatile CheckpointerShmemStruct *) CheckpointerShmem)->wal_prealloc_requested) + continue; + /* * Sleep until we are signaled or it's time for another checkpoint or * xlog file switch. @@ -682,6 +706,8 @@ ImmediateCheckpointRequested(void) * * 'progress' is an estimate of how much of the work has been done, as a * fraction between 0.0 meaning none, and 1.0 meaning all done. + * + * This function also takes care of handling any WAL pre-allocation requests. */ void CheckpointWriteDelay(int flags, double progress) @@ -692,6 +718,15 @@ CheckpointWriteDelay(int flags, double progress) if (!AmCheckpointerProcess()) return; + /* + * WAL pre-allocation has nothing to do with throttling BufferSync()'s write + * rate. However, since this function is called frequently during + * checkpoints, it is a convenient place to handle any pending WAL pre- + * allocation requests. + */ + if (((volatile CheckpointerShmemStruct *) CheckpointerShmem)->wal_prealloc_requested) + DoWalPreAllocation(); + /* * Perform the usual duties and take a nap, unless we're behind schedule, * in which case we just try to catch up as quickly as possible. @@ -823,6 +858,203 @@ IsCheckpointOnSchedule(double progress) return true; } +/* + * GetNumPreallocatedWalSegs + * + * Returns the number of pre-allocated WAL segments in the preallocated_segments + * directory. Callers are expected to hold the WALPreallocationLock. + */ +int +GetNumPreallocatedWalSegs(void) +{ + Assert(LWLockHeldByMe(WALPreallocationLock)); + return CheckpointerShmem->num_prealloc_segs; +} + +/* + * SetNumPreallocatedWalSegs + * + * Sets the number of pre-allocated WAL segments in the preallocated_segments + * directory. Callers are expected to hold the WALPreallocationLock + * exclusively. + */ +void +SetNumPreallocatedWalSegs(int i) +{ + Assert(LWLockHeldByMeInMode(WALPreallocationLock, LW_EXCLUSIVE)); + CheckpointerShmem->num_prealloc_segs = i; +} + +/* + * ScanForExistingPreallocatedSegments + * + * This function searches through pg_wal/preallocated_segments for any segments + * that were left over and sets the tracking variable in shared memory + * accordingly. + */ +static void +ScanForExistingPreallocatedSegments(void) +{ + int i = 0; + + /* + * fsync the preallocated_segments directory in case any renames have yet to + * be flushed to disk. + */ + fsync_fname_ext(XLOGDIR "/preallocated_segments", true, false, FATAL); + + /* + * Gather all the preallocated segments we can find. + */ + while (true) + { + FILE *fd; + char path[MAXPGPATH]; + + snprintf(path, MAXPGPATH, "%s/preallocated_segments/xlogtemp.%d", + XLOGDIR, i); + + fd = AllocateFile(path, "r"); + if (fd != NULL) + { + FreeFile(fd); + i++; + } + else + { + if (errno != ENOENT) + ereport(FATAL, + (errcode_for_file_access(), + errmsg("could not open file \"%s\": %m", path))); + break; + } + } + + LWLockAcquire(WALPreallocationLock, LW_EXCLUSIVE); + SetNumPreallocatedWalSegs(i); + LWLockRelease(WALPreallocationLock); + + elog(DEBUG2, "found %d preallocated segments during startup", i); +} + +/* + * InstallPreallocatedWalSeg + * + * Renames the file at "path" to the next open pre-allocated segment slot and + * bumps up num_prealloc_segs. If there is a problem, a WARNING is emitted, we + * attempt to delete the file, and false is returned. Otherwise, true is + * returned. + */ +static bool +InstallPreallocatedWalSeg(const char *path) +{ + char newpath[MAXPGPATH]; + int rc; + + LWLockAcquire(WALPreallocationLock, LW_EXCLUSIVE); + + snprintf(newpath, MAXPGPATH, "%s/preallocated_segments/xlogtemp.%d", + XLOGDIR, CheckpointerShmem->num_prealloc_segs); + + rc = durable_rename(path, newpath, DEBUG1); + if (rc == 0) + CheckpointerShmem->num_prealloc_segs++; + else + { + ereport(WARNING, + (errcode_for_file_access(), + errmsg("file \"%s\" could not be renamed to \"%s\": %m", + path, newpath))); + + (void) durable_unlink(path, DEBUG1); + (void) durable_unlink(newpath, DEBUG1); + } + + LWLockRelease(WALPreallocationLock); + + return (rc == 0); +} + +/* + * DoWalPreAllocation + * + * Tries to allocate up to wal_preallocate_max_size worth of WAL. + */ +static void +DoWalPreAllocation(void) +{ + int segs_to_prealloc; + + /* + * Reset the request flag. + */ + SpinLockAcquire(&CheckpointerShmem->ckpt_lck); + CheckpointerShmem->wal_prealloc_requested = false; + SpinLockRelease(&CheckpointerShmem->ckpt_lck); + + /* + * Determine how many segments to pre-allocate. + */ + LWLockAcquire(WALPreallocationLock, LW_SHARED); + segs_to_prealloc = GetMaxPreallocatedWalSegs() - GetNumPreallocatedWalSegs(); + LWLockRelease(WALPreallocationLock); + + /* + * Do the pre-allocation. + */ + for (int i = 0; i < segs_to_prealloc; i++) + { + char tmppath[MAXPGPATH]; + + snprintf(tmppath, MAXPGPATH, "%s/preallocated_segments/xlogtemp", XLOGDIR); + + if (!CreateEmptyWalSegment(tmppath, WARNING) || + !InstallPreallocatedWalSeg(tmppath)) + { + elog(DEBUG2, "failed to pre-allocate WAL segment"); + return; + } + else + elog(DEBUG2, "pre-allocated WAL segment"); + + /* Check for barrier events. */ + if (ProcSignalBarrierPending) + ProcessProcSignalBarrier(); + + if (ShutdownRequestPending) + return; + } +} + +/* + * GetMaxPreallocatedWalSegs + * + * Returns the maximum number of pre-allocated WAL segments to create based on + * the current value of wal_preallocate_max_size. + */ +static int +GetMaxPreallocatedWalSegs(void) +{ + return wal_prealloc_max_size_mb / (wal_segment_size / (1024 * 1024)); +} + +/* + * RequestWalPreallocation + * + * Requests that more segments be pre-allocated for future use. + */ +void +RequestWalPreallocation(void) +{ + SpinLockAcquire(&CheckpointerShmem->ckpt_lck); + CheckpointerShmem->wal_prealloc_requested = true; + SpinLockRelease(&CheckpointerShmem->ckpt_lck); + + if (ProcGlobal->checkpointerLatch && + GetMaxPreallocatedWalSegs() > 0) + SetLatch(ProcGlobal->checkpointerLatch); +} + /* -------------------------------- * signal handler routines @@ -896,6 +1128,8 @@ CheckpointerShmemInit(void) CheckpointerShmem->max_requests = NBuffers; ConditionVariableInit(&CheckpointerShmem->start_cv); ConditionVariableInit(&CheckpointerShmem->done_cv); + CheckpointerShmem->wal_prealloc_requested = false; + CheckpointerShmem->num_prealloc_segs = 0; } } diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index 4c97ab7b5a..e84288a8a7 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -1412,11 +1412,13 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces, size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly); /* - * Also send archive_status directory (by hackishly reusing - * statbuf from above ...). + * Also send archive_status and preallocated_segments (by hackishly + * reusing statbuf from above ...). */ size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf, sizeonly); + size += _tarWriteHeader("./pg_wal/preallocated_segments", NULL, &statbuf, + sizeonly); continue; /* don't recurse into pg_wal */ } diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index a44df86537..e5425597df 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -3877,8 +3877,8 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset) * Create a new file that can be used as a new WAL segment. The caller is * responsible for installing the new file in pg_wal. */ -void -CreateEmptyWalSegment(const char *path) +bool +CreateEmptyWalSegment(const char *path, int elevel) { PGAlignedXLogBlock zbuffer; int fd; @@ -3889,9 +3889,12 @@ CreateEmptyWalSegment(const char *path) /* do not use get_sync_bit() here --- want to fsync only at end of fill */ fd = BasicOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY); if (fd < 0) - ereport(ERROR, + { + ereport(elevel, (errcode_for_file_access(), errmsg("could not create file \"%s\": %m", path))); + return false; + } memset(zbuffer.data, 0, XLOG_BLCKSZ); @@ -3961,9 +3964,10 @@ CreateEmptyWalSegment(const char *path) errno = save_errno; - ereport(ERROR, + ereport(elevel, (errcode_for_file_access(), errmsg("could not write to file \"%s\": %m", path))); + return false; } pgstat_report_wait_start(WAIT_EVENT_WAL_INIT_SYNC); @@ -3973,14 +3977,20 @@ CreateEmptyWalSegment(const char *path) close(fd); errno = save_errno; - ereport(ERROR, + ereport(elevel, (errcode_for_file_access(), errmsg("could not fsync file \"%s\": %m", path))); + return false; } pgstat_report_wait_end(); if (close(fd) != 0) - ereport(ERROR, + { + ereport(elevel, (errcode_for_file_access(), errmsg("could not close file \"%s\": %m", path))); + return false; + } + + return true; } diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt index 6c7cf6c295..212bda8e7d 100644 --- a/src/backend/storage/lmgr/lwlocknames.txt +++ b/src/backend/storage/lmgr/lwlocknames.txt @@ -53,3 +53,4 @@ XactTruncationLock 44 # 45 was XactTruncationLock until removal of BackendRandomLock WrapLimitsVacuumLock 46 NotifyQueueTailLock 47 +WALPreallocationLock 48 diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index d2ce4a8450..4d3274a70c 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2840,6 +2840,17 @@ static struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, + { + {"wal_preallocate_max_size", PGC_SIGHUP, WAL_SETTINGS, + gettext_noop("Sets the maximum amount of WAL to pre-allocate."), + NULL, + GUC_UNIT_MB + }, + &wal_prealloc_max_size_mb, + 64, 0, 102400, + NULL, NULL, NULL + }, + { {"wal_buffers", PGC_POSTMASTER, WAL_SETTINGS, gettext_noop("Sets the number of disk-page buffers in shared memory for WAL."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 3fe9a53cb3..309745e932 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -223,6 +223,7 @@ # off, pglz, lz4, or on #wal_init_zero = on # zero-fill new WAL files #wal_recycle = on # recycle WAL files +#wal_preallocate_max_size = 64MB # amount of WAL to pre-allocate #wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers # (change requires restart) #wal_writer_delay = 200ms # 1-10000 milliseconds diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 1ed4808d53..aa52aaeffb 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -208,6 +208,7 @@ static char *extra_options = ""; static const char *const subdirs[] = { "global", "pg_wal/archive_status", + "pg_wal/preallocated_segments", "pg_commit_ts", "pg_dynshmem", "pg_notify", diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index 27ee6394cf..0623cfe4b3 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -680,6 +680,22 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier) pg_log_error("could not create directory \"%s\": %m", statusdir); exit(1); } + + /* + * Also create pg_wal/preallocated_segments if necessary. + */ + if (PQserverVersion(conn) >= 150000) + { + char prealloc_dir[MAXPGPATH]; + + snprintf(prealloc_dir, sizeof(prealloc_dir), "%s/pg_wal/preallocated_segments", + basedir); + if (pg_mkdir_p(prealloc_dir, pg_dir_create_mode) != 0 && errno != EEXIST) + { + pg_log_error("could not create directory \"%s\": %m", prealloc_dir); + exit(1); + } + } } /* @@ -1611,7 +1627,8 @@ ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data) */ if (!((pg_str_endswith(state->filename, "/pg_wal") || pg_str_endswith(state->filename, "/pg_xlog") || - pg_str_endswith(state->filename, "/archive_status")) && + pg_str_endswith(state->filename, "/archive_status") || + pg_str_endswith(state->filename, "/preallocated_segments")) && errno == EEXIST)) { pg_log_error("could not create directory \"%s\": %m", diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl index a2cb2a7679..43e1e3e89d 100644 --- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl +++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl @@ -120,10 +120,10 @@ SKIP: "check backup dir permissions"); } -# Only archive_status directory should be copied in pg_wal/. +# Only archive_status and preallocated_segments directories should be copied in pg_wal/. is_deeply( [ sort(slurp_dir("$tempdir/backup/pg_wal/")) ], - [ sort qw(. .. archive_status) ], + [ sort qw(. .. archive_status preallocated_segments) ], 'no WAL files copied'); # Contents of these directories should not be copied. diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index 84b6f70ad6..ca09ad72d2 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -85,6 +85,7 @@ static void RewriteControlFile(void); static void FindEndOfXLOG(void); static void KillExistingXLOG(void); static void KillExistingArchiveStatus(void); +static void KillExistingPreallocatedSegments(void); static void WriteEmptyXLOG(void); static void usage(void); @@ -530,6 +531,7 @@ main(int argc, char *argv[]) RewriteControlFile(); KillExistingXLOG(); KillExistingArchiveStatus(); + KillExistingPreallocatedSegments(); WriteEmptyXLOG(); printf(_("Write-ahead log reset\n")); @@ -1120,6 +1122,52 @@ KillExistingArchiveStatus(void) } +/* + * Remove existing preallocated segments + */ +static void +KillExistingPreallocatedSegments(void) +{ +#define PREALLOCSEGDIR XLOGDIR "/preallocated_segments" + + DIR *xldir; + struct dirent *xlde; + char path[MAXPGPATH + sizeof(PREALLOCSEGDIR)]; + + xldir = opendir(PREALLOCSEGDIR); + if (xldir == NULL) + { + pg_log_error("could not open directory \"%s\": %m", PREALLOCSEGDIR); + exit(1); + } + + while (errno = 0, (xlde = readdir(xldir)) != NULL) + { + if (strncmp(xlde->d_name, "xlogtemp", strlen("xlogtemp")) == 0) + { + snprintf(path, sizeof(path), "%s/%s", PREALLOCSEGDIR, xlde->d_name); + if (unlink(path) < 0) + { + pg_log_error("could not delete file \"%s\": %m", path); + exit(1); + } + } + } + + if (errno) + { + pg_log_error("could not read directory \"%s\": %m", PREALLOCSEGDIR); + exit(1); + } + + if (closedir(xldir)) + { + pg_log_error("could not close directory \"%s\": %m", PREALLOCSEGDIR); + exit(1); + } +} + + /* * Write an empty XLOG file, containing only the checkpoint record * already set up in ControlFile. diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h index c430b1b236..8303eb48cb 100644 --- a/src/include/postmaster/bgwriter.h +++ b/src/include/postmaster/bgwriter.h @@ -26,6 +26,7 @@ extern int BgWriterDelay; extern int CheckPointTimeout; extern int CheckPointWarning; extern double CheckPointCompletionTarget; +extern int wal_prealloc_max_size_mb; extern void BackgroundWriterMain(void) pg_attribute_noreturn(); extern void CheckpointerMain(void) pg_attribute_noreturn(); @@ -42,4 +43,8 @@ extern void CheckpointerShmemInit(void); extern bool FirstCallSinceLastCheckpoint(void); +extern int GetNumPreallocatedWalSegs(void); +extern void SetNumPreallocatedWalSegs(int i); +extern void RequestWalPreallocation(void); + #endif /* _BGWRITER_H */ diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index abcd74bd51..2d174509c5 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -190,7 +190,7 @@ extern int durable_unlink(const char *fname, int loglevel); extern int durable_rename_excl(const char *oldfile, const char *newfile, int loglevel); extern void SyncDataDirectory(void); extern int data_sync_elevel(int elevel); -extern void CreateEmptyWalSegment(const char *path); +extern bool CreateEmptyWalSegment(const char *path, int elevel); /* Filename components */ #define PG_TEMP_FILES_DIR "pgsql_tmp" -- 2.16.6