52#define AUTOPREWARM_FILE "autoprewarm.blocks"
108static int apw_dump_now(
bool is_bgworker,
bool dump_unlogged);
129 "Sets the interval between dumps of shared buffers",
130 "If set to zero, time-based dumping is disabled.",
145 "Starts the autoprewarm worker.",
169 bool first_time =
true;
170 bool final_dump_allowed =
true;
201 (
errmsg(
"autoprewarm worker is already running under PID %d",
261 if (delay_in_ms <= 0)
283 if (final_dump_allowed)
311 (
errmsg(
"skipping prewarm because block dump file is being written by PID %d",
333 errmsg(
"could not read file \"%s\": %m",
338 if (fscanf(file,
"<<%d>>\n", &num_elements) != 1)
341 errmsg(
"could not read from file \"%s\": %m",
349 for (
i = 0;
i < num_elements;
i++)
353 if (fscanf(file,
"%u,%u,%u,%u,%u\n", &blkinfo[
i].database,
355 &forknum, &blkinfo[
i].blocknum) != 5)
357 (
errmsg(
"autoprewarm block dump file is corrupted at line %d",
378 (
errmsg(
"autoprewarm capping prewarmed blocks to %d (shared_buffers size)",
393 while (
j < num_elements)
395 if (current_db != blkinfo[
j].database)
449 (
errmsg(
"autoprewarm successfully prewarmed %d of %d previously-loaded blocks",
459 void *callback_private_data,
460 void *per_buffer_data)
516 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
517 errmsg(
"could not map dynamic shared memory segment")));
528 while (i < apw_state->prewarm_stop_idx)
574 while (i < apw_state->prewarm_stop_idx &&
672 char transient_dump_file_path[
MAXPGPATH];
685 (
errmsg(
"could not perform block dump because dump file is being used by PID %d",
689 (
errmsg(
"skipping block dump because it is already being performed by PID %d",
727 block_info_array[num_blocks].
forknum =
741 errmsg(
"could not open file \"%s\": %m",
742 transient_dump_file_path)));
744 ret =
fprintf(file,
"<<%d>>\n", num_blocks);
747 int save_errno = errno;
750 unlink(transient_dump_file_path);
754 errmsg(
"could not write to file \"%s\": %m",
755 transient_dump_file_path)));
758 for (
i = 0;
i < num_blocks;
i++)
762 ret =
fprintf(file,
"%u,%u,%u,%u,%u\n",
763 block_info_array[
i].database,
765 block_info_array[
i].filenumber,
766 (
uint32) block_info_array[
i].forknum,
767 block_info_array[
i].blocknum);
770 int save_errno = errno;
773 unlink(transient_dump_file_path);
777 errmsg(
"could not write to file \"%s\": %m",
778 transient_dump_file_path)));
782 pfree(block_info_array);
791 int save_errno = errno;
793 unlink(transient_dump_file_path);
797 errmsg(
"could not close file \"%s\": %m",
798 transient_dump_file_path)));
819 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
820 errmsg(
"autoprewarm is disabled")));
829 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
830 errmsg(
"autoprewarm worker is already running under PID %d",
917 strcpy(worker.
bgw_name,
"autoprewarm leader");
918 strcpy(worker.
bgw_type,
"autoprewarm leader");
931 (
errcode(ERRCODE_INSUFFICIENT_RESOURCES),
932 errmsg(
"could not register background process"),
933 errhint(
"You may need to increase \"max_worker_processes\".")));
938 (
errcode(ERRCODE_INSUFFICIENT_RESOURCES),
939 errmsg(
"could not start background process"),
940 errhint(
"More details may be available in the server log.")));
958 strcpy(worker.
bgw_name,
"autoprewarm worker");
959 strcpy(worker.
bgw_type,
"autoprewarm worker");
966 (
errcode(ERRCODE_INSUFFICIENT_RESOURCES),
967 errmsg(
"registering dynamic bgworker autoprewarm failed"),
968 errhint(
"Consider increasing the configuration parameter \"%s\".",
"max_worker_processes")));
978#define cmp_member_elem(fld) \
980 if (a->fld < b->fld) \
982 else if (a->fld > b->fld) \
static int apw_compare_blockinfo(const void *p, const void *q)
Datum autoprewarm_start_worker(PG_FUNCTION_ARGS)
static AutoPrewarmSharedState * apw_state
static void apw_detach_shmem(int code, Datum arg)
PGDLLEXPORT void autoprewarm_main(Datum main_arg)
#define cmp_member_elem(fld)
static bool apw_init_shmem(void)
static void apw_start_leader_worker(void)
PGDLLEXPORT void autoprewarm_database_main(Datum main_arg)
struct AutoPrewarmReadStreamData AutoPrewarmReadStreamData
static void apw_start_database_worker(void)
static void apw_load_buffers(void)
static void apw_init_state(void *ptr)
Datum autoprewarm_dump_now(PG_FUNCTION_ARGS)
static BlockNumber apw_read_stream_next_block(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
static int autoprewarm_interval
static int apw_dump_now(bool is_bgworker, bool dump_unlogged)
struct AutoPrewarmSharedState AutoPrewarmSharedState
PG_FUNCTION_INFO_V1(autoprewarm_start_worker)
struct BlockInfoRecord BlockInfoRecord
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
TimestampTz GetCurrentTimestamp(void)
void RegisterBackgroundWorker(BackgroundWorker *worker)
BgwHandleStatus WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp)
BgwHandleStatus WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle)
void BackgroundWorkerUnblockSignals(void)
void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags)
bool RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle)
#define BGW_NEVER_RESTART
@ BgWorkerStart_ConsistentState
#define BGWORKER_BACKEND_DATABASE_CONNECTION
#define BGWORKER_SHMEM_ACCESS
#define InvalidBlockNumber
static ForkNumber BufTagGetForkNum(const BufferTag *tag)
static void UnlockBufHdr(BufferDesc *desc, uint32 buf_state)
static RelFileNumber BufTagGetRelNumber(const BufferTag *tag)
static BufferDesc * GetBufferDescriptor(uint32 id)
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
void ReleaseBuffer(Buffer buffer)
uint32 LockBufHdr(BufferDesc *desc)
#define OidIsValid(objectId)
#define fprintf(file, fmt, msg)
dsm_handle dsm_segment_handle(dsm_segment *seg)
void dsm_detach(dsm_segment *seg)
void * dsm_segment_address(dsm_segment *seg)
dsm_segment * dsm_create(Size size, int flags)
dsm_segment * dsm_attach(dsm_handle h)
#define DSM_HANDLE_INVALID
void * GetNamedDSMSegment(const char *name, size_t size, void(*init_callback)(void *ptr), bool *found)
int errmsg_internal(const char *fmt,...)
int errcode_for_file_access(void)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
int durable_rename(const char *oldfile, const char *newfile, int elevel)
FILE * AllocateFile(const char *name, const char *mode)
#define PG_RETURN_INT64(x)
void ProcessConfigFile(GucContext context)
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)
void MarkGUCPrefixReserved(const char *className)
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)
Assert(PointerIsAligned(start, uint64))
void SignalHandlerForShutdownRequest(SIGNAL_ARGS)
volatile sig_atomic_t ShutdownRequestPending
volatile sig_atomic_t ConfigReloadPending
void SignalHandlerForConfigReload(SIGNAL_ARGS)
void before_shmem_exit(pg_on_exit_callback function, Datum arg)
#define PG_ENSURE_ERROR_CLEANUP(cleanup_function, arg)
#define PG_END_ENSURE_ERROR_CLEANUP(cleanup_function, arg)
void ResetLatch(Latch *latch)
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
int LWLockNewTrancheId(const char *name)
void LWLockRelease(LWLock *lock)
void LWLockInitialize(LWLock *lock, int tranche_id)
void pfree(void *pointer)
void * palloc_extended(Size size, int flags)
#define CHECK_FOR_INTERRUPTS()
bool process_shared_preload_libraries_in_progress
#define qsort(a, b, c, d)
void procsignal_sigusr1_handler(SIGNAL_ARGS)
Buffer read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
ReadStream * read_stream_begin_relation(int flags, BufferAccessStrategy strategy, Relation rel, ForkNumber forknum, ReadStreamBlockNumberCB callback, void *callback_private_data, size_t per_buffer_data_size)
void read_stream_end(ReadStream *stream)
#define READ_STREAM_MAINTENANCE
#define READ_STREAM_USE_BATCHING
#define READ_STREAM_DEFAULT
static SMgrRelation RelationGetSmgr(Relation rel)
Oid RelidByRelfilenumber(Oid reltablespace, RelFileNumber relfilenumber)
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
void relation_close(Relation relation, LOCKMODE lockmode)
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
BlockInfoRecord * block_info
dsm_handle block_info_handle
char bgw_function_name[BGW_MAXLEN]
char bgw_name[BGW_MAXLEN]
char bgw_type[BGW_MAXLEN]
BgWorkerStartTime bgw_start_time
char bgw_library_name[MAXPGPATH]
#define TimestampTzPlusMilliseconds(tz, ms)
#define PG_WAIT_EXTENSION
#define WL_EXIT_ON_PM_DEATH
void StartTransactionCommand(void)
void CommitTransactionCommand(void)