PostgreSQL Source Code git master
Loading...
Searching...
No Matches
wait.c File Reference
#include "postgres.h"
#include <math.h>
#include "access/xlog.h"
#include "access/xlogrecovery.h"
#include "access/xlogwait.h"
#include "catalog/pg_type_d.h"
#include "commands/defrem.h"
#include "commands/wait.h"
#include "executor/executor.h"
#include "parser/parse_node.h"
#include "storage/proc.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/pg_lsn.h"
#include "utils/snapmgr.h"
Include dependency graph for wait.c:

Go to the source code of this file.

Functions

void ExecWaitStmt (ParseState *pstate, WaitStmt *stmt, bool isTopLevel, DestReceiver *dest)
 
TupleDesc WaitStmtResultDesc (WaitStmt *stmt)
 

Function Documentation

◆ ExecWaitStmt()

void ExecWaitStmt ( ParseState pstate,
WaitStmt stmt,
bool  isTopLevel,
DestReceiver dest 
)

Definition at line 34 of file wait.c.

36{
37 XLogRecPtr lsn;
38 int64 timeout = 0;
40 WaitLSNType lsnType = WAIT_LSN_TYPE_STANDBY_REPLAY; /* default */
41 bool throw = true;
42 TupleDesc tupdesc;
44 const char *result = "<unset>";
45 bool timeout_specified = false;
46 bool no_throw_specified = false;
47 bool mode_specified = false;
48
49 /*
50 * WAIT FOR must not be run as a non-top-level statement (e.g., inside a
51 * function, procedure, or DO block). Forbid this case upfront.
52 */
53 if (!isTopLevel)
56 errmsg("%s can only be executed as a top-level statement",
57 "WAIT FOR"),
58 errdetail("WAIT FOR cannot be used within a function, procedure, or DO block.")));
59
60 /* Parse and validate the mandatory LSN */
62 CStringGetDatum(stmt->lsn_literal)));
63
64 foreach_node(DefElem, defel, stmt->options)
65 {
66 if (strcmp(defel->defname, "mode") == 0)
67 {
68 char *mode_str;
69
72 mode_specified = true;
73
75
76 if (pg_strcasecmp(mode_str, "standby_replay") == 0)
78 else if (pg_strcasecmp(mode_str, "standby_write") == 0)
80 else if (pg_strcasecmp(mode_str, "standby_flush") == 0)
82 else if (pg_strcasecmp(mode_str, "primary_flush") == 0)
84 else
87 errmsg("unrecognized value for %s option \"%s\": \"%s\"",
88 "WAIT", defel->defname, mode_str),
89 parser_errposition(pstate, defel->location)));
90 }
91 else if (strcmp(defel->defname, "timeout") == 0)
92 {
93 char *timeout_str;
94 const char *hintmsg;
95 double dval;
96
99 timeout_specified = true;
100
102
104 {
107 errmsg("invalid timeout value: \"%s\"", timeout_str),
108 hintmsg ? errhint("%s", _(hintmsg)) : 0);
109 }
110
111 /*
112 * Get rid of any fractional part in the input. This is so we
113 * don't fail on just-out-of-range values that would round into
114 * range.
115 */
116 dval = rint(dval);
117
118 /* Range check */
119 if (unlikely(isnan(dval) || !FLOAT8_FITS_IN_INT64(dval)))
122 errmsg("timeout value is out of range"));
123
124 if (dval < 0)
127 errmsg("timeout cannot be negative"));
128
129 timeout = (int64) dval;
130 }
131 else if (strcmp(defel->defname, "no_throw") == 0)
132 {
135
136 no_throw_specified = true;
137
138 throw = !defGetBoolean(defel);
139 }
140 else
141 {
144 errmsg("option \"%s\" not recognized",
145 defel->defname),
146 parser_errposition(pstate, defel->location));
147 }
148 }
149
150 /*
151 * We are going to wait for the LSN. We should first care that we don't
152 * hold a snapshot and correspondingly our MyProc->xmin is invalid.
153 * Otherwise, our snapshot could prevent the replay of WAL records
154 * implying a kind of self-deadlock. This is the reason why WAIT FOR is a
155 * command, not a procedure or function.
156 *
157 * Non-top-level contexts are rejected above, but be defensive and pop any
158 * active snapshot if one is present. PortalRunUtility() can tolerate
159 * utility commands that remove the active snapshot.
160 */
161 if (ActiveSnapshotSet())
163
164 /*
165 * At second, invalidate a catalog snapshot if any. And we should be done
166 * with the preparation.
167 */
169
170 /* Give up if there is still an active or registered snapshot. */
174 errmsg("WAIT FOR must be called without an active or registered snapshot"),
175 errdetail("WAIT FOR cannot be executed within a transaction with an isolation level higher than READ COMMITTED."));
176
177 /*
178 * As the result we should hold no snapshot, and correspondingly our xmin
179 * should be unset.
180 */
182
183 /*
184 * Validate that the requested mode matches the current server state.
185 * Primary modes can only be used on a primary.
186 */
187 if (lsnType == WAIT_LSN_TYPE_PRIMARY_FLUSH)
188 {
189 if (RecoveryInProgress())
192 errmsg("recovery is in progress"),
193 errhint("Waiting for primary_flush can only be done on a primary server. "
194 "Use standby_flush mode on a standby server.")));
195 }
196
197 /* Now wait for the LSN */
198 waitLSNResult = WaitForLSN(lsnType, lsn, timeout);
199
200 /*
201 * Process the result of WaitForLSN(). Throw appropriate error if needed.
202 */
203 switch (waitLSNResult)
204 {
206 /* Nothing to do on success */
207 result = "success";
208 break;
209
211 if (throw)
212 {
214
215 switch (lsnType)
216 {
220 errmsg("timed out while waiting for target LSN %X/%08X to be replayed; current standby_replay LSN %X/%08X",
221 LSN_FORMAT_ARGS(lsn),
223 break;
224
228 errmsg("timed out while waiting for target LSN %X/%08X to be written; current standby_write LSN %X/%08X",
229 LSN_FORMAT_ARGS(lsn),
231 break;
232
236 errmsg("timed out while waiting for target LSN %X/%08X to be flushed; current standby_flush LSN %X/%08X",
237 LSN_FORMAT_ARGS(lsn),
239 break;
240
244 errmsg("timed out while waiting for target LSN %X/%08X to be flushed; current primary_flush LSN %X/%08X",
245 LSN_FORMAT_ARGS(lsn),
247 break;
248
249 default:
250 elog(ERROR, "unexpected wait LSN type %d", lsnType);
251 }
252 }
253 else
254 result = "timeout";
255 break;
256
258 if (throw)
259 {
260 if (PromoteIsTriggered())
261 {
263
264 switch (lsnType)
265 {
269 errmsg("recovery is not in progress"),
270 errdetail("Recovery ended before target LSN %X/%08X was replayed; last standby_replay LSN %X/%08X.",
271 LSN_FORMAT_ARGS(lsn),
273 break;
274
278 errmsg("recovery is not in progress"),
279 errdetail("Recovery ended before target LSN %X/%08X was written; last standby_write LSN %X/%08X.",
280 LSN_FORMAT_ARGS(lsn),
282 break;
283
287 errmsg("recovery is not in progress"),
288 errdetail("Recovery ended before target LSN %X/%08X was flushed; last standby_flush LSN %X/%08X.",
289 LSN_FORMAT_ARGS(lsn),
291 break;
292
293 default:
294 elog(ERROR, "unexpected wait LSN type %d", lsnType);
295 }
296 }
297 else
298 {
299 switch (lsnType)
300 {
304 errmsg("recovery is not in progress"),
305 errhint("Waiting for the standby_replay LSN can only be executed during recovery."));
306 break;
307
311 errmsg("recovery is not in progress"),
312 errhint("Waiting for the standby_write LSN can only be executed during recovery."));
313 break;
314
318 errmsg("recovery is not in progress"),
319 errhint("Waiting for the standby_flush LSN can only be executed during recovery."));
320 break;
321
322 default:
323 elog(ERROR, "unexpected wait LSN type %d", lsnType);
324 }
325 }
326 }
327 else
328 result = "not in recovery";
329 break;
330 }
331
332 /* need a tuple descriptor representing a single TEXT column */
333 tupdesc = WaitStmtResultDesc(stmt);
334
335 /* prepare for projection of tuples */
337
338 /* Send it */
340
342}
#define Assert(condition)
Definition c.h:943
int64_t int64
Definition c.h:621
#define FLOAT8_FITS_IN_INT64(num)
Definition c.h:1179
#define unlikely(x)
Definition c.h:438
uint32 result
char * defGetString(DefElem *def)
Definition define.c:34
bool defGetBoolean(DefElem *def)
Definition define.c:93
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition define.c:370
int errcode(int sqlerrcode)
Definition elog.c:875
#define _(x)
Definition elog.c:96
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
const TupleTableSlotOps TTSOpsVirtual
Definition execTuples.c:84
void end_tup_output(TupOutputState *tstate)
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
#define do_text_output_oneline(tstate, str_to_emit)
Definition executor.h:639
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:684
bool parse_real(const char *value, double *result, int flags, const char **hintmsg)
Definition guc.c:2865
#define GUC_UNIT_MS
Definition guc.h:239
#define stmt
static char * errmsg
int parser_errposition(ParseState *pstate, int location)
Definition parse_node.c:106
#define foreach_node(type, var, lst)
Definition pg_list.h:528
Datum pg_lsn_in(PG_FUNCTION_ARGS)
Definition pg_lsn.c:64
static XLogRecPtr DatumGetLSN(Datum X)
Definition pg_lsn.h:25
int pg_strcasecmp(const char *s1, const char *s2)
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
static int fb(int x)
bool ActiveSnapshotSet(void)
Definition snapmgr.c:812
bool HaveRegisteredOrActiveSnapshot(void)
Definition snapmgr.c:1644
void PopActiveSnapshot(void)
Definition snapmgr.c:775
void InvalidateCatalogSnapshot(void)
Definition snapmgr.c:455
PGPROC * MyProc
Definition proc.c:71
TransactionId xmin
Definition proc.h:242
#define InvalidTransactionId
Definition transam.h:31
TupleDesc WaitStmtResultDesc(WaitStmt *stmt)
Definition wait.c:345
bool RecoveryInProgress(void)
Definition xlog.c:6836
#define LSN_FORMAT_ARGS(lsn)
Definition xlogdefs.h:47
uint64 XLogRecPtr
Definition xlogdefs.h:21
bool PromoteIsTriggered(void)
XLogRecPtr GetCurrentLSNForWaitType(WaitLSNType lsnType)
Definition xlogwait.c:98
WaitLSNResult WaitForLSN(WaitLSNType lsnType, XLogRecPtr targetLSN, int64 timeout)
Definition xlogwait.c:378
WaitLSNResult
Definition xlogwait.h:26
@ WAIT_LSN_RESULT_NOT_IN_RECOVERY
Definition xlogwait.h:28
@ WAIT_LSN_RESULT_TIMEOUT
Definition xlogwait.h:30
@ WAIT_LSN_RESULT_SUCCESS
Definition xlogwait.h:27
WaitLSNType
Definition xlogwait.h:37
@ WAIT_LSN_TYPE_PRIMARY_FLUSH
Definition xlogwait.h:44
@ WAIT_LSN_TYPE_STANDBY_REPLAY
Definition xlogwait.h:39
@ WAIT_LSN_TYPE_STANDBY_FLUSH
Definition xlogwait.h:41
@ WAIT_LSN_TYPE_STANDBY_WRITE
Definition xlogwait.h:40

References _, ActiveSnapshotSet(), Assert, begin_tup_output_tupdesc(), CStringGetDatum(), DatumGetLSN(), defGetBoolean(), defGetString(), DirectFunctionCall1, do_text_output_oneline, elog, end_tup_output(), ereport, errcode(), errdetail(), errhint(), errmsg, ERROR, errorConflictingDefElem(), fb(), FLOAT8_FITS_IN_INT64, foreach_node, GetCurrentLSNForWaitType(), GUC_UNIT_MS, HaveRegisteredOrActiveSnapshot(), InvalidateCatalogSnapshot(), InvalidTransactionId, LSN_FORMAT_ARGS, MyProc, parse_real(), parser_errposition(), pg_lsn_in(), pg_strcasecmp(), PopActiveSnapshot(), PromoteIsTriggered(), RecoveryInProgress(), result, stmt, TTSOpsVirtual, unlikely, WAIT_LSN_RESULT_NOT_IN_RECOVERY, WAIT_LSN_RESULT_SUCCESS, WAIT_LSN_RESULT_TIMEOUT, WAIT_LSN_TYPE_PRIMARY_FLUSH, WAIT_LSN_TYPE_STANDBY_FLUSH, WAIT_LSN_TYPE_STANDBY_REPLAY, WAIT_LSN_TYPE_STANDBY_WRITE, WaitForLSN(), WaitStmtResultDesc(), and PGPROC::xmin.

Referenced by standard_ProcessUtility().

◆ WaitStmtResultDesc()

TupleDesc WaitStmtResultDesc ( WaitStmt stmt)

Definition at line 345 of file wait.c.

346{
347 TupleDesc tupdesc;
348
349 /*
350 * Need a tuple descriptor representing a single TEXT column.
351 *
352 * We use TupleDescInitBuiltinEntry instead of TupleDescInitEntry to avoid
353 * syscache access. This is important because WaitStmtResultDesc may be
354 * called after snapshots have been released, and we must not re-establish
355 * a catalog snapshot which could cause recovery conflicts on a standby.
356 */
357 tupdesc = CreateTemplateTupleDesc(1);
358 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "status",
359 TEXTOID, -1, 0);
360 TupleDescFinalize(tupdesc);
361 return tupdesc;
362}
int16 AttrNumber
Definition attnum.h:21
TupleDesc CreateTemplateTupleDesc(int natts)
Definition tupdesc.c:165
void TupleDescFinalize(TupleDesc tupdesc)
Definition tupdesc.c:511
void TupleDescInitBuiltinEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition tupdesc.c:976

References CreateTemplateTupleDesc(), fb(), TupleDescFinalize(), and TupleDescInitBuiltinEntry().

Referenced by ExecWaitStmt(), and UtilityTupleDescriptor().