/* Metadata for each block we dump. */ typedefstruct BlockInfoRecord
{
Oid database;
Oid tablespace;
RelFileNumber filenumber;
ForkNumber forknum;
BlockNumber blocknum;
} BlockInfoRecord;
/* Shared state information for autoprewarm bgworker. */ typedefstruct AutoPrewarmSharedState
{
LWLock lock; /* mutual exclusion */
pid_t bgworker_pid; /* for main bgworker */
pid_t pid_using_dumpfile; /* for autoprewarm or block dump */
/* Following items are for communication with per-database worker */
dsm_handle block_info_handle;
Oid database; int prewarm_start_idx; int prewarm_stop_idx; int prewarmed_blocks;
} AutoPrewarmSharedState;
/* *PrivatedatapassedthroughthereadstreamAPIforouruseinthe *callback.
*/ typedefstruct AutoPrewarmReadStreamData
{ /* The array of records containing the blocks we should prewarm. */
BlockInfoRecord *block_info;
/* *posisthereadstreamcallback'sindexintoblock_info.Becausethe *readstreammayreadahead,posislikelytobeaheadoftheindexin *themainloopinautoprewarm_database_main().
*/ int pos;
Oid tablespace;
RelFileNumber filenumber;
ForkNumber forknum;
BlockNumber nblocks;
} AutoPrewarmReadStreamData;
/* Periodically dump buffers until terminated. */ while (!ShutdownRequestPending)
{ /* In case of a SIGHUP, just reload the configuration. */ if (ConfigReloadPending)
{
ConfigReloadPending = false;
ProcessConfigFile(PGC_SIGHUP);
}
if (autoprewarm_interval <= 0)
{ /* We're only dumping at shutdown, so just wait forever. */
(void) WaitLatch(MyLatch,
WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1L,
PG_WAIT_EXTENSION);
} else
{
TimestampTz next_dump_time; long delay_in_ms;
/* Compute the next dump time. */
next_dump_time =
TimestampTzPlusMilliseconds(last_dump_time,
autoprewarm_interval * 1000);
delay_in_ms =
TimestampDifferenceMilliseconds(GetCurrentTimestamp(),
next_dump_time);
/* Perform a dump if it's time. */ if (delay_in_ms <= 0)
{
last_dump_time = GetCurrentTimestamp();
apw_dump_now(true, false); continue;
}
/* Sleep until the next dump time. */
(void) WaitLatch(MyLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_in_ms,
PG_WAIT_EXTENSION);
}
/* Reset the latch, loop. */
ResetLatch(MyLatch);
}
/* *Dumponelasttime.Weassumethisisprobablytheresultofasystem *shutdown,althoughit'spossiblethatwe'vemerelybeenterminated.
*/ if (final_dump_allowed)
apw_dump_now(true, true);
}
/* *Skiptheprewarmifthedumpfileisinuse;otherwise,preventany *otherprocessfromwritingitwhilewe'reusingit.
*/
LWLockAcquire(&apw_state->lock, LW_EXCLUSIVE); if (apw_state->pid_using_dumpfile == InvalidPid)
apw_state->pid_using_dumpfile = MyProcPid; else
{
LWLockRelease(&apw_state->lock);
ereport(LOG,
(errmsg("skipping prewarm because block dump file is being written by PID %d",
(int) apw_state->pid_using_dumpfile))); return;
}
LWLockRelease(&apw_state->lock);
/* *Opentheblockdumpfile.Exitquietlyifitdoesn'texist,butreport *anyothererror.
*/
file = AllocateFile(AUTOPREWARM_FILE, "r"); if (!file)
{ if (errno == ENOENT)
{
LWLockAcquire(&apw_state->lock, LW_EXCLUSIVE);
apw_state->pid_using_dumpfile = InvalidPid;
LWLockRelease(&apw_state->lock); return; /* No file to load. */
}
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read file \"%s\": %m",
AUTOPREWARM_FILE)));
}
/* First line of the file is a record count. */ if (fscanf(file, "<<%d>>\n", &num_elements) != 1)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read from file \"%s\": %m",
AUTOPREWARM_FILE)));
/* Allocate a dynamic shared memory segment to store the record data. */
seg = dsm_create(sizeof(BlockInfoRecord) * num_elements, 0);
blkinfo = (BlockInfoRecord *) dsm_segment_address(seg);
/* Read records, one per line. */ for (i = 0; i < num_elements; i++)
{ unsigned forknum;
if (fscanf(file, "%u,%u,%u,%u,%u\n", &blkinfo[i].database,
&blkinfo[i].tablespace, &blkinfo[i].filenumber,
&forknum, &blkinfo[i].blocknum) != 5)
ereport(ERROR,
(errmsg("autoprewarm block dump file is corrupted at line %d",
i + 1)));
blkinfo[i].forknum = forknum;
}
FreeFile(file);
/* Sort the blocks to be loaded. */
qsort(blkinfo, num_elements, sizeof(BlockInfoRecord),
apw_compare_blockinfo);
/* Get the info position of the first block of the next database. */ while (apw_state->prewarm_start_idx < num_elements)
{ int j = apw_state->prewarm_start_idx;
Oid current_db = blkinfo[j].database;
/* *Advancetheprewarm_stop_idxtothefirstBlockInfoRecordthatdoes *notbelongtothisdatabase.
*/
j++; while (j < num_elements)
{ if (current_db != blkinfo[j].database)
{ /* *CombineBlockInfoRecordsforglobalobjectswiththoseof *thedatabase.
*/ if (current_db != InvalidOid) break;
current_db = blkinfo[j].database;
}
j++;
}
/* *Ifwereachthispointwithcurrent_db==InvalidOid,thenonly *BlockInfoRecordsbelongingtoglobalobjectsexist.Wecan't *prewarmwithoutadatabaseconnection,sojustbailout.
*/ if (current_db == InvalidOid) break;
/* Configure stop point and database for next per-database worker. */
apw_state->prewarm_stop_idx = j;
apw_state->database = current_db;
Assert(apw_state->prewarm_start_idx < apw_state->prewarm_stop_idx);
/* If we've run out of free buffers, don't launch another worker. */ if (!have_free_buffer()) break;
/* *Likewise,don'tlaunchifwe'vealreadybeentoldtoshutdown. *(Thelaunchwouldfailanyway,butwemightaswellskipit.)
*/ if (ShutdownRequestPending) break;
/* Report our success, if we were able to finish. */ if (!ShutdownRequestPending)
ereport(LOG,
(errmsg("autoprewarm successfully prewarmed %d of %d previously-loaded blocks",
apw_state->prewarmed_blocks, num_elements)));
}
reloid = RelidByRelfilenumber(blk.tablespace, blk.filenumber); if (!OidIsValid(reloid) ||
(rel = try_relation_open(reloid, AccessShareLock)) == NULL)
{ /* We failed to open the relation, so there is nothing to close. */
CommitTransactionCommand();
/* *Fast-forwardtothenextrelation.Wewanttoskipallofthe *otherrecordsreferencingthisrelationsinceweknowwecan't *openit.Thatway,weavoidrepeatedlytryingandfailingto *openthesamerelation.
*/ for (; i < apw_state->prewarm_stop_idx; i++)
{
blk = block_info[i]; if (blk.tablespace != tablespace ||
blk.filenumber != filenumber) break;
}
/* Time to try and open our newfound relation */ continue;
}
if (pid != InvalidPid)
{ if (!is_bgworker)
ereport(ERROR,
(errmsg("could not perform block dump because dump file is being used by PID %d",
(int) apw_state->pid_using_dumpfile)));
ereport(LOG,
(errmsg("skipping block dump because it is already being performed by PID %d",
(int) apw_state->pid_using_dumpfile))); return0;
}
if (process_shared_preload_libraries_in_progress)
{
RegisterBackgroundWorker(&worker); return;
}
/* must set notify PID to wait for startup */
worker.bgw_notify_pid = MyProcPid;
if (!RegisterDynamicBackgroundWorker(&worker, &handle))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
errmsg("could not register background process"),
errhint("You may need to increase \"max_worker_processes\".")));
status = WaitForBackgroundWorkerStartup(handle, &pid); if (status != BGWH_STARTED)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
errmsg("could not start background process"),
errhint("More details may be available in the server log.")));
}
/* Compare member elements to check whether they are not equal. */ #define cmp_member_elem(fld) \ do { \ if (a->fld < b->fld) \ return -1; \ elseif (a->fld > b->fld) \ return1; \
} while(0)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.