PostgreSQL Source Code  git master
autoprewarm.c File Reference
#include "postgres.h"
#include <unistd.h>
#include "access/relation.h"
#include "access/xact.h"
#include "catalog/pg_class.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/bgworker.h"
#include "postmaster/interrupt.h"
#include "storage/buf_internals.h"
#include "storage/dsm.h"
#include "storage/ipc.h"
#include "storage/latch.h"
#include "storage/lwlock.h"
#include "storage/proc.h"
#include "storage/procsignal.h"
#include "storage/shmem.h"
#include "storage/smgr.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h"
#include "utils/datetime.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/relfilenodemap.h"
#include "utils/resowner.h"
Include dependency graph for autoprewarm.c:

Go to the source code of this file.

Data Structures

struct  BlockInfoRecord
 
struct  AutoPrewarmSharedState
 

Macros

#define AUTOPREWARM_FILE   "autoprewarm.blocks"
 
#define cmp_member_elem(fld)
 

Typedefs

typedef struct BlockInfoRecord BlockInfoRecord
 
typedef struct AutoPrewarmSharedState AutoPrewarmSharedState
 

Functions

void _PG_init (void)
 
void autoprewarm_main (Datum main_arg)
 
void autoprewarm_database_main (Datum main_arg)
 
 PG_FUNCTION_INFO_V1 (autoprewarm_start_worker)
 
 PG_FUNCTION_INFO_V1 (autoprewarm_dump_now)
 
static void apw_load_buffers (void)
 
static int apw_dump_now (bool is_bgworker, bool dump_unlogged)
 
static void apw_start_leader_worker (void)
 
static void apw_start_database_worker (void)
 
static bool apw_init_shmem (void)
 
static void apw_detach_shmem (int code, Datum arg)
 
static int apw_compare_blockinfo (const void *p, const void *q)
 
Datum autoprewarm_start_worker (PG_FUNCTION_ARGS)
 
Datum autoprewarm_dump_now (PG_FUNCTION_ARGS)
 

Variables

static AutoPrewarmSharedStateapw_state = NULL
 
static bool autoprewarm = true
 
static int autoprewarm_interval
 

Macro Definition Documentation

◆ AUTOPREWARM_FILE

#define AUTOPREWARM_FILE   "autoprewarm.blocks"

Definition at line 57 of file autoprewarm.c.

Referenced by apw_dump_now(), and apw_load_buffers().

◆ cmp_member_elem

#define cmp_member_elem (   fld)
Value:
do { \
if (a->fld < b->fld) \
return -1; \
else if (a->fld > b->fld) \
return 1; \
} while(0)

Definition at line 873 of file autoprewarm.c.

Referenced by apw_compare_blockinfo().

Typedef Documentation

◆ AutoPrewarmSharedState

◆ BlockInfoRecord

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 110 of file autoprewarm.c.

References apw_start_leader_worker(), autoprewarm, autoprewarm_interval, DefineCustomBoolVariable(), DefineCustomIntVariable(), EmitWarningsOnPlaceholders(), GUC_UNIT_S, MAXALIGN, PGC_POSTMASTER, PGC_SIGHUP, process_shared_preload_libraries_in_progress, and RequestAddinShmemSpace().

111 {
112  DefineCustomIntVariable("pg_prewarm.autoprewarm_interval",
113  "Sets the interval between dumps of shared buffers",
114  "If set to zero, time-based dumping is disabled.",
116  300,
117  0, INT_MAX / 1000,
118  PGC_SIGHUP,
119  GUC_UNIT_S,
120  NULL,
121  NULL,
122  NULL);
123 
125  return;
126 
127  /* can't define PGC_POSTMASTER variable after startup */
128  DefineCustomBoolVariable("pg_prewarm.autoprewarm",
129  "Starts the autoprewarm worker.",
130  NULL,
131  &autoprewarm,
132  true,
134  0,
135  NULL,
136  NULL,
137  NULL);
138 
139  EmitWarningsOnPlaceholders("pg_prewarm");
140 
142 
143  /* Register autoprewarm worker, if enabled. */
144  if (autoprewarm)
146 }
void DefineCustomIntVariable(const char *name, const char *short_desc, const char *long_desc, int *valueAddr, int bootValue, int minValue, int maxValue, GucContext context, int flags, GucIntCheckHook check_hook, GucIntAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:9177
void RequestAddinShmemSpace(Size size)
Definition: ipci.c:71
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1598
static int autoprewarm_interval
Definition: autoprewarm.c:104
#define GUC_UNIT_S
Definition: guc.h:226
void EmitWarningsOnPlaceholders(const char *className)
Definition: guc.c:9290
static void apw_start_leader_worker(void)
Definition: autoprewarm.c:799
Definition: guc.h:72
static bool autoprewarm
Definition: autoprewarm.c:103
#define MAXALIGN(LEN)
Definition: c.h:757
void DefineCustomBoolVariable(const char *name, const char *short_desc, const char *long_desc, bool *valueAddr, bool bootValue, GucContext context, int flags, GucBoolCheckHook check_hook, GucBoolAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:9151

◆ apw_compare_blockinfo()

static int apw_compare_blockinfo ( const void *  p,
const void *  q 
)
static

Definition at line 891 of file autoprewarm.c.

References BlockInfoRecord::blocknum, cmp_member_elem, BlockInfoRecord::database, BlockInfoRecord::filenode, BlockInfoRecord::forknum, and BlockInfoRecord::tablespace.

Referenced by apw_load_buffers().

892 {
893  const BlockInfoRecord *a = (const BlockInfoRecord *) p;
894  const BlockInfoRecord *b = (const BlockInfoRecord *) q;
895 
896  cmp_member_elem(database);
898  cmp_member_elem(filenode);
899  cmp_member_elem(forknum);
900  cmp_member_elem(blocknum);
901 
902  return 0;
903 }
#define cmp_member_elem(fld)
Definition: autoprewarm.c:873
char * tablespace
Definition: pgbench.c:226

◆ apw_detach_shmem()

static void apw_detach_shmem ( int  code,
Datum  arg 
)
static

Definition at line 785 of file autoprewarm.c.

References AutoPrewarmSharedState::bgworker_pid, InvalidPid, AutoPrewarmSharedState::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyProcPid, and AutoPrewarmSharedState::pid_using_dumpfile.

Referenced by autoprewarm_dump_now(), and autoprewarm_main().

786 {
793 }
int MyProcPid
Definition: globals.c:43
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
static AutoPrewarmSharedState * apw_state
Definition: autoprewarm.c:100
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
#define InvalidPid
Definition: miscadmin.h:32

◆ apw_dump_now()

static int apw_dump_now ( bool  is_bgworker,
bool  dump_unlogged 
)
static

Definition at line 566 of file autoprewarm.c.

References AllocateFile(), AUTOPREWARM_FILE, BlockInfoRecord::blocknum, buftag::blockNum, BM_PERMANENT, BM_TAG_VALID, CHECK_FOR_INTERRUPTS, BlockInfoRecord::database, RelFileNode::dbNode, DEBUG1, durable_rename(), ereport, errcode_for_file_access(), errmsg(), errmsg_internal(), ERROR, BlockInfoRecord::filenode, BlockInfoRecord::forknum, buftag::forkNum, fprintf, FreeFile(), GetBufferDescriptor, i, InvalidPid, AutoPrewarmSharedState::lock, LockBufHdr(), LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAXPGPATH, MyProcPid, NBuffers, palloc(), pfree(), AutoPrewarmSharedState::pid_using_dumpfile, RelFileNode::relNode, buftag::rnode, snprintf, RelFileNode::spcNode, BlockInfoRecord::tablespace, BufferDesc::tag, and UnlockBufHdr.

Referenced by autoprewarm_dump_now(), and autoprewarm_main().

567 {
568  int num_blocks;
569  int i;
570  int ret;
571  BlockInfoRecord *block_info_array;
572  BufferDesc *bufHdr;
573  FILE *file;
574  char transient_dump_file_path[MAXPGPATH];
575  pid_t pid;
576 
582 
583  if (pid != InvalidPid)
584  {
585  if (!is_bgworker)
586  ereport(ERROR,
587  (errmsg("could not perform block dump because dump file is being used by PID %lu",
588  (unsigned long) apw_state->pid_using_dumpfile)));
589 
590  ereport(LOG,
591  (errmsg("skipping block dump because it is already being performed by PID %lu",
592  (unsigned long) apw_state->pid_using_dumpfile)));
593  return 0;
594  }
595 
596  block_info_array =
598 
599  for (num_blocks = 0, i = 0; i < NBuffers; i++)
600  {
601  uint32 buf_state;
602 
604 
605  bufHdr = GetBufferDescriptor(i);
606 
607  /* Lock each buffer header before inspecting. */
608  buf_state = LockBufHdr(bufHdr);
609 
610  /*
611  * Unlogged tables will be automatically truncated after a crash or
612  * unclean shutdown. In such cases we need not prewarm them. Dump them
613  * only if requested by caller.
614  */
615  if (buf_state & BM_TAG_VALID &&
616  ((buf_state & BM_PERMANENT) || dump_unlogged))
617  {
618  block_info_array[num_blocks].database = bufHdr->tag.rnode.dbNode;
619  block_info_array[num_blocks].tablespace = bufHdr->tag.rnode.spcNode;
620  block_info_array[num_blocks].filenode = bufHdr->tag.rnode.relNode;
621  block_info_array[num_blocks].forknum = bufHdr->tag.forkNum;
622  block_info_array[num_blocks].blocknum = bufHdr->tag.blockNum;
623  ++num_blocks;
624  }
625 
626  UnlockBufHdr(bufHdr, buf_state);
627  }
628 
629  snprintf(transient_dump_file_path, MAXPGPATH, "%s.tmp", AUTOPREWARM_FILE);
630  file = AllocateFile(transient_dump_file_path, "w");
631  if (!file)
632  ereport(ERROR,
634  errmsg("could not open file \"%s\": %m",
635  transient_dump_file_path)));
636 
637  ret = fprintf(file, "<<%d>>\n", num_blocks);
638  if (ret < 0)
639  {
640  int save_errno = errno;
641 
642  FreeFile(file);
643  unlink(transient_dump_file_path);
644  errno = save_errno;
645  ereport(ERROR,
647  errmsg("could not write to file \"%s\": %m",
648  transient_dump_file_path)));
649  }
650 
651  for (i = 0; i < num_blocks; i++)
652  {
654 
655  ret = fprintf(file, "%u,%u,%u,%u,%u\n",
656  block_info_array[i].database,
657  block_info_array[i].tablespace,
658  block_info_array[i].filenode,
659  (uint32) block_info_array[i].forknum,
660  block_info_array[i].blocknum);
661  if (ret < 0)
662  {
663  int save_errno = errno;
664 
665  FreeFile(file);
666  unlink(transient_dump_file_path);
667  errno = save_errno;
668  ereport(ERROR,
670  errmsg("could not write to file \"%s\": %m",
671  transient_dump_file_path)));
672  }
673  }
674 
675  pfree(block_info_array);
676 
677  /*
678  * Rename transient_dump_file_path to AUTOPREWARM_FILE to make things
679  * permanent.
680  */
681  ret = FreeFile(file);
682  if (ret != 0)
683  {
684  int save_errno = errno;
685 
686  unlink(transient_dump_file_path);
687  errno = save_errno;
688  ereport(ERROR,
690  errmsg("could not close file \"%s\": %m",
691  transient_dump_file_path)));
692  }
693 
694  (void) durable_rename(transient_dump_file_path, AUTOPREWARM_FILE, ERROR);
696 
697  ereport(DEBUG1,
698  (errmsg_internal("wrote block details for %d blocks", num_blocks)));
699  return num_blocks;
700 }
#define BM_PERMANENT
Definition: buf_internals.h:67
#define DEBUG1
Definition: elog.h:25
int MyProcPid
Definition: globals.c:43
#define BM_TAG_VALID
Definition: buf_internals.h:61
ForkNumber forkNum
Definition: buf_internals.h:94
#define LOG
Definition: elog.h:26
#define fprintf
Definition: port.h:220
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
#define AUTOPREWARM_FILE
Definition: autoprewarm.c:57
ForkNumber forknum
Definition: autoprewarm.c:65
void pfree(void *pointer)
Definition: mcxt.c:1169
#define ERROR
Definition: elog.h:46
static AutoPrewarmSharedState * apw_state
Definition: autoprewarm.c:100
#define MAXPGPATH
char * tablespace
Definition: pgbench.c:226
int errcode_for_file_access(void)
Definition: elog.c:721
#define GetBufferDescriptor(id)
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2417
unsigned int uint32
Definition: c.h:441
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:692
#define ereport(elevel,...)
Definition: elog.h:157
int errmsg_internal(const char *fmt,...)
Definition: elog.c:996
uint32 LockBufHdr(BufferDesc *desc)
Definition: bufmgr.c:4591
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
BlockNumber blockNum
Definition: buf_internals.h:95
RelFileNode rnode
Definition: buf_internals.h:93
int FreeFile(FILE *file)
Definition: fd.c:2616
BufferTag tag
BlockNumber blocknum
Definition: autoprewarm.c:66
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define UnlockBufHdr(desc, s)
int i
int NBuffers
Definition: globals.c:135
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
#define snprintf
Definition: port.h:216
#define InvalidPid
Definition: miscadmin.h:32

◆ apw_init_shmem()

static bool apw_init_shmem ( void  )
static

Definition at line 759 of file autoprewarm.c.

References AutoPrewarmSharedState::bgworker_pid, InvalidPid, AutoPrewarmSharedState::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockInitialize(), LWLockNewTrancheId(), LWLockRegisterTranche(), LWLockRelease(), AutoPrewarmSharedState::pid_using_dumpfile, ShmemInitStruct(), and LWLock::tranche.

Referenced by autoprewarm_database_main(), autoprewarm_dump_now(), autoprewarm_main(), and autoprewarm_start_worker().

760 {
761  bool found;
762 
763  LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
764  apw_state = ShmemInitStruct("autoprewarm",
765  sizeof(AutoPrewarmSharedState),
766  &found);
767  if (!found)
768  {
769  /* First time through ... */
773  }
774  LWLockRelease(AddinShmemInitLock);
775 
776  LWLockRegisterTranche(apw_state->lock.tranche, "autoprewarm");
777 
778  return found;
779 }
int LWLockNewTrancheId(void)
Definition: lwlock.c:625
void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
Definition: lwlock.c:649
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
static AutoPrewarmSharedState * apw_state
Definition: autoprewarm.c:100
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
uint16 tranche
Definition: lwlock.h:33
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:736
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
#define InvalidPid
Definition: miscadmin.h:32

◆ apw_load_buffers()

static void apw_load_buffers ( void  )
static

Definition at line 272 of file autoprewarm.c.

References AllocateFile(), apw_compare_blockinfo(), apw_start_database_worker(), Assert, AUTOPREWARM_FILE, AutoPrewarmSharedState::block_info_handle, BlockInfoRecord::blocknum, BlockInfoRecord::database, AutoPrewarmSharedState::database, dsm_create(), dsm_detach(), DSM_HANDLE_INVALID, dsm_segment_address(), dsm_segment_handle(), ereport, errcode_for_file_access(), errmsg(), ERROR, BlockInfoRecord::filenode, BlockInfoRecord::forknum, FreeFile(), have_free_buffer(), i, InvalidOid, InvalidPid, AutoPrewarmSharedState::lock, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyProcPid, pg_qsort(), AutoPrewarmSharedState::pid_using_dumpfile, AutoPrewarmSharedState::prewarm_start_idx, AutoPrewarmSharedState::prewarm_stop_idx, AutoPrewarmSharedState::prewarmed_blocks, ShutdownRequestPending, and BlockInfoRecord::tablespace.

Referenced by autoprewarm_main().

273 {
274  FILE *file = NULL;
275  int num_elements,
276  i;
277  BlockInfoRecord *blkinfo;
278  dsm_segment *seg;
279 
280  /*
281  * Skip the prewarm if the dump file is in use; otherwise, prevent any
282  * other process from writing it while we're using it.
283  */
287  else
288  {
290  ereport(LOG,
291  (errmsg("skipping prewarm because block dump file is being written by PID %lu",
292  (unsigned long) apw_state->pid_using_dumpfile)));
293  return;
294  }
296 
297  /*
298  * Open the block dump file. Exit quietly if it doesn't exist, but report
299  * any other error.
300  */
301  file = AllocateFile(AUTOPREWARM_FILE, "r");
302  if (!file)
303  {
304  if (errno == ENOENT)
305  {
309  return; /* No file to load. */
310  }
311  ereport(ERROR,
313  errmsg("could not read file \"%s\": %m",
314  AUTOPREWARM_FILE)));
315  }
316 
317  /* First line of the file is a record count. */
318  if (fscanf(file, "<<%d>>\n", &num_elements) != 1)
319  ereport(ERROR,
321  errmsg("could not read from file \"%s\": %m",
322  AUTOPREWARM_FILE)));
323 
324  /* Allocate a dynamic shared memory segment to store the record data. */
325  seg = dsm_create(sizeof(BlockInfoRecord) * num_elements, 0);
326  blkinfo = (BlockInfoRecord *) dsm_segment_address(seg);
327 
328  /* Read records, one per line. */
329  for (i = 0; i < num_elements; i++)
330  {
331  unsigned forknum;
332 
333  if (fscanf(file, "%u,%u,%u,%u,%u\n", &blkinfo[i].database,
334  &blkinfo[i].tablespace, &blkinfo[i].filenode,
335  &forknum, &blkinfo[i].blocknum) != 5)
336  ereport(ERROR,
337  (errmsg("autoprewarm block dump file is corrupted at line %d",
338  i + 1)));
339  blkinfo[i].forknum = forknum;
340  }
341 
342  FreeFile(file);
343 
344  /* Sort the blocks to be loaded. */
345  pg_qsort(blkinfo, num_elements, sizeof(BlockInfoRecord),
347 
348  /* Populate shared memory state. */
352 
353  /* Get the info position of the first block of the next database. */
354  while (apw_state->prewarm_start_idx < num_elements)
355  {
356  int j = apw_state->prewarm_start_idx;
357  Oid current_db = blkinfo[j].database;
358 
359  /*
360  * Advance the prewarm_stop_idx to the first BlockInfoRecord that does
361  * not belong to this database.
362  */
363  j++;
364  while (j < num_elements)
365  {
366  if (current_db != blkinfo[j].database)
367  {
368  /*
369  * Combine BlockInfoRecords for global objects with those of
370  * the database.
371  */
372  if (current_db != InvalidOid)
373  break;
374  current_db = blkinfo[j].database;
375  }
376 
377  j++;
378  }
379 
380  /*
381  * If we reach this point with current_db == InvalidOid, then only
382  * BlockInfoRecords belonging to global objects exist. We can't
383  * prewarm without a database connection, so just bail out.
384  */
385  if (current_db == InvalidOid)
386  break;
387 
388  /* Configure stop point and database for next per-database worker. */
390  apw_state->database = current_db;
392 
393  /* If we've run out of free buffers, don't launch another worker. */
394  if (!have_free_buffer())
395  break;
396 
397  /*
398  * Likewise, don't launch if we've already been told to shut down.
399  * (The launch would fail anyway, but we might as well skip it.)
400  */
402  break;
403 
404  /*
405  * Start a per-database worker to load blocks for this database; this
406  * function will return once the per-database worker exits.
407  */
409 
410  /* Prepare for next database. */
412  }
413 
414  /* Clean up. */
415  dsm_detach(seg);
420 
421  /* Report our success, if we were able to finish. */
423  ereport(LOG,
424  (errmsg("autoprewarm successfully prewarmed %d of %d previously-loaded blocks",
425  apw_state->prewarmed_blocks, num_elements)));
426 }
int MyProcPid
Definition: globals.c:43
dsm_handle dsm_segment_handle(dsm_segment *seg)
Definition: dsm.c:1087
#define LOG
Definition: elog.h:26
unsigned int Oid
Definition: postgres_ext.h:31
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
#define DSM_HANDLE_INVALID
Definition: dsm.h:23
#define AUTOPREWARM_FILE
Definition: autoprewarm.c:57
ForkNumber forknum
Definition: autoprewarm.c:65
#define ERROR
Definition: elog.h:46
static AutoPrewarmSharedState * apw_state
Definition: autoprewarm.c:100
static void apw_start_database_worker(void)
Definition: autoprewarm.c:841
char * tablespace
Definition: pgbench.c:226
int errcode_for_file_access(void)
Definition: elog.c:721
dsm_handle block_info_handle
Definition: autoprewarm.c:77
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2417
volatile sig_atomic_t ShutdownRequestPending
Definition: interrupt.c:27
dsm_segment * dsm_create(Size size, int flags)
Definition: dsm.c:487
bool have_free_buffer(void)
Definition: freelist.c:180
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
void * dsm_segment_address(dsm_segment *seg)
Definition: dsm.c:1059
#define Assert(condition)
Definition: c.h:804
void pg_qsort(void *base, size_t nel, size_t elsize, int(*cmp)(const void *, const void *))
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
int FreeFile(FILE *file)
Definition: fd.c:2616
void dsm_detach(dsm_segment *seg)
Definition: dsm.c:769
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
static int apw_compare_blockinfo(const void *p, const void *q)
Definition: autoprewarm.c:891
#define InvalidPid
Definition: miscadmin.h:32

◆ apw_start_database_worker()

static void apw_start_database_worker ( void  )
static

Definition at line 841 of file autoprewarm.c.

References BackgroundWorker::bgw_flags, BackgroundWorker::bgw_function_name, BackgroundWorker::bgw_library_name, BackgroundWorker::bgw_name, BGW_NEVER_RESTART, BackgroundWorker::bgw_notify_pid, BackgroundWorker::bgw_restart_time, BackgroundWorker::bgw_start_time, BackgroundWorker::bgw_type, BGWORKER_BACKEND_DATABASE_CONNECTION, BGWORKER_SHMEM_ACCESS, BgWorkerStart_ConsistentState, ereport, errcode(), errhint(), errmsg(), ERROR, MemSet, MyProcPid, RegisterDynamicBackgroundWorker(), and WaitForBackgroundWorkerShutdown().

Referenced by apw_load_buffers().

842 {
843  BackgroundWorker worker;
844  BackgroundWorkerHandle *handle;
845 
846  MemSet(&worker, 0, sizeof(BackgroundWorker));
847  worker.bgw_flags =
851  strcpy(worker.bgw_library_name, "pg_prewarm");
852  strcpy(worker.bgw_function_name, "autoprewarm_database_main");
853  strcpy(worker.bgw_name, "autoprewarm worker");
854  strcpy(worker.bgw_type, "autoprewarm worker");
855 
856  /* must set notify PID to wait for shutdown */
857  worker.bgw_notify_pid = MyProcPid;
858 
859  if (!RegisterDynamicBackgroundWorker(&worker, &handle))
860  ereport(ERROR,
861  (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
862  errmsg("registering dynamic bgworker autoprewarm failed"),
863  errhint("Consider increasing configuration parameter \"max_worker_processes\".")));
864 
865  /*
866  * Ignore return value; if it fails, postmaster has died, but we have
867  * checks for that elsewhere.
868  */
870 }
int MyProcPid
Definition: globals.c:43
int errhint(const char *fmt,...)
Definition: elog.c:1156
int bgw_restart_time
Definition: bgworker.h:94
int errcode(int sqlerrcode)
Definition: elog.c:698
#define MemSet(start, val, len)
Definition: c.h:1008
#define BGWORKER_SHMEM_ACCESS
Definition: bgworker.h:52
char bgw_function_name[BGW_MAXLEN]
Definition: bgworker.h:96
#define ERROR
Definition: elog.h:46
BgwHandleStatus WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle)
Definition: bgworker.c:1185
#define BGW_NEVER_RESTART
Definition: bgworker.h:84
#define ereport(elevel,...)
Definition: elog.h:157
char bgw_name[BGW_MAXLEN]
Definition: bgworker.h:90
#define BGWORKER_BACKEND_DATABASE_CONNECTION
Definition: bgworker.h:59
BgWorkerStartTime bgw_start_time
Definition: bgworker.h:93
bool RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle)
Definition: bgworker.c:973
char bgw_type[BGW_MAXLEN]
Definition: bgworker.h:91
int errmsg(const char *fmt,...)
Definition: elog.c:909
pid_t bgw_notify_pid
Definition: bgworker.h:99
char bgw_library_name[BGW_MAXLEN]
Definition: bgworker.h:95

◆ apw_start_leader_worker()

static void apw_start_leader_worker ( void  )
static

Definition at line 799 of file autoprewarm.c.

References BackgroundWorker::bgw_flags, BackgroundWorker::bgw_function_name, BackgroundWorker::bgw_library_name, BackgroundWorker::bgw_name, BackgroundWorker::bgw_notify_pid, BackgroundWorker::bgw_start_time, BackgroundWorker::bgw_type, BGWH_STARTED, BGWORKER_SHMEM_ACCESS, BgWorkerStart_ConsistentState, ereport, errcode(), errhint(), errmsg(), ERROR, MemSet, MyProcPid, process_shared_preload_libraries_in_progress, RegisterBackgroundWorker(), RegisterDynamicBackgroundWorker(), status(), and WaitForBackgroundWorkerStartup().

Referenced by _PG_init(), and autoprewarm_start_worker().

800 {
801  BackgroundWorker worker;
802  BackgroundWorkerHandle *handle;
804  pid_t pid;
805 
806  MemSet(&worker, 0, sizeof(BackgroundWorker));
809  strcpy(worker.bgw_library_name, "pg_prewarm");
810  strcpy(worker.bgw_function_name, "autoprewarm_main");
811  strcpy(worker.bgw_name, "autoprewarm leader");
812  strcpy(worker.bgw_type, "autoprewarm leader");
813 
815  {
816  RegisterBackgroundWorker(&worker);
817  return;
818  }
819 
820  /* must set notify PID to wait for startup */
821  worker.bgw_notify_pid = MyProcPid;
822 
823  if (!RegisterDynamicBackgroundWorker(&worker, &handle))
824  ereport(ERROR,
825  (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
826  errmsg("could not register background process"),
827  errhint("You may need to increase max_worker_processes.")));
828 
829  status = WaitForBackgroundWorkerStartup(handle, &pid);
830  if (status != BGWH_STARTED)
831  ereport(ERROR,
832  (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
833  errmsg("could not start background process"),
834  errhint("More details may be available in the server log.")));
835 }
BgwHandleStatus WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp)
Definition: bgworker.c:1140
void RegisterBackgroundWorker(BackgroundWorker *worker)
Definition: bgworker.c:889
int MyProcPid
Definition: globals.c:43
int errhint(const char *fmt,...)
Definition: elog.c:1156
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1598
int errcode(int sqlerrcode)
Definition: elog.c:698
#define MemSet(start, val, len)
Definition: c.h:1008
#define BGWORKER_SHMEM_ACCESS
Definition: bgworker.h:52
char bgw_function_name[BGW_MAXLEN]
Definition: bgworker.h:96
#define ERROR
Definition: elog.h:46
BgwHandleStatus
Definition: bgworker.h:102
#define ereport(elevel,...)
Definition: elog.h:157
char bgw_name[BGW_MAXLEN]
Definition: bgworker.h:90
BgWorkerStartTime bgw_start_time
Definition: bgworker.h:93
bool RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle)
Definition: bgworker.c:973
char bgw_type[BGW_MAXLEN]
Definition: bgworker.h:91
int errmsg(const char *fmt,...)
Definition: elog.c:909
pid_t bgw_notify_pid
Definition: bgworker.h:99
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
char bgw_library_name[BGW_MAXLEN]
Definition: bgworker.h:95

◆ autoprewarm_database_main()

void autoprewarm_database_main ( Datum  main_arg)

Definition at line 433 of file autoprewarm.c.

References AccessShareLock, apw_init_shmem(), Assert, BackgroundWorkerInitializeConnectionByOid(), BackgroundWorkerUnblockSignals(), AutoPrewarmSharedState::block_info_handle, BlockInfoRecord::blocknum, buf, BufferIsValid, CHECK_FOR_INTERRUPTS, CommitTransactionCommand(), BlockInfoRecord::database, AutoPrewarmSharedState::database, die, dsm_attach(), dsm_detach(), dsm_segment_address(), ereport, errcode(), errmsg(), ERROR, BlockInfoRecord::filenode, BlockInfoRecord::forknum, have_free_buffer(), InvalidForkNumber, InvalidOid, MAX_FORKNUM, OidIsValid, pqsignal(), AutoPrewarmSharedState::prewarm_start_idx, AutoPrewarmSharedState::prewarmed_blocks, RBM_NORMAL, ReadBufferExtended(), relation_close(), RelationGetNumberOfBlocksInFork(), RelationGetSmgr(), ReleaseBuffer(), RelidByRelfilenode(), smgrexists(), StartTransactionCommand(), BlockInfoRecord::tablespace, and try_relation_open().

434 {
435  int pos;
436  BlockInfoRecord *block_info;
437  Relation rel = NULL;
438  BlockNumber nblocks = 0;
439  BlockInfoRecord *old_blk = NULL;
440  dsm_segment *seg;
441 
442  /* Establish signal handlers; once that's done, unblock signals. */
443  pqsignal(SIGTERM, die);
445 
446  /* Connect to correct database and get block information. */
447  apw_init_shmem();
449  if (seg == NULL)
450  ereport(ERROR,
451  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
452  errmsg("could not map dynamic shared memory segment")));
454  block_info = (BlockInfoRecord *) dsm_segment_address(seg);
456 
457  /*
458  * Loop until we run out of blocks to prewarm or until we run out of free
459  * buffers.
460  */
461  while (pos < apw_state->prewarm_stop_idx && have_free_buffer())
462  {
463  BlockInfoRecord *blk = &block_info[pos++];
464  Buffer buf;
465 
467 
468  /*
469  * Quit if we've reached records for another database. If previous
470  * blocks are of some global objects, then continue pre-warming.
471  */
472  if (old_blk != NULL && old_blk->database != blk->database &&
473  old_blk->database != 0)
474  break;
475 
476  /*
477  * As soon as we encounter a block of a new relation, close the old
478  * relation. Note that rel will be NULL if try_relation_open failed
479  * previously; in that case, there is nothing to close.
480  */
481  if (old_blk != NULL && old_blk->filenode != blk->filenode &&
482  rel != NULL)
483  {
485  rel = NULL;
487  }
488 
489  /*
490  * Try to open each new relation, but only once, when we first
491  * encounter it. If it's been dropped, skip the associated blocks.
492  */
493  if (old_blk == NULL || old_blk->filenode != blk->filenode)
494  {
495  Oid reloid;
496 
497  Assert(rel == NULL);
499  reloid = RelidByRelfilenode(blk->tablespace, blk->filenode);
500  if (OidIsValid(reloid))
501  rel = try_relation_open(reloid, AccessShareLock);
502 
503  if (!rel)
505  }
506  if (!rel)
507  {
508  old_blk = blk;
509  continue;
510  }
511 
512  /* Once per fork, check for fork existence and size. */
513  if (old_blk == NULL ||
514  old_blk->filenode != blk->filenode ||
515  old_blk->forknum != blk->forknum)
516  {
517  /*
518  * smgrexists is not safe for illegal forknum, hence check whether
519  * the passed forknum is valid before using it in smgrexists.
520  */
521  if (blk->forknum > InvalidForkNumber &&
522  blk->forknum <= MAX_FORKNUM &&
523  smgrexists(RelationGetSmgr(rel), blk->forknum))
524  nblocks = RelationGetNumberOfBlocksInFork(rel, blk->forknum);
525  else
526  nblocks = 0;
527  }
528 
529  /* Check whether blocknum is valid and within fork file size. */
530  if (blk->blocknum >= nblocks)
531  {
532  /* Move to next forknum. */
533  old_blk = blk;
534  continue;
535  }
536 
537  /* Prewarm buffer. */
538  buf = ReadBufferExtended(rel, blk->forknum, blk->blocknum, RBM_NORMAL,
539  NULL);
540  if (BufferIsValid(buf))
541  {
543  ReleaseBuffer(buf);
544  }
545 
546  old_blk = blk;
547  }
548 
549  dsm_detach(seg);
550 
551  /* Release lock on previous relation. */
552  if (rel)
553  {
556  }
557 }
void CommitTransactionCommand(void)
Definition: xact.c:2939
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:741
dsm_segment * dsm_attach(dsm_handle h)
Definition: dsm.c:631
Oid RelidByRelfilenode(Oid reltablespace, Oid relfilenode)
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:698
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3772
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:247
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:89
ForkNumber forknum
Definition: autoprewarm.c:65
#define ERROR
Definition: elog.h:46
static AutoPrewarmSharedState * apw_state
Definition: autoprewarm.c:100
static char * buf
Definition: pg_test_fsync.c:68
dsm_handle block_info_handle
Definition: autoprewarm.c:77
static bool apw_init_shmem(void)
Definition: autoprewarm.c:759
bool have_free_buffer(void)
Definition: freelist.c:180
void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags)
Definition: postmaster.c:5708
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
pqsigfunc pqsignal(int signum, pqsigfunc handler)
Definition: signal.c:170
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
Definition: bufmgr.c:2939
void * dsm_segment_address(dsm_segment *seg)
Definition: dsm.c:1059
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:804
void StartTransactionCommand(void)
Definition: xact.c:2838
static SMgrRelation RelationGetSmgr(Relation rel)
Definition: rel.h:544
#define MAX_FORKNUM
Definition: relpath.h:55
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
BlockNumber blocknum
Definition: autoprewarm.c:66
void dsm_detach(dsm_segment *seg)
Definition: dsm.c:769
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
int Buffer
Definition: buf.h:23
#define die(msg)
Definition: pg_test_fsync.c:97
void BackgroundWorkerUnblockSignals(void)
Definition: postmaster.c:5737

◆ autoprewarm_dump_now()

Datum autoprewarm_dump_now ( PG_FUNCTION_ARGS  )

Definition at line 738 of file autoprewarm.c.

References apw_detach_shmem(), apw_dump_now(), apw_init_shmem(), PG_END_ENSURE_ERROR_CLEANUP, PG_ENSURE_ERROR_CLEANUP, and PG_RETURN_INT64.

739 {
740  int num_blocks;
741 
742  apw_init_shmem();
743 
745  {
746  num_blocks = apw_dump_now(false, true);
747  }
749 
750  PG_RETURN_INT64((int64) num_blocks);
751 }
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
static int apw_dump_now(bool is_bgworker, bool dump_unlogged)
Definition: autoprewarm.c:566
#define PG_ENSURE_ERROR_CLEANUP(cleanup_function, arg)
Definition: ipc.h:47
static bool apw_init_shmem(void)
Definition: autoprewarm.c:759
#define PG_END_ENSURE_ERROR_CLEANUP(cleanup_function, arg)
Definition: ipc.h:52
static void apw_detach_shmem(int code, Datum arg)
Definition: autoprewarm.c:785

◆ autoprewarm_main()

void autoprewarm_main ( Datum  main_arg)

Definition at line 153 of file autoprewarm.c.

References apw_detach_shmem(), apw_dump_now(), apw_init_shmem(), apw_load_buffers(), autoprewarm_interval, BackgroundWorkerUnblockSignals(), AutoPrewarmSharedState::bgworker_pid, ConfigReloadPending, ereport, errmsg(), GetCurrentTimestamp(), InvalidPid, AutoPrewarmSharedState::lock, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyLatch, MyProcPid, on_shmem_exit(), PG_WAIT_EXTENSION, PGC_SIGHUP, pqsignal(), ProcessConfigFile(), procsignal_sigusr1_handler(), ResetLatch(), ShutdownRequestPending, SIGHUP, SignalHandlerForConfigReload(), SignalHandlerForShutdownRequest(), SIGUSR1, TimestampDifferenceMilliseconds(), TimestampTzPlusMilliseconds, WaitLatch(), WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, and WL_TIMEOUT.

154 {
155  bool first_time = true;
156  bool final_dump_allowed = true;
157  TimestampTz last_dump_time = 0;
158 
159  /* Establish signal handlers; once that's done, unblock signals. */
164 
165  /* Create (if necessary) and attach to our shared memory area. */
166  if (apw_init_shmem())
167  first_time = false;
168 
169  /* Set on-detach hook so that our PID will be cleared on exit. */
171 
172  /*
173  * Store our PID in the shared memory area --- unless there's already
174  * another worker running, in which case just exit.
175  */
178  {
180  ereport(LOG,
181  (errmsg("autoprewarm worker is already running under PID %lu",
182  (unsigned long) apw_state->bgworker_pid)));
183  return;
184  }
187 
188  /*
189  * Preload buffers from the dump file only if we just created the shared
190  * memory region. Otherwise, it's either already been done or shouldn't
191  * be done - e.g. because the old dump file has been overwritten since the
192  * server was started.
193  *
194  * There's not much point in performing a dump immediately after we finish
195  * preloading; so, if we do end up preloading, consider the last dump time
196  * to be equal to the current time.
197  *
198  * If apw_load_buffers() is terminated early by a shutdown request,
199  * prevent dumping out our state below the loop, because we'd effectively
200  * just truncate the saved state to however much we'd managed to preload.
201  */
202  if (first_time)
203  {
205  final_dump_allowed = !ShutdownRequestPending;
206  last_dump_time = GetCurrentTimestamp();
207  }
208 
209  /* Periodically dump buffers until terminated. */
210  while (!ShutdownRequestPending)
211  {
212  /* In case of a SIGHUP, just reload the configuration. */
214  {
215  ConfigReloadPending = false;
217  }
218 
219  if (autoprewarm_interval <= 0)
220  {
221  /* We're only dumping at shutdown, so just wait forever. */
222  (void) WaitLatch(MyLatch,
224  -1L,
226  }
227  else
228  {
229  TimestampTz next_dump_time;
230  long delay_in_ms;
231 
232  /* Compute the next dump time. */
233  next_dump_time =
234  TimestampTzPlusMilliseconds(last_dump_time,
235  autoprewarm_interval * 1000);
236  delay_in_ms =
238  next_dump_time);
239 
240  /* Perform a dump if it's time. */
241  if (delay_in_ms <= 0)
242  {
243  last_dump_time = GetCurrentTimestamp();
244  apw_dump_now(true, false);
245  continue;
246  }
247 
248  /* Sleep until the next dump time. */
249  (void) WaitLatch(MyLatch,
251  delay_in_ms,
253  }
254 
255  /* Reset the latch, loop. */
257  }
258 
259  /*
260  * Dump one last time. We assume this is probably the result of a system
261  * shutdown, although it's possible that we've merely been terminated.
262  */
263  if (final_dump_allowed)
264  apw_dump_now(true, true);
265 }
int MyProcPid
Definition: globals.c:43
#define WL_TIMEOUT
Definition: latch.h:128
void ProcessConfigFile(GucContext context)
#define SIGUSR1
Definition: win32_port.h:171
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1580
#define PG_WAIT_EXTENSION
Definition: wait_event.h:23
int64 TimestampTz
Definition: timestamp.h:39
void SignalHandlerForConfigReload(SIGNAL_ARGS)
Definition: interrupt.c:56
static int autoprewarm_interval
Definition: autoprewarm.c:104
#define LOG
Definition: elog.h:26
static int apw_dump_now(bool is_bgworker, bool dump_unlogged)
Definition: autoprewarm.c:566
void ResetLatch(Latch *latch)
Definition: latch.c:660
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition: latch.c:452
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
static AutoPrewarmSharedState * apw_state
Definition: autoprewarm.c:100
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:361
#define SIGHUP
Definition: win32_port.h:159
static bool apw_init_shmem(void)
Definition: autoprewarm.c:759
volatile sig_atomic_t ShutdownRequestPending
Definition: interrupt.c:27
Definition: guc.h:72
void SignalHandlerForShutdownRequest(SIGNAL_ARGS)
Definition: interrupt.c:104
#define TimestampTzPlusMilliseconds(tz, ms)
Definition: timestamp.h:56
#define ereport(elevel,...)
Definition: elog.h:157
pqsigfunc pqsignal(int signum, pqsigfunc handler)
Definition: signal.c:170
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
int errmsg(const char *fmt,...)
Definition: elog.c:909
volatile sig_atomic_t ConfigReloadPending
Definition: interrupt.c:26
static void apw_detach_shmem(int code, Datum arg)
Definition: autoprewarm.c:785
static void apw_load_buffers(void)
Definition: autoprewarm.c:272
struct Latch * MyLatch
Definition: globals.c:57
void procsignal_sigusr1_handler(SIGNAL_ARGS)
Definition: procsignal.c:642
#define WL_LATCH_SET
Definition: latch.h:125
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
Definition: timestamp.c:1693
#define WL_EXIT_ON_PM_DEATH
Definition: latch.h:130
#define InvalidPid
Definition: miscadmin.h:32
void BackgroundWorkerUnblockSignals(void)
Definition: postmaster.c:5737

◆ autoprewarm_start_worker()

Datum autoprewarm_start_worker ( PG_FUNCTION_ARGS  )

Definition at line 706 of file autoprewarm.c.

References apw_init_shmem(), apw_start_leader_worker(), autoprewarm, AutoPrewarmSharedState::bgworker_pid, ereport, errcode(), errmsg(), ERROR, InvalidPid, AutoPrewarmSharedState::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), and PG_RETURN_VOID.

707 {
708  pid_t pid;
709 
710  if (!autoprewarm)
711  ereport(ERROR,
712  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
713  errmsg("autoprewarm is disabled")));
714 
715  apw_init_shmem();
717  pid = apw_state->bgworker_pid;
719 
720  if (pid != InvalidPid)
721  ereport(ERROR,
722  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
723  errmsg("autoprewarm worker is already running under PID %lu",
724  (unsigned long) pid)));
725 
727 
728  PG_RETURN_VOID();
729 }
int errcode(int sqlerrcode)
Definition: elog.c:698
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
#define ERROR
Definition: elog.h:46
static AutoPrewarmSharedState * apw_state
Definition: autoprewarm.c:100
static void apw_start_leader_worker(void)
Definition: autoprewarm.c:799
static bool apw_init_shmem(void)
Definition: autoprewarm.c:759
#define ereport(elevel,...)
Definition: elog.h:157
#define PG_RETURN_VOID()
Definition: fmgr.h:349
static bool autoprewarm
Definition: autoprewarm.c:103
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define InvalidPid
Definition: miscadmin.h:32

◆ PG_FUNCTION_INFO_V1() [1/2]

PG_FUNCTION_INFO_V1 ( autoprewarm_start_worker  )

◆ PG_FUNCTION_INFO_V1() [2/2]

PG_FUNCTION_INFO_V1 ( autoprewarm_dump_now  )

Variable Documentation

◆ apw_state

AutoPrewarmSharedState* apw_state = NULL
static

Definition at line 100 of file autoprewarm.c.

◆ autoprewarm

bool autoprewarm = true
static

Definition at line 103 of file autoprewarm.c.

Referenced by _PG_init(), and autoprewarm_start_worker().

◆ autoprewarm_interval

int autoprewarm_interval
static

Definition at line 104 of file autoprewarm.c.

Referenced by _PG_init(), and autoprewarm_main().