Hello,

I'd like to propose a small patch that allows better checkpoint progress
monitoring. The patch is quite simple - it adds a new integer GUC
"checkpoint_update_limit" and every time checkpoint writes this number of
buffers, it does two things:

(a) logs a "checkpoint status" message into the server log, with info
about total number of buffers to write, number of already written buffers,
current and average write speed and estimate of remaining time

(b) sends bgwriter stats (so that the buffers_checkpoint is updated)

I believe this will make checkpoint tuning easier, especially with large
shared bufferers and large when there's other write activity (so that it's
difficult to see checkpoint I/O).

The default value (0) means this continuous logging is disabled.

Tomas
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
new file mode 100644
index 67e722f..64d84b0
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
*************** SET ENABLE_SEQSCAN TO OFF;
*** 1863,1868 ****
--- 1863,1885 ----
        </listitem>
       </varlistentry>
  
+      <varlistentry id="guc-checkpoint-update-limit" 
xreflabel="checkpoint_update_limit">
+       <term><varname>checkpoint_update_limit</varname> 
(<type>integer</type>)</term>
+       <indexterm>
+        <primary><varname>checkpoint_update_limit</> configuration 
parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Number of buffers written during a checkpoint between logging a status
+         (with total number of buffers to write, number of already written 
buffers,
+         average/current write and estimate of the remaining time) and updates 
bgwriter
+         stats at the same time. The default value 0 disables the continuous 
updates so
+         the stats are updated only at the end of the checkpoint. This 
parameter can only
+         be set in the <filename>postgresql.conf</> file or on the server 
command line.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
       </variablelist>
       </sect2>
       <sect2 id="runtime-config-wal-archiving">
diff --git a/src/backend/storage/buffer/bufmgr.c 
b/src/backend/storage/buffer/bufmgr.c
new file mode 100644
index 4c7cfb0..b24ec93
*** a/src/backend/storage/buffer/bufmgr.c
--- b/src/backend/storage/buffer/bufmgr.c
***************
*** 66,71 ****
--- 66,72 ----
  bool          zero_damaged_pages = false;
  int                   bgwriter_lru_maxpages = 100;
  double                bgwriter_lru_multiplier = 2.0;
+ int           checkpoint_update_limit = 0;
  
  /*
   * How many buffers PrefetchBuffer callers should try to stay ahead of their
*************** BufferSync(int flags)
*** 1175,1180 ****
--- 1176,1192 ----
        int                     num_to_write;
        int                     num_written;
        int                     mask = BM_DIRTY;
+       
+       int                     num_since_update;
+       
+       long            curr_secs,
+                               total_secs;
+       int                     curr_usecs,
+                               total_usecs;
+       float           curr_time,
+                               total_time;
+       
+       TimestampTz             startTimestamp, lastTimestamp;
  
        /* Make sure we can handle the pin inside SyncOneBuffer */
        ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
*************** BufferSync(int flags)
*** 1238,1243 ****
--- 1250,1260 ----
        buf_id = StrategySyncStart(NULL, NULL);
        num_to_scan = NBuffers;
        num_written = 0;
+       num_since_update = 0;
+       
+       startTimestamp = GetCurrentTimestamp();
+       lastTimestamp = startTimestamp;
+       
        while (num_to_scan-- > 0)
        {
                volatile BufferDesc *bufHdr = &BufferDescriptors[buf_id];
*************** BufferSync(int flags)
*** 1261,1266 ****
--- 1278,1327 ----
                                TRACE_POSTGRESQL_BUFFER_SYNC_WRITTEN(buf_id);
                                BgWriterStats.m_buf_written_checkpoints++;
                                num_written++;
+                               num_since_update++;
+                               
+                               /*
+                                * Every time we write enough buffers 
(checkpoint_update_limit),
+                                * we log a checkpoint status message and 
update the bgwriter
+                                * stats (so that the pg_stat_bgwriter table 
may be updated).
+                                * 
+                                * The log message contains info about total 
number of buffers to
+                                * write, how many buffers are already written, 
average and current
+                                * write speed and an estimate remaining time.
+                                */
+                               if ((checkpoint_update_limit > 0) && 
(num_since_update >= checkpoint_update_limit))
+                               {
+                                 
+                                       TimestampDifference(lastTimestamp,
+                                               GetCurrentTimestamp(),
+                                               &curr_secs, &curr_usecs);
+                                       
+                                       TimestampDifference(startTimestamp,
+                                               GetCurrentTimestamp(),
+                                               &total_secs, &total_usecs);
+                                       
+                                       curr_time = curr_secs + 
(float)curr_usecs / 1000000;
+                                       total_time = total_secs + 
(float)total_usecs / 1000000;
+                                       
+                                       elog(LOG, "checkpoint status: wrote %d 
buffers of %d (%.1f%%) in %.1f s; "
+                                               "average %.1f MB/s (%d buffers, 
%ld.%03d s), "
+                                               "current %.1f MB/s (%d buffers, 
%ld.%03d s), "
+                                               "remaining %.1f s",
+                                               num_written, num_to_write, 
((float) num_written * 100 / num_to_write),
+                                               total_time,
+                                               ((float)BLCKSZ * num_written / 
1024 / 1024 / total_time),
+                                               num_written, total_secs, 
total_usecs/1000,
+                                               ((float)BLCKSZ * 
num_since_update / 1024 / 1024 / curr_time),
+                                               num_since_update, curr_secs, 
curr_usecs/1000,
+                                               (float)(num_to_write - 
num_written) * total_time / (num_written));
+                                       
+                                       pgstat_send_bgwriter();
+                                       
+                                       /* reset the counter and timestamp */
+                                       num_since_update = 0;                   
                
+                                       lastTimestamp = GetCurrentTimestamp();
+ 
+                               }
  
                                /*
                                 * We know there are at most num_to_write 
buffers with
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
new file mode 100644
index 6670997..2176933
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** static struct config_int ConfigureNamesI
*** 1965,1970 ****
--- 1965,1981 ----
        },
  
        {
+               {"checkpoint_update_limit", PGC_SIGHUP, WAL_CHECKPOINTS,
+                       gettext_noop("Sets number of buffers written between 
stats updates during a checkpoint."),
+                       gettext_noop("Every time the checkpoint writes this 
number of buffers, it updates "
+                       "the stats in pg_stat_bgwriter and logs a message with 
the current checkpoint progress. "
+                       "Zero means the stats are updated when the checkpoint 
only."),
+               },
+               &checkpoint_update_limit,
+               0, 0, INT_MAX, NULL, NULL
+       },
+ 
+       {
                {"wal_buffers", PGC_POSTMASTER, WAL_SETTINGS,
                        gettext_noop("Sets the number of disk-page buffers in 
shared memory for WAL."),
                        NULL,
diff --git a/src/backend/utils/misc/postgresql.conf.sample 
b/src/backend/utils/misc/postgresql.conf.sample
new file mode 100644
index 65fd126..284ddd1
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 180,185 ****
--- 180,187 ----
  #checkpoint_timeout = 5min            # range 30s-1h
  #checkpoint_completion_target = 0.5   # checkpoint target duration, 0.0 - 1.0
  #checkpoint_warning = 30s             # 0 disables
+ #checkpoint_update_limit = 0  # buffers written between loggin checkpoint
+                               # status and updating bgwriter stats, 0 disables
  
  # - Archiving -
  
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
new file mode 100644
index b8fc87e..b36a87a
*** a/src/include/storage/bufmgr.h
--- b/src/include/storage/bufmgr.h
*************** extern bool zero_damaged_pages;
*** 49,54 ****
--- 49,55 ----
  extern int    bgwriter_lru_maxpages;
  extern double bgwriter_lru_multiplier;
  extern int    target_prefetch_pages;
+ extern int    checkpoint_update_limit;
  
  /* in buf_init.c */
  extern PGDLLIMPORT char *BufferBlocks;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to