Fix check_agg_arguments' examination of aggregate FILTER clauses.
[pgsql.git] / contrib / pg_prewarm / pg_prewarm.c
blob00438239749287f601e40f53cb80d020ae4badcf
1 /*-------------------------------------------------------------------------
3 * pg_prewarm.c
4 * prewarming utilities
6 * Copyright (c) 2010-2021, PostgreSQL Global Development Group
8 * IDENTIFICATION
9 * contrib/pg_prewarm/pg_prewarm.c
11 *-------------------------------------------------------------------------
13 #include "postgres.h"
15 #include <sys/stat.h>
16 #include <unistd.h>
18 #include "access/relation.h"
19 #include "fmgr.h"
20 #include "miscadmin.h"
21 #include "storage/bufmgr.h"
22 #include "storage/smgr.h"
23 #include "utils/acl.h"
24 #include "utils/builtins.h"
25 #include "utils/lsyscache.h"
26 #include "utils/rel.h"
28 PG_MODULE_MAGIC;
30 PG_FUNCTION_INFO_V1(pg_prewarm);
32 typedef enum
34 PREWARM_PREFETCH,
35 PREWARM_READ,
36 PREWARM_BUFFER
37 } PrewarmType;
39 static PGAlignedBlock blockbuffer;
42 * pg_prewarm(regclass, mode text, fork text,
43 * first_block int8, last_block int8)
45 * The first argument is the relation to be prewarmed; the second controls
46 * how prewarming is done; legal options are 'prefetch', 'read', and 'buffer'.
47 * The third is the name of the relation fork to be prewarmed. The fourth
48 * and fifth arguments specify the first and last block to be prewarmed.
49 * If the fourth argument is NULL, it will be taken as 0; if the fifth argument
50 * is NULL, it will be taken as the number of blocks in the relation. The
51 * return value is the number of blocks successfully prewarmed.
53 Datum
54 pg_prewarm(PG_FUNCTION_ARGS)
56 Oid relOid;
57 text *forkName;
58 text *type;
59 int64 first_block;
60 int64 last_block;
61 int64 nblocks;
62 int64 blocks_done = 0;
63 int64 block;
64 Relation rel;
65 ForkNumber forkNumber;
66 char *forkString;
67 char *ttype;
68 PrewarmType ptype;
69 AclResult aclresult;
71 /* Basic sanity checking. */
72 if (PG_ARGISNULL(0))
73 ereport(ERROR,
74 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
75 errmsg("relation cannot be null")));
76 relOid = PG_GETARG_OID(0);
77 if (PG_ARGISNULL(1))
78 ereport(ERROR,
79 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
80 errmsg("prewarm type cannot be null")));
81 type = PG_GETARG_TEXT_PP(1);
82 ttype = text_to_cstring(type);
83 if (strcmp(ttype, "prefetch") == 0)
84 ptype = PREWARM_PREFETCH;
85 else if (strcmp(ttype, "read") == 0)
86 ptype = PREWARM_READ;
87 else if (strcmp(ttype, "buffer") == 0)
88 ptype = PREWARM_BUFFER;
89 else
91 ereport(ERROR,
92 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
93 errmsg("invalid prewarm type"),
94 errhint("Valid prewarm types are \"prefetch\", \"read\", and \"buffer\".")));
95 PG_RETURN_INT64(0); /* Placate compiler. */
97 if (PG_ARGISNULL(2))
98 ereport(ERROR,
99 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
100 errmsg("relation fork cannot be null")));
101 forkName = PG_GETARG_TEXT_PP(2);
102 forkString = text_to_cstring(forkName);
103 forkNumber = forkname_to_number(forkString);
105 /* Open relation and check privileges. */
106 rel = relation_open(relOid, AccessShareLock);
107 aclresult = pg_class_aclcheck(relOid, GetUserId(), ACL_SELECT);
108 if (aclresult != ACLCHECK_OK)
109 aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind), get_rel_name(relOid));
111 /* Check that the fork exists. */
112 if (!smgrexists(RelationGetSmgr(rel), forkNumber))
113 ereport(ERROR,
114 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
115 errmsg("fork \"%s\" does not exist for this relation",
116 forkString)));
118 /* Validate block numbers, or handle nulls. */
119 nblocks = RelationGetNumberOfBlocksInFork(rel, forkNumber);
120 if (PG_ARGISNULL(3))
121 first_block = 0;
122 else
124 first_block = PG_GETARG_INT64(3);
125 if (first_block < 0 || first_block >= nblocks)
126 ereport(ERROR,
127 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
128 errmsg("starting block number must be between 0 and %lld",
129 (long long) (nblocks - 1))));
131 if (PG_ARGISNULL(4))
132 last_block = nblocks - 1;
133 else
135 last_block = PG_GETARG_INT64(4);
136 if (last_block < 0 || last_block >= nblocks)
137 ereport(ERROR,
138 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
139 errmsg("ending block number must be between 0 and %lld",
140 (long long) (nblocks - 1))));
143 /* Now we're ready to do the real work. */
144 if (ptype == PREWARM_PREFETCH)
146 #ifdef USE_PREFETCH
149 * In prefetch mode, we just hint the OS to read the blocks, but we
150 * don't know whether it really does it, and we don't wait for it to
151 * finish.
153 * It would probably be better to pass our prefetch requests in chunks
154 * of a megabyte or maybe even a whole segment at a time, but there's
155 * no practical way to do that at present without a gross modularity
156 * violation, so we just do this.
158 for (block = first_block; block <= last_block; ++block)
160 CHECK_FOR_INTERRUPTS();
161 PrefetchBuffer(rel, forkNumber, block);
162 ++blocks_done;
164 #else
165 ereport(ERROR,
166 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
167 errmsg("prefetch is not supported by this build")));
168 #endif
170 else if (ptype == PREWARM_READ)
173 * In read mode, we actually read the blocks, but not into shared
174 * buffers. This is more portable than prefetch mode (it works
175 * everywhere) and is synchronous.
177 for (block = first_block; block <= last_block; ++block)
179 CHECK_FOR_INTERRUPTS();
180 smgrread(RelationGetSmgr(rel), forkNumber, block, blockbuffer.data);
181 ++blocks_done;
184 else if (ptype == PREWARM_BUFFER)
187 * In buffer mode, we actually pull the data into shared_buffers.
189 for (block = first_block; block <= last_block; ++block)
191 Buffer buf;
193 CHECK_FOR_INTERRUPTS();
194 buf = ReadBufferExtended(rel, forkNumber, block, RBM_NORMAL, NULL);
195 ReleaseBuffer(buf);
196 ++blocks_done;
200 /* Close relation, release lock. */
201 relation_close(rel, AccessShareLock);
203 PG_RETURN_INT64(blocks_done);