diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index fdf6625..2b223e9 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -143,14 +143,16 @@ static CheckpointerShmemStruct *CheckpointerShmem; */ int CheckPointTimeout = 300; int CheckPointWarning = 30; +int CheckPointerFsyncDelayThreshold = -1; double CheckPointCompletionTarget = 0.5; +double CheckPointerFsyncDelayRatio = 0.0; /* * Flags set by interrupt handlers for later service in the main loop. */ static volatile sig_atomic_t got_SIGHUP = false; -static volatile sig_atomic_t checkpoint_requested = false; -static volatile sig_atomic_t shutdown_requested = false; +extern volatile sig_atomic_t checkpoint_requested = false; +extern volatile sig_atomic_t shutdown_requested = false; /* * Private state @@ -169,7 +171,6 @@ static pg_time_t last_xlog_switch_time; static void CheckArchiveTimeout(void); static bool IsCheckpointOnSchedule(double progress); -static bool ImmediateCheckpointRequested(void); static bool CompactCheckpointerRequestQueue(void); static void UpdateSharedMemoryConfig(void); @@ -643,7 +644,7 @@ CheckArchiveTimeout(void) * this does not check the *current* checkpoint's IMMEDIATE flag, but whether * there is one pending behind it.) */ -static bool +extern bool ImmediateCheckpointRequested(void) { if (checkpoint_requested) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 8079226..3f02d0b 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -1828,7 +1828,7 @@ CheckPointBuffers(int flags) BufferSync(flags); CheckpointStats.ckpt_sync_t = GetCurrentTimestamp(); TRACE_POSTGRESQL_BUFFER_CHECKPOINT_SYNC_START(); - smgrsync(); + smgrsync(flags); CheckpointStats.ckpt_sync_end_t = GetCurrentTimestamp(); TRACE_POSTGRESQL_BUFFER_CHECKPOINT_DONE(); } diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index e629181..d762511 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -21,6 +21,7 @@ */ #include "postgres.h" +#include #include #include #include @@ -44,6 +45,9 @@ #define FSYNCS_PER_ABSORB 10 #define UNLINKS_PER_ABSORB 10 +/* Protect too long sleep in each file fsync. */ +#define MAX_FSYNC_SLEEP 10000 + /* * Special values for the segno arg to RememberFsyncRequest. * @@ -162,6 +166,8 @@ static List *pendingUnlinks = NIL; static CycleCtr mdsync_cycle_ctr = 0; static CycleCtr mdckpt_cycle_ctr = 0; +extern volatile sig_atomic_t checkpoint_requested; +extern volatile sig_atomic_t shutdown_requested; typedef enum /* behavior for mdopen & _mdfd_getseg */ { @@ -235,7 +241,7 @@ SetForwardFsyncRequests(void) /* Perform any pending fsyncs we may have queued up, then drop table */ if (pendingOpsTable) { - mdsync(); + mdsync(CHECKPOINT_IMMEDIATE); hash_destroy(pendingOpsTable); } pendingOpsTable = NULL; @@ -974,7 +980,7 @@ mdimmedsync(SMgrRelation reln, ForkNumber forknum) * mdsync() -- Sync previous writes to stable storage. */ void -mdsync(void) +mdsync(int ckpt_flags) { static bool mdsync_in_progress = false; @@ -1171,6 +1177,28 @@ mdsync(void) FilePathName(seg->mdfd_vfd), (double) elapsed / 1000); + /* + * If this fsync has long time, we sleep 'fsync-time * checkpoint_fsync_delay_ratio' + * for giving priority to executing transaction. + */ + if(CheckPointerFsyncDelayThreshold >= 0 && + CheckPointerFsyncDelayRatio > 0 && + !shutdown_requested && + !ImmediateCheckpointRequested() && + !(ckpt_flags & CHECKPOINT_FORCE) && + !(ckpt_flags & CHECKPOINT_END_OF_RECOVERY) && + (elapsed / 1000 > CheckPointerFsyncDelayThreshold)) + { + double fsync_sleep = (elapsed / 1000) * CheckPointerFsyncDelayRatio; + + /* Too long sleep is not good for checkpoint scheduler */ + if(fsync_sleep > MAX_FSYNC_SLEEP) + fsync_sleep = MAX_FSYNC_SLEEP; + pg_usleep(fsync_sleep * 1000L); + if(log_checkpoints) + elog(DEBUG1, "checkpoint sync sleep: time=%.3f msec", + fsync_sleep); + } break; /* out of retry loop */ } diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index f7f1437..bc07b03 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -58,7 +58,7 @@ typedef struct f_smgr BlockNumber nblocks); void (*smgr_immedsync) (SMgrRelation reln, ForkNumber forknum); void (*smgr_pre_ckpt) (void); /* may be NULL */ - void (*smgr_sync) (void); /* may be NULL */ + void (*smgr_sync) (int ckpt_flags); /* may be NULL */ void (*smgr_post_ckpt) (void); /* may be NULL */ } f_smgr; @@ -708,14 +708,18 @@ smgrpreckpt(void) * smgrsync() -- Sync files to disk during checkpoint. */ void -smgrsync(void) +smgrsync(int ckpt_flags) { int i; + /* + * XXX: If we ever have more than one smgr, the remaining progress + * should somehow be divided among all smgrs. + */ for (i = 0; i < NSmgr; i++) { if (smgrsw[i].smgr_sync) - (*(smgrsw[i].smgr_sync)) (); + (*(smgrsw[i].smgr_sync)) (ckpt_flags); } } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index ea16c64..a240c43 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2014,6 +2014,17 @@ static struct config_int ConfigureNamesInt[] = }, { + {"checkpointer_fsync_delay_threshold", PGC_SIGHUP, RESOURCES_CHECKPOINTER, + gettext_noop("If a file fsync time over this threshold, checkpointer sleep file_fsync_time * checkpointer_fsync_delay_ratio."), + NULL, + GUC_UNIT_MS + }, + &CheckPointerFsyncDelayThreshold, + -1, -1, 1000000, + NULL, NULL, NULL + }, + + { {"wal_buffers", PGC_POSTMASTER, WAL_SETTINGS, gettext_noop("Sets the number of disk-page buffers in shared memory for WAL."), NULL, @@ -2551,6 +2562,16 @@ static struct config_real ConfigureNamesReal[] = NULL, NULL, NULL }, + { + {"checkpointer_fsync_delay_ratio", PGC_SIGHUP, RESOURCES_CHECKPOINTER, + gettext_noop("checkpointer sleep time during file fsync in checkpoint."), + NULL + }, + &CheckPointerFsyncDelayRatio, + 0.0, 0.0, 2.0, + NULL, NULL, NULL + }, + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL, NULL diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 0303ac7..707b433 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -186,6 +186,8 @@ #checkpoint_timeout = 5min # range 30s-1h #checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 #checkpoint_warning = 30s # 0 disables +#checkpointer_fsync_delay_ratio = 0.0 # range 0.0 - 1.0 +#checkpointer_fsync_delay_threshold = -1 # range 0 - 1000000 milliseconds. -1 is disable. # - Archiving - diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h index 46d3c26..a02ba1f 100644 --- a/src/include/postmaster/bgwriter.h +++ b/src/include/postmaster/bgwriter.h @@ -23,7 +23,9 @@ extern int BgWriterDelay; extern int CheckPointTimeout; extern int CheckPointWarning; +extern int CheckPointerFsyncDelayThreshold; extern double CheckPointCompletionTarget; +extern double CheckPointerFsyncDelayRatio; extern void BackgroundWriterMain(void) __attribute__((noreturn)); extern void CheckpointerMain(void) __attribute__((noreturn)); @@ -31,6 +33,7 @@ extern void CheckpointerMain(void) __attribute__((noreturn)); extern void RequestCheckpoint(int flags); extern void CheckpointWriteDelay(int flags, double progress); +extern bool ImmediateCheckpointRequested(void); extern bool ForwardFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno); extern void AbsorbFsyncRequests(void); diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index 98b6f13..f796ab7 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -100,7 +100,7 @@ extern void smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks); extern void smgrimmedsync(SMgrRelation reln, ForkNumber forknum); extern void smgrpreckpt(void); -extern void smgrsync(void); +extern void smgrsync(int ckpt_flags); extern void smgrpostckpt(void); extern void AtEOXact_SMgr(void); @@ -126,7 +126,7 @@ extern void mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks); extern void mdimmedsync(SMgrRelation reln, ForkNumber forknum); extern void mdpreckpt(void); -extern void mdsync(void); +extern void mdsync(int ckpt_flags); extern void mdpostckpt(void); extern void SetForwardFsyncRequests(void); diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h index 8dcdd4b..efc5ee4 100644 --- a/src/include/utils/guc_tables.h +++ b/src/include/utils/guc_tables.h @@ -63,6 +63,7 @@ enum config_group RESOURCES_KERNEL, RESOURCES_VACUUM_DELAY, RESOURCES_BGWRITER, + RESOURCES_CHECKPOINTER, RESOURCES_ASYNCHRONOUS, WAL, WAL_SETTINGS,