1/*-------------------------------------------------------------------------
6 * Copyright (c) 2010-2025, PostgreSQL Global Development Group
9 * contrib/pg_prewarm/pg_prewarm.c
11 *-------------------------------------------------------------------------
46 * pg_prewarm(regclass, mode text, fork text,
47 * first_block int8, last_block int8)
49 * The first argument is the relation to be prewarmed; the second controls
50 * how prewarming is done; legal options are 'prefetch', 'read', and 'buffer'.
51 * The third is the name of the relation fork to be prewarmed. The fourth
52 * and fifth arguments specify the first and last block to be prewarmed.
53 * If the fourth argument is NULL, it will be taken as 0; if the fifth argument
54 * is NULL, it will be taken as the number of blocks in the relation. The
55 * return value is the number of blocks successfully prewarmed.
66 int64 blocks_done = 0;
75 /* Basic sanity checking. */
78 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
79 errmsg(
"relation cannot be null")));
83 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
84 errmsg(
"prewarm type cannot be null")));
87 if (strcmp(ttype,
"prefetch") == 0)
89 else if (strcmp(ttype,
"read") == 0)
91 else if (strcmp(ttype,
"buffer") == 0)
96 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
97 errmsg(
"invalid prewarm type"),
98 errhint(
"Valid prewarm types are \"prefetch\", \"read\", and \"buffer\".")));
103 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
104 errmsg(
"relation fork cannot be null")));
109 /* Open relation and check privileges. */
115 /* Check that the relation has storage. */
116 if (!RELKIND_HAS_STORAGE(rel->
rd_rel->relkind))
118 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
119 errmsg(
"relation \"%s\" does not have storage",
123 /* Check that the fork exists. */
126 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
127 errmsg(
"fork \"%s\" does not exist for this relation",
130 /* Validate block numbers, or handle nulls. */
137 if (first_block < 0 || first_block >= nblocks)
139 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
140 errmsg(
"starting block number must be between 0 and %" PRId64,
144 last_block = nblocks - 1;
148 if (last_block < 0 || last_block >= nblocks)
150 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
151 errmsg(
"ending block number must be between 0 and %" PRId64,
155 /* Now we're ready to do the real work. */
161 * In prefetch mode, we just hint the OS to read the blocks, but we
162 * don't know whether it really does it, and we don't wait for it to
165 * It would probably be better to pass our prefetch requests in chunks
166 * of a megabyte or maybe even a whole segment at a time, but there's
167 * no practical way to do that at present without a gross modularity
168 * violation, so we just do this.
170 for (block = first_block; block <= last_block; ++block)
178 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
179 errmsg(
"prefetch is not supported by this build")));
185 * In read mode, we actually read the blocks, but not into shared
186 * buffers. This is more portable than prefetch mode (it works
187 * everywhere) and is synchronous.
189 for (block = first_block; block <= last_block; ++block)
202 * In buffer mode, we actually pull the data into shared_buffers.
205 /* Set up the private state for our streaming buffer read callback. */
210 * It is safe to use batchmode as block_range_read_stream_cb takes no
223 for (block = first_block; block <= last_block; ++block)
236 /* Close relation, release lock. */
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
PrefetchBufferResult PrefetchBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
void ReleaseBuffer(Buffer buffer)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define PG_GETARG_TEXT_PP(n)
#define PG_RETURN_INT64(x)
#define PG_GETARG_INT64(n)
Assert(PointerIsAligned(start, uint64))
char * get_rel_name(Oid relid)
#define CHECK_FOR_INTERRUPTS()
ObjectType get_relkind_objtype(char relkind)
int errdetail_relkind_not_supported(char relkind)
PG_FUNCTION_INFO_V1(pg_prewarm)
PG_MODULE_MAGIC_EXT(.name="pg_prewarm",.version=PG_VERSION)
static PGIOAlignedBlock blockbuffer
Datum pg_prewarm(PG_FUNCTION_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)
BlockNumber block_range_read_stream_cb(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
#define READ_STREAM_MAINTENANCE
#define READ_STREAM_USE_BATCHING
static SMgrRelation RelationGetSmgr(Relation rel)
#define RelationGetRelationName(relation)
ForkNumber forkname_to_number(const char *forkName)
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
static void smgrread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, void *buffer)
void relation_close(Relation relation, LOCKMODE lockmode)
Relation relation_open(Oid relationId, LOCKMODE lockmode)
BlockNumber last_exclusive
BlockNumber current_blocknum
char * text_to_cstring(const text *t)