2011-11-04 10:37:17 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* xlogfuncs.c
|
|
|
|
*
|
2017-05-12 17:49:56 +02:00
|
|
|
* PostgreSQL write-ahead log manager user interface functions
|
2011-11-04 10:37:17 +01:00
|
|
|
*
|
|
|
|
* This file contains WAL control and information functions.
|
|
|
|
*
|
|
|
|
*
|
2022-01-08 01:04:57 +01:00
|
|
|
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
|
2011-11-04 10:37:17 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* src/backend/access/transam/xlogfuncs.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2018-10-25 02:46:00 +02:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
2011-11-04 10:37:17 +01:00
|
|
|
#include "access/xlog_internal.h"
|
2022-02-16 08:30:38 +01:00
|
|
|
#include "access/xlogrecovery.h"
|
2011-11-04 10:37:17 +01:00
|
|
|
#include "access/xlogutils.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "funcapi.h"
|
|
|
|
#include "miscadmin.h"
|
2018-10-25 02:46:00 +02:00
|
|
|
#include "pgstat.h"
|
2011-11-04 10:37:17 +01:00
|
|
|
#include "replication/walreceiver.h"
|
2019-11-12 04:00:16 +01:00
|
|
|
#include "storage/fd.h"
|
|
|
|
#include "storage/ipc.h"
|
2011-11-04 10:37:17 +01:00
|
|
|
#include "storage/smgr.h"
|
|
|
|
#include "utils/builtins.h"
|
2019-11-12 04:00:16 +01:00
|
|
|
#include "utils/guc.h"
|
2016-04-05 20:03:49 +02:00
|
|
|
#include "utils/memutils.h"
|
2012-03-04 12:15:24 +01:00
|
|
|
#include "utils/numeric.h"
|
2014-02-19 17:13:44 +01:00
|
|
|
#include "utils/pg_lsn.h"
|
2011-11-04 10:37:17 +01:00
|
|
|
#include "utils/timestamp.h"
|
2016-04-05 20:03:49 +02:00
|
|
|
#include "utils/tuplestore.h"
|
2012-03-04 12:24:09 +01:00
|
|
|
|
2016-04-05 20:03:49 +02:00
|
|
|
/*
|
2022-04-06 20:41:03 +02:00
|
|
|
* Store label file and tablespace map during backups.
|
2016-04-05 20:03:49 +02:00
|
|
|
*/
|
|
|
|
static StringInfo label_file;
|
|
|
|
static StringInfo tblspc_map_file;
|
|
|
|
|
2011-11-04 10:37:17 +01:00
|
|
|
/*
|
2022-04-06 20:41:03 +02:00
|
|
|
* pg_backup_start: set up for taking an on-line backup dump
|
2011-11-04 10:37:17 +01:00
|
|
|
*
|
|
|
|
* Essentially what this does is to create a backup label file in $PGDATA,
|
|
|
|
* where it will be archived as part of the backup dump. The label file
|
|
|
|
* contains the user-supplied label string (typically this would be used
|
|
|
|
* to tell where the backup dump will be stored) and the starting time and
|
|
|
|
* starting WAL location for the dump.
|
2016-04-07 03:45:32 +02:00
|
|
|
*
|
|
|
|
* Permission checking for this function is managed through the normal
|
|
|
|
* GRANT system.
|
2011-11-04 10:37:17 +01:00
|
|
|
*/
|
|
|
|
Datum
|
2022-04-06 20:41:03 +02:00
|
|
|
pg_backup_start(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
2017-03-13 00:35:34 +01:00
|
|
|
text *backupid = PG_GETARG_TEXT_PP(0);
|
2011-11-04 10:37:17 +01:00
|
|
|
bool fast = PG_GETARG_BOOL(1);
|
|
|
|
char *backupidstr;
|
|
|
|
XLogRecPtr startpoint;
|
2017-03-24 11:53:40 +01:00
|
|
|
SessionBackupState status = get_backup_status();
|
2022-04-06 20:41:03 +02:00
|
|
|
MemoryContext oldcontext;
|
2011-11-04 10:37:17 +01:00
|
|
|
|
|
|
|
backupidstr = text_to_cstring(backupid);
|
|
|
|
|
2022-04-06 20:41:03 +02:00
|
|
|
if (status == SESSION_BACKUP_RUNNING)
|
2016-04-05 20:03:49 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("a backup is already in progress in this session")));
|
|
|
|
|
2022-04-06 20:41:03 +02:00
|
|
|
/*
|
|
|
|
* Label file and tablespace map file need to be long-lived, since they
|
|
|
|
* are read in pg_backup_stop.
|
|
|
|
*/
|
|
|
|
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
|
|
|
label_file = makeStringInfo();
|
|
|
|
tblspc_map_file = makeStringInfo();
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2016-04-05 20:03:49 +02:00
|
|
|
|
2022-04-06 20:41:03 +02:00
|
|
|
register_persistent_abort_backup_handler();
|
Fix minor problems with non-exclusive backup cleanup.
The previous coding imagined that it could call before_shmem_exit()
when a non-exclusive backup began and then remove the previously-added
handler by calling cancel_before_shmem_exit() when that backup
ended. However, this only works provided that nothing else in the
system has registered a before_shmem_exit() hook in the interim,
because cancel_before_shmem_exit() is documented to remove a callback
only if it is the latest callback registered. It also only works
if nothing can ERROR out between the time that sessionBackupState
is reset and the time that cancel_before_shmem_exit(), which doesn't
seem to be strictly true.
To fix, leave the handler installed for the lifetime of the session,
arrange to install it just once, and teach it to quietly do nothing if
there isn't a non-exclusive backup in process.
This is a bug, but for now I'm not going to back-patch, because the
consequences are minor. It's possible to cause a spurious warning
to be generated, but that doesn't really matter. It's also possible
to trigger an assertion failure, but production builds shouldn't
have assertions enabled.
Patch by me, reviewed by Kyotaro Horiguchi, Michael Paquier (who
preferred a different approach, but got outvoted), Fujii Masao,
and Tom Lane, and with comments by various others.
Discussion: http://postgr.es/m/CA+TgmobMjnyBfNhGTKQEDbqXYE3_rXWpc4CM63fhyerNCes3mA@mail.gmail.com
2019-12-19 15:06:54 +01:00
|
|
|
|
2022-04-06 20:41:03 +02:00
|
|
|
startpoint = do_pg_backup_start(backupidstr, fast, NULL, label_file,
|
|
|
|
NULL, tblspc_map_file);
|
2015-05-12 15:29:10 +02:00
|
|
|
|
2014-02-19 17:13:44 +01:00
|
|
|
PG_RETURN_LSN(startpoint);
|
2011-11-04 10:37:17 +01:00
|
|
|
}
|
|
|
|
|
2016-04-05 20:03:49 +02:00
|
|
|
|
|
|
|
/*
|
2022-04-06 20:41:03 +02:00
|
|
|
* pg_backup_stop: finish taking an on-line backup.
|
2017-03-23 04:44:58 +01:00
|
|
|
*
|
2022-04-06 20:41:03 +02:00
|
|
|
* The first parameter (variable 'waitforarchive'), which is optional,
|
2017-03-23 04:44:58 +01:00
|
|
|
* allows the user to choose if they want to wait for the WAL to be archived
|
|
|
|
* or if we should just return as soon as the WAL record is written.
|
|
|
|
*
|
2016-04-07 03:45:32 +02:00
|
|
|
* Permission checking for this function is managed through the normal
|
|
|
|
* GRANT system.
|
2016-04-05 20:03:49 +02:00
|
|
|
*/
|
|
|
|
Datum
|
2022-04-06 20:41:03 +02:00
|
|
|
pg_backup_stop(PG_FUNCTION_ARGS)
|
2016-04-05 20:03:49 +02:00
|
|
|
{
|
2022-03-03 02:51:57 +01:00
|
|
|
#define PG_STOP_BACKUP_V2_COLS 3
|
2016-04-05 20:03:49 +02:00
|
|
|
TupleDesc tupdesc;
|
2022-07-16 08:42:15 +02:00
|
|
|
Datum values[PG_STOP_BACKUP_V2_COLS] = {0};
|
|
|
|
bool nulls[PG_STOP_BACKUP_V2_COLS] = {0};
|
2016-04-05 20:03:49 +02:00
|
|
|
|
2022-04-06 20:41:03 +02:00
|
|
|
bool waitforarchive = PG_GETARG_BOOL(0);
|
2016-04-05 20:03:49 +02:00
|
|
|
XLogRecPtr stoppoint;
|
2017-03-24 11:53:40 +01:00
|
|
|
SessionBackupState status = get_backup_status();
|
2016-04-05 20:03:49 +02:00
|
|
|
|
2022-03-03 02:51:57 +01:00
|
|
|
/* Initialize attributes information in the tuple descriptor */
|
2016-04-05 20:03:49 +02:00
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
|
2022-04-06 20:41:03 +02:00
|
|
|
if (status != SESSION_BACKUP_RUNNING)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("backup is not in progress"),
|
|
|
|
errhint("Did you call pg_backup_start()?")));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stop the backup. Return a copy of the backup label and tablespace map
|
|
|
|
* so they can be written to disk by the caller.
|
|
|
|
*/
|
|
|
|
stoppoint = do_pg_backup_stop(label_file->data, waitforarchive, NULL);
|
2016-04-05 20:03:49 +02:00
|
|
|
|
|
|
|
values[0] = LSNGetDatum(stoppoint);
|
2022-04-06 20:41:03 +02:00
|
|
|
values[1] = CStringGetTextDatum(label_file->data);
|
|
|
|
values[2] = CStringGetTextDatum(tblspc_map_file->data);
|
|
|
|
|
|
|
|
/* Free structures allocated in TopMemoryContext */
|
|
|
|
pfree(label_file->data);
|
|
|
|
pfree(label_file);
|
|
|
|
label_file = NULL;
|
|
|
|
pfree(tblspc_map_file->data);
|
|
|
|
pfree(tblspc_map_file);
|
|
|
|
tblspc_map_file = NULL;
|
2016-04-05 20:03:49 +02:00
|
|
|
|
2022-03-03 02:51:57 +01:00
|
|
|
/* Returns the record as Datum */
|
|
|
|
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
|
2016-04-05 20:03:49 +02:00
|
|
|
}
|
|
|
|
|
2011-11-04 10:37:17 +01:00
|
|
|
/*
|
2017-02-09 21:10:09 +01:00
|
|
|
* pg_switch_wal: switch to next xlog file
|
2016-04-07 03:45:32 +02:00
|
|
|
*
|
|
|
|
* Permission checking for this function is managed through the normal
|
|
|
|
* GRANT system.
|
2011-11-04 10:37:17 +01:00
|
|
|
*/
|
|
|
|
Datum
|
2017-02-09 21:10:09 +01:00
|
|
|
pg_switch_wal(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
|
|
|
XLogRecPtr switchpoint;
|
|
|
|
|
|
|
|
if (RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is in progress"),
|
|
|
|
errhint("WAL control functions cannot be executed during recovery.")));
|
|
|
|
|
Skip checkpoints, archiving on idle systems.
Some background activity (like checkpoints, archive timeout, standby
snapshots) is not supposed to happen on an idle system. Unfortunately
so far it was not easy to determine when a system is idle, which
defeated some of the attempts to avoid redundant activity on an idle
system.
To make that easier, allow to make individual WAL insertions as not
being "important". By checking whether any important activity happened
since the last time an activity was performed, it now is easy to check
whether some action needs to be repeated.
Use the new facility for checkpoints, archive timeout and standby
snapshots.
The lack of a facility causes some issues in older releases, but in my
opinion the consequences (superflous checkpoints / archived segments)
aren't grave enough to warrant backpatching.
Author: Michael Paquier, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Amit Kapila, Kyotaro HORIGUCHI
Bug: #13685
Discussion:
https://www.postgresql.org/message-id/20151016203031.3019.72930@wrigleys.postgresql.org
https://www.postgresql.org/message-id/CAB7nPqQcPqxEM3S735Bd2RzApNqSNJVietAC=6kfkYv_45dKwA@mail.gmail.com
Backpatch: -
2016-12-22 20:31:50 +01:00
|
|
|
switchpoint = RequestXLogSwitch(false);
|
2011-11-04 10:37:17 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* As a convenience, return the WAL location of the switch record
|
|
|
|
*/
|
2014-02-19 17:13:44 +01:00
|
|
|
PG_RETURN_LSN(switchpoint);
|
2011-11-04 10:37:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_create_restore_point: a named point for restore
|
2016-04-07 03:45:32 +02:00
|
|
|
*
|
|
|
|
* Permission checking for this function is managed through the normal
|
|
|
|
* GRANT system.
|
2011-11-04 10:37:17 +01:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_create_restore_point(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2017-03-13 00:35:34 +01:00
|
|
|
text *restore_name = PG_GETARG_TEXT_PP(0);
|
2011-11-04 10:37:17 +01:00
|
|
|
char *restore_name_str;
|
|
|
|
XLogRecPtr restorepoint;
|
|
|
|
|
|
|
|
if (RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
2020-01-30 17:32:04 +01:00
|
|
|
errmsg("recovery is in progress"),
|
|
|
|
errhint("WAL control functions cannot be executed during recovery.")));
|
2011-11-04 10:37:17 +01:00
|
|
|
|
|
|
|
if (!XLogIsNeeded())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("WAL level not sufficient for creating a restore point"),
|
2016-03-01 02:01:54 +01:00
|
|
|
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
|
2011-11-04 10:37:17 +01:00
|
|
|
|
|
|
|
restore_name_str = text_to_cstring(restore_name);
|
|
|
|
|
|
|
|
if (strlen(restore_name_str) >= MAXFNAMELEN)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("value too long for restore point (maximum %d characters)", MAXFNAMELEN - 1)));
|
|
|
|
|
|
|
|
restorepoint = XLogRestorePoint(restore_name_str);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As a convenience, return the WAL location of the restore point record
|
|
|
|
*/
|
2014-02-19 17:13:44 +01:00
|
|
|
PG_RETURN_LSN(restorepoint);
|
2011-11-04 10:37:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2022-04-06 20:41:03 +02:00
|
|
|
* Report the current WAL write location (same format as pg_backup_start etc)
|
2011-11-04 10:37:17 +01:00
|
|
|
*
|
|
|
|
* This is useful for determining how much of WAL is visible to an external
|
|
|
|
* archiving process. Note that the data before this point is written out
|
|
|
|
* to the kernel, but is not necessarily synced to disk.
|
|
|
|
*/
|
|
|
|
Datum
|
2017-05-11 17:49:59 +02:00
|
|
|
pg_current_wal_lsn(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
|
|
|
XLogRecPtr current_recptr;
|
|
|
|
|
|
|
|
if (RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is in progress"),
|
|
|
|
errhint("WAL control functions cannot be executed during recovery.")));
|
|
|
|
|
|
|
|
current_recptr = GetXLogWriteRecPtr();
|
|
|
|
|
2014-02-19 17:13:44 +01:00
|
|
|
PG_RETURN_LSN(current_recptr);
|
2011-11-04 10:37:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2022-04-06 20:41:03 +02:00
|
|
|
* Report the current WAL insert location (same format as pg_backup_start etc)
|
2011-11-04 10:37:17 +01:00
|
|
|
*
|
|
|
|
* This function is mostly for debugging purposes.
|
|
|
|
*/
|
|
|
|
Datum
|
2017-05-11 17:49:59 +02:00
|
|
|
pg_current_wal_insert_lsn(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
|
|
|
XLogRecPtr current_recptr;
|
|
|
|
|
|
|
|
if (RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is in progress"),
|
|
|
|
errhint("WAL control functions cannot be executed during recovery.")));
|
|
|
|
|
2012-01-11 10:00:53 +01:00
|
|
|
current_recptr = GetXLogInsertRecPtr();
|
2011-11-04 10:37:17 +01:00
|
|
|
|
2014-02-19 17:13:44 +01:00
|
|
|
PG_RETURN_LSN(current_recptr);
|
2011-11-04 10:37:17 +01:00
|
|
|
}
|
|
|
|
|
2016-01-12 08:54:52 +01:00
|
|
|
/*
|
2022-04-06 20:41:03 +02:00
|
|
|
* Report the current WAL flush location (same format as pg_backup_start etc)
|
2016-01-12 08:54:52 +01:00
|
|
|
*
|
|
|
|
* This function is mostly for debugging purposes.
|
|
|
|
*/
|
|
|
|
Datum
|
2017-05-11 17:49:59 +02:00
|
|
|
pg_current_wal_flush_lsn(PG_FUNCTION_ARGS)
|
2016-01-12 08:54:52 +01:00
|
|
|
{
|
|
|
|
XLogRecPtr current_recptr;
|
|
|
|
|
|
|
|
if (RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is in progress"),
|
|
|
|
errhint("WAL control functions cannot be executed during recovery.")));
|
|
|
|
|
Remove all use of ThisTimeLineID global variable outside of xlog.c
All such code deals with this global variable in one of three ways.
Sometimes the same functions use it in more than one of these ways
at the same time.
First, sometimes it's an implicit argument to one or more functions
being called in xlog.c or elsewhere, and must be set to the
appropriate value before calling those functions lest they
misbehave. In those cases, it is now passed as an explicit argument
instead.
Second, sometimes it's used to obtain the current timeline after
the end of recovery, i.e. the timeline to which WAL is being
written and flushed. Such code now calls GetWALInsertionTimeLine()
or relies on the new out parameter added to GetFlushRecPtr().
Third, sometimes it's used during recovery to store the current
replay timeline. That can change, so such code must generally
update the value before each use. It can still do that, but must
now use a local variable instead.
The net effect of these changes is to reduce by a fair amount the
amount of code that is directly accessing this global variable.
That's good, because history has shown that we don't always think
clearly about which timeline ID it's supposed to contain at any
given point in time, or indeed, whether it has been or needs to
be initialized at any given point in the code.
Patch by me, reviewed and tested by Michael Paquier, Amul Sul, and
Álvaro Herrera.
Discussion: https://postgr.es/m/CA+TgmobfAAqhfWa1kaFBBFvX+5CjM=7TE=n4r4Q1o2bjbGYBpA@mail.gmail.com
2021-11-05 17:50:01 +01:00
|
|
|
current_recptr = GetFlushRecPtr(NULL);
|
2016-01-12 08:54:52 +01:00
|
|
|
|
|
|
|
PG_RETURN_LSN(current_recptr);
|
|
|
|
}
|
|
|
|
|
2011-11-04 10:37:17 +01:00
|
|
|
/*
|
2022-04-06 20:41:03 +02:00
|
|
|
* Report the last WAL receive location (same format as pg_backup_start etc)
|
2011-11-04 10:37:17 +01:00
|
|
|
*
|
|
|
|
* This is useful for determining how much of WAL is guaranteed to be received
|
|
|
|
* and synced to disk by walreceiver.
|
|
|
|
*/
|
|
|
|
Datum
|
2017-05-11 17:49:59 +02:00
|
|
|
pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
|
|
|
XLogRecPtr recptr;
|
|
|
|
|
2020-04-08 13:45:09 +02:00
|
|
|
recptr = GetWalRcvFlushRecPtr(NULL, NULL);
|
2011-11-04 10:37:17 +01:00
|
|
|
|
2012-06-24 17:51:37 +02:00
|
|
|
if (recptr == 0)
|
2011-11-04 10:37:17 +01:00
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2014-02-19 17:13:44 +01:00
|
|
|
PG_RETURN_LSN(recptr);
|
2011-11-04 10:37:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2022-04-06 20:41:03 +02:00
|
|
|
* Report the last WAL replay location (same format as pg_backup_start etc)
|
2011-11-04 10:37:17 +01:00
|
|
|
*
|
|
|
|
* This is useful for determining how much of WAL is visible to read-only
|
|
|
|
* connections during recovery.
|
|
|
|
*/
|
|
|
|
Datum
|
2017-05-11 17:49:59 +02:00
|
|
|
pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
|
|
|
XLogRecPtr recptr;
|
|
|
|
|
Follow TLI of last replayed record, not recovery target TLI, in walsenders.
Most of the time, the last replayed record comes from the recovery target
timeline, but there is a corner case where it makes a difference. When
the startup process scans for a new timeline, and decides to change recovery
target timeline, there is a window where the recovery target TLI has already
been bumped, but there are no WAL segments from the new timeline in pg_xlog
yet. For example, if we have just replayed up to point 0/30002D8, on
timeline 1, there is a WAL file called 000000010000000000000003 in pg_xlog
that contains the WAL up to that point. When recovery switches recovery
target timeline to 2, a walsender can immediately try to read WAL from
0/30002D8, from timeline 2, so it will try to open WAL file
000000020000000000000003. However, that doesn't exist yet - the startup
process hasn't copied that file from the archive yet nor has the walreceiver
streamed it yet, so walsender fails with error "requested WAL segment
000000020000000000000003 has already been removed". That's harmless, in that
the standby will try to reconnect later and by that time the segment is
already created, but error messages that should be ignored are not good.
To fix that, have walsender track the TLI of the last replayed record,
instead of the recovery target timeline. That way walsender will not try to
read anything from timeline 2, until the WAL segment has been created and at
least one record has been replayed from it. The recovery target timeline is
now xlog.c's internal affair, it doesn't need to be exposed in shared memory
anymore.
This fixes the error reported by Thom Brown. depesz the same error message,
but I'm not sure if this fixes his scenario.
2012-12-20 13:23:31 +01:00
|
|
|
recptr = GetXLogReplayRecPtr(NULL);
|
2011-11-04 10:37:17 +01:00
|
|
|
|
2012-06-24 17:51:37 +02:00
|
|
|
if (recptr == 0)
|
2011-11-04 10:37:17 +01:00
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2014-02-19 17:13:44 +01:00
|
|
|
PG_RETURN_LSN(recptr);
|
2011-11-04 10:37:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute an xlog file name and decimal byte offset given a WAL location,
|
2022-04-06 20:41:03 +02:00
|
|
|
* such as is returned by pg_backup_stop() or pg_switch_wal().
|
2011-11-04 10:37:17 +01:00
|
|
|
*
|
|
|
|
* Note that a location exactly at a segment boundary is taken to be in
|
|
|
|
* the previous segment. This is usually the right thing, since the
|
|
|
|
* expected usage is to determine which xlog file(s) are ready to archive.
|
|
|
|
*/
|
|
|
|
Datum
|
2017-02-09 21:10:09 +01:00
|
|
|
pg_walfile_name_offset(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
2012-06-24 17:06:38 +02:00
|
|
|
XLogSegNo xlogsegno;
|
2011-11-04 10:37:17 +01:00
|
|
|
uint32 xrecoff;
|
2014-02-19 17:13:44 +01:00
|
|
|
XLogRecPtr locationpoint = PG_GETARG_LSN(0);
|
2011-11-04 10:37:17 +01:00
|
|
|
char xlogfilename[MAXFNAMELEN];
|
|
|
|
Datum values[2];
|
|
|
|
bool isnull[2];
|
|
|
|
TupleDesc resultTupleDesc;
|
|
|
|
HeapTuple resultHeapTuple;
|
|
|
|
Datum result;
|
|
|
|
|
|
|
|
if (RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is in progress"),
|
2018-12-19 18:51:13 +01:00
|
|
|
errhint("%s cannot be executed during recovery.",
|
|
|
|
"pg_walfile_name_offset()")));
|
2011-11-04 10:37:17 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct a tuple descriptor for the result row. This must match this
|
|
|
|
* function's pg_proc entry!
|
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
resultTupleDesc = CreateTemplateTupleDesc(2);
|
2011-11-04 10:37:17 +01:00
|
|
|
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "file_name",
|
|
|
|
TEXTOID, -1, 0);
|
|
|
|
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "file_offset",
|
|
|
|
INT4OID, -1, 0);
|
|
|
|
|
|
|
|
resultTupleDesc = BlessTupleDesc(resultTupleDesc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* xlogfilename
|
|
|
|
*/
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size);
|
Remove all use of ThisTimeLineID global variable outside of xlog.c
All such code deals with this global variable in one of three ways.
Sometimes the same functions use it in more than one of these ways
at the same time.
First, sometimes it's an implicit argument to one or more functions
being called in xlog.c or elsewhere, and must be set to the
appropriate value before calling those functions lest they
misbehave. In those cases, it is now passed as an explicit argument
instead.
Second, sometimes it's used to obtain the current timeline after
the end of recovery, i.e. the timeline to which WAL is being
written and flushed. Such code now calls GetWALInsertionTimeLine()
or relies on the new out parameter added to GetFlushRecPtr().
Third, sometimes it's used during recovery to store the current
replay timeline. That can change, so such code must generally
update the value before each use. It can still do that, but must
now use a local variable instead.
The net effect of these changes is to reduce by a fair amount the
amount of code that is directly accessing this global variable.
That's good, because history has shown that we don't always think
clearly about which timeline ID it's supposed to contain at any
given point in time, or indeed, whether it has been or needs to
be initialized at any given point in the code.
Patch by me, reviewed and tested by Michael Paquier, Amul Sul, and
Álvaro Herrera.
Discussion: https://postgr.es/m/CA+TgmobfAAqhfWa1kaFBBFvX+5CjM=7TE=n4r4Q1o2bjbGYBpA@mail.gmail.com
2021-11-05 17:50:01 +01:00
|
|
|
XLogFileName(xlogfilename, GetWALInsertionTimeLine(), xlogsegno,
|
|
|
|
wal_segment_size);
|
2011-11-04 10:37:17 +01:00
|
|
|
|
|
|
|
values[0] = CStringGetTextDatum(xlogfilename);
|
|
|
|
isnull[0] = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* offset
|
|
|
|
*/
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
xrecoff = XLogSegmentOffset(locationpoint, wal_segment_size);
|
2011-11-04 10:37:17 +01:00
|
|
|
|
|
|
|
values[1] = UInt32GetDatum(xrecoff);
|
|
|
|
isnull[1] = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tuple jam: Having first prepared your Datums, then squash together
|
|
|
|
*/
|
|
|
|
resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
|
|
|
|
|
|
|
|
result = HeapTupleGetDatum(resultHeapTuple);
|
|
|
|
|
|
|
|
PG_RETURN_DATUM(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute an xlog file name given a WAL location,
|
2022-04-06 20:41:03 +02:00
|
|
|
* such as is returned by pg_backup_stop() or pg_switch_wal().
|
2011-11-04 10:37:17 +01:00
|
|
|
*/
|
|
|
|
Datum
|
2017-02-09 21:10:09 +01:00
|
|
|
pg_walfile_name(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
2012-06-24 17:06:38 +02:00
|
|
|
XLogSegNo xlogsegno;
|
2014-02-19 17:13:44 +01:00
|
|
|
XLogRecPtr locationpoint = PG_GETARG_LSN(0);
|
2011-11-04 10:37:17 +01:00
|
|
|
char xlogfilename[MAXFNAMELEN];
|
|
|
|
|
|
|
|
if (RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is in progress"),
|
2018-12-19 18:51:13 +01:00
|
|
|
errhint("%s cannot be executed during recovery.",
|
|
|
|
"pg_walfile_name()")));
|
2011-11-04 10:37:17 +01:00
|
|
|
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size);
|
Remove all use of ThisTimeLineID global variable outside of xlog.c
All such code deals with this global variable in one of three ways.
Sometimes the same functions use it in more than one of these ways
at the same time.
First, sometimes it's an implicit argument to one or more functions
being called in xlog.c or elsewhere, and must be set to the
appropriate value before calling those functions lest they
misbehave. In those cases, it is now passed as an explicit argument
instead.
Second, sometimes it's used to obtain the current timeline after
the end of recovery, i.e. the timeline to which WAL is being
written and flushed. Such code now calls GetWALInsertionTimeLine()
or relies on the new out parameter added to GetFlushRecPtr().
Third, sometimes it's used during recovery to store the current
replay timeline. That can change, so such code must generally
update the value before each use. It can still do that, but must
now use a local variable instead.
The net effect of these changes is to reduce by a fair amount the
amount of code that is directly accessing this global variable.
That's good, because history has shown that we don't always think
clearly about which timeline ID it's supposed to contain at any
given point in time, or indeed, whether it has been or needs to
be initialized at any given point in the code.
Patch by me, reviewed and tested by Michael Paquier, Amul Sul, and
Álvaro Herrera.
Discussion: https://postgr.es/m/CA+TgmobfAAqhfWa1kaFBBFvX+5CjM=7TE=n4r4Q1o2bjbGYBpA@mail.gmail.com
2021-11-05 17:50:01 +01:00
|
|
|
XLogFileName(xlogfilename, GetWALInsertionTimeLine(), xlogsegno,
|
|
|
|
wal_segment_size);
|
2011-11-04 10:37:17 +01:00
|
|
|
|
|
|
|
PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
Be clear about whether a recovery pause has taken effect.
Previously, the code and documentation seem to have essentially
assumed than a call to pg_wal_replay_pause() would take place
immediately, but that's not the case, because we only check for a
pause in certain places. This means that a tool that uses this
function and then wants to do something else afterward that is
dependent on the pause having taken effect doesn't know how long it
needs to wait to be sure that no more WAL is going to be replayed.
To avoid that, add a new function pg_get_wal_replay_pause_state()
which returns either 'not paused', 'paused requested', or 'paused'.
After calling pg_wal_replay_pause() the status will immediate change
from 'not paused' to 'pause requested'; when the startup process
has noticed this, the status will change to 'pause'. For backward
compatibility, pg_is_wal_replay_paused() still exists and returns
the same thing as before: true if a pause has been requested,
whether or not it has taken effect yet; and false if not.
The documentation is updated to clarify.
To improve the changes that a pause request is quickly confirmed
effective, adjust things so that WaitForWALToBecomeAvailable will
swiftly reach a call to recoveryPausesHere() when a pause request
is made.
Dilip Kumar, reviewed by Simon Riggs, Kyotaro Horiguchi, Yugo Nagata,
Masahiko Sawada, and Bharath Rupireddy.
Discussion: http://postgr.es/m/CAFiTN-vcLLWEm8Zr%3DYK83rgYrT9pbC8VJCfa1kY9vL3AUPfu6g%40mail.gmail.com
2021-03-11 20:52:32 +01:00
|
|
|
* pg_wal_replay_pause - Request to pause recovery
|
2016-04-07 03:45:32 +02:00
|
|
|
*
|
|
|
|
* Permission checking for this function is managed through the normal
|
|
|
|
* GRANT system.
|
2011-11-04 10:37:17 +01:00
|
|
|
*/
|
|
|
|
Datum
|
2017-02-09 21:10:09 +01:00
|
|
|
pg_wal_replay_pause(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
|
|
|
if (!RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is not in progress"),
|
|
|
|
errhint("Recovery control functions can only be executed during recovery.")));
|
|
|
|
|
2020-03-24 04:46:48 +01:00
|
|
|
if (PromoteIsTriggered())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("standby promotion is ongoing"),
|
|
|
|
errhint("%s cannot be executed after promotion is triggered.",
|
|
|
|
"pg_wal_replay_pause()")));
|
|
|
|
|
2011-11-04 10:37:17 +01:00
|
|
|
SetRecoveryPause(true);
|
|
|
|
|
Be clear about whether a recovery pause has taken effect.
Previously, the code and documentation seem to have essentially
assumed than a call to pg_wal_replay_pause() would take place
immediately, but that's not the case, because we only check for a
pause in certain places. This means that a tool that uses this
function and then wants to do something else afterward that is
dependent on the pause having taken effect doesn't know how long it
needs to wait to be sure that no more WAL is going to be replayed.
To avoid that, add a new function pg_get_wal_replay_pause_state()
which returns either 'not paused', 'paused requested', or 'paused'.
After calling pg_wal_replay_pause() the status will immediate change
from 'not paused' to 'pause requested'; when the startup process
has noticed this, the status will change to 'pause'. For backward
compatibility, pg_is_wal_replay_paused() still exists and returns
the same thing as before: true if a pause has been requested,
whether or not it has taken effect yet; and false if not.
The documentation is updated to clarify.
To improve the changes that a pause request is quickly confirmed
effective, adjust things so that WaitForWALToBecomeAvailable will
swiftly reach a call to recoveryPausesHere() when a pause request
is made.
Dilip Kumar, reviewed by Simon Riggs, Kyotaro Horiguchi, Yugo Nagata,
Masahiko Sawada, and Bharath Rupireddy.
Discussion: http://postgr.es/m/CAFiTN-vcLLWEm8Zr%3DYK83rgYrT9pbC8VJCfa1kY9vL3AUPfu6g%40mail.gmail.com
2021-03-11 20:52:32 +01:00
|
|
|
/* wake up the recovery process so that it can process the pause request */
|
|
|
|
WakeupRecovery();
|
|
|
|
|
2011-11-04 10:37:17 +01:00
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-02-09 21:10:09 +01:00
|
|
|
* pg_wal_replay_resume - resume recovery now
|
2016-04-07 03:45:32 +02:00
|
|
|
*
|
|
|
|
* Permission checking for this function is managed through the normal
|
|
|
|
* GRANT system.
|
2011-11-04 10:37:17 +01:00
|
|
|
*/
|
|
|
|
Datum
|
2017-02-09 21:10:09 +01:00
|
|
|
pg_wal_replay_resume(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
|
|
|
if (!RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is not in progress"),
|
|
|
|
errhint("Recovery control functions can only be executed during recovery.")));
|
|
|
|
|
2020-03-24 04:46:48 +01:00
|
|
|
if (PromoteIsTriggered())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("standby promotion is ongoing"),
|
|
|
|
errhint("%s cannot be executed after promotion is triggered.",
|
|
|
|
"pg_wal_replay_resume()")));
|
|
|
|
|
2011-11-04 10:37:17 +01:00
|
|
|
SetRecoveryPause(false);
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-02-09 21:10:09 +01:00
|
|
|
* pg_is_wal_replay_paused
|
2011-11-04 10:37:17 +01:00
|
|
|
*/
|
|
|
|
Datum
|
2017-02-09 21:10:09 +01:00
|
|
|
pg_is_wal_replay_paused(PG_FUNCTION_ARGS)
|
2011-11-04 10:37:17 +01:00
|
|
|
{
|
|
|
|
if (!RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is not in progress"),
|
|
|
|
errhint("Recovery control functions can only be executed during recovery.")));
|
|
|
|
|
Be clear about whether a recovery pause has taken effect.
Previously, the code and documentation seem to have essentially
assumed than a call to pg_wal_replay_pause() would take place
immediately, but that's not the case, because we only check for a
pause in certain places. This means that a tool that uses this
function and then wants to do something else afterward that is
dependent on the pause having taken effect doesn't know how long it
needs to wait to be sure that no more WAL is going to be replayed.
To avoid that, add a new function pg_get_wal_replay_pause_state()
which returns either 'not paused', 'paused requested', or 'paused'.
After calling pg_wal_replay_pause() the status will immediate change
from 'not paused' to 'pause requested'; when the startup process
has noticed this, the status will change to 'pause'. For backward
compatibility, pg_is_wal_replay_paused() still exists and returns
the same thing as before: true if a pause has been requested,
whether or not it has taken effect yet; and false if not.
The documentation is updated to clarify.
To improve the changes that a pause request is quickly confirmed
effective, adjust things so that WaitForWALToBecomeAvailable will
swiftly reach a call to recoveryPausesHere() when a pause request
is made.
Dilip Kumar, reviewed by Simon Riggs, Kyotaro Horiguchi, Yugo Nagata,
Masahiko Sawada, and Bharath Rupireddy.
Discussion: http://postgr.es/m/CAFiTN-vcLLWEm8Zr%3DYK83rgYrT9pbC8VJCfa1kY9vL3AUPfu6g%40mail.gmail.com
2021-03-11 20:52:32 +01:00
|
|
|
PG_RETURN_BOOL(GetRecoveryPauseState() != RECOVERY_NOT_PAUSED);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_get_wal_replay_pause_state - Returns the recovery pause state.
|
|
|
|
*
|
|
|
|
* Returned values:
|
|
|
|
*
|
|
|
|
* 'not paused' - if pause is not requested
|
|
|
|
* 'pause requested' - if pause is requested but recovery is not yet paused
|
|
|
|
* 'paused' - if recovery is paused
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_get_wal_replay_pause_state(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *statestr = NULL;
|
|
|
|
|
|
|
|
if (!RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is not in progress"),
|
|
|
|
errhint("Recovery control functions can only be executed during recovery.")));
|
|
|
|
|
|
|
|
/* get the recovery pause state */
|
|
|
|
switch (GetRecoveryPauseState())
|
|
|
|
{
|
|
|
|
case RECOVERY_NOT_PAUSED:
|
|
|
|
statestr = "not paused";
|
|
|
|
break;
|
|
|
|
case RECOVERY_PAUSE_REQUESTED:
|
|
|
|
statestr = "pause requested";
|
|
|
|
break;
|
|
|
|
case RECOVERY_PAUSED:
|
|
|
|
statestr = "paused";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Assert(statestr != NULL);
|
|
|
|
PG_RETURN_TEXT_P(cstring_to_text(statestr));
|
2011-11-04 10:37:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns timestamp of latest processed commit/abort record.
|
|
|
|
*
|
|
|
|
* When the server has been started normally without recovery the function
|
|
|
|
* returns NULL.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_last_xact_replay_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
TimestampTz xtime;
|
|
|
|
|
|
|
|
xtime = GetLatestXTime();
|
|
|
|
if (xtime == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMPTZ(xtime);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns bool with current recovery mode, a global state.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_is_in_recovery(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_BOOL(RecoveryInProgress());
|
|
|
|
}
|
2012-03-04 12:15:24 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute the difference in bytes between two WAL locations.
|
|
|
|
*/
|
|
|
|
Datum
|
2017-05-11 17:49:59 +02:00
|
|
|
pg_wal_lsn_diff(PG_FUNCTION_ARGS)
|
2012-03-04 12:15:24 +01:00
|
|
|
{
|
2014-02-19 17:13:44 +01:00
|
|
|
Datum result;
|
2012-03-04 12:15:24 +01:00
|
|
|
|
2014-02-19 17:13:44 +01:00
|
|
|
result = DirectFunctionCall2(pg_lsn_mi,
|
|
|
|
PG_GETARG_DATUM(0),
|
|
|
|
PG_GETARG_DATUM(1));
|
2012-03-04 12:15:24 +01:00
|
|
|
|
|
|
|
PG_RETURN_NUMERIC(result);
|
|
|
|
}
|
2012-06-14 19:25:43 +02:00
|
|
|
|
2018-10-25 02:46:00 +02:00
|
|
|
/*
|
|
|
|
* Promotes a standby server.
|
|
|
|
*
|
|
|
|
* A result of "true" means that promotion has been completed if "wait" is
|
|
|
|
* "true", or initiated if "wait" is false.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_promote(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
bool wait = PG_GETARG_BOOL(0);
|
|
|
|
int wait_seconds = PG_GETARG_INT32(1);
|
|
|
|
FILE *promote_file;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!RecoveryInProgress())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("recovery is not in progress"),
|
|
|
|
errhint("Recovery control functions can only be executed during recovery.")));
|
|
|
|
|
|
|
|
if (wait_seconds <= 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
2019-09-23 13:37:33 +02:00
|
|
|
errmsg("\"wait_seconds\" must not be negative or zero")));
|
2018-10-25 02:46:00 +02:00
|
|
|
|
|
|
|
/* create the promote signal file */
|
|
|
|
promote_file = AllocateFile(PROMOTE_SIGNAL_FILE, "w");
|
|
|
|
if (!promote_file)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not create file \"%s\": %m",
|
|
|
|
PROMOTE_SIGNAL_FILE)));
|
|
|
|
|
|
|
|
if (FreeFile(promote_file))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not write file \"%s\": %m",
|
|
|
|
PROMOTE_SIGNAL_FILE)));
|
|
|
|
|
|
|
|
/* signal the postmaster */
|
|
|
|
if (kill(PostmasterPid, SIGUSR1) != 0)
|
|
|
|
{
|
|
|
|
ereport(WARNING,
|
|
|
|
(errmsg("failed to send signal to postmaster: %m")));
|
|
|
|
(void) unlink(PROMOTE_SIGNAL_FILE);
|
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return immediately if waiting was not requested */
|
|
|
|
if (!wait)
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
|
|
|
|
/* wait for the amount of time wanted until promotion */
|
|
|
|
#define WAITS_PER_SECOND 10
|
|
|
|
for (i = 0; i < WAITS_PER_SECOND * wait_seconds; i++)
|
|
|
|
{
|
2019-09-06 07:27:25 +02:00
|
|
|
int rc;
|
|
|
|
|
2018-10-25 02:46:00 +02:00
|
|
|
ResetLatch(MyLatch);
|
|
|
|
|
|
|
|
if (!RecoveryInProgress())
|
|
|
|
PG_RETURN_BOOL(true);
|
|
|
|
|
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
|
2019-09-06 07:27:25 +02:00
|
|
|
rc = WaitLatch(MyLatch,
|
|
|
|
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
|
|
|
|
1000L / WAITS_PER_SECOND,
|
|
|
|
WAIT_EVENT_PROMOTE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Emergency bailout if postmaster has died. This is to avoid the
|
|
|
|
* necessity for manual cleanup of all postmaster children.
|
|
|
|
*/
|
|
|
|
if (rc & WL_POSTMASTER_DEATH)
|
|
|
|
PG_RETURN_BOOL(false);
|
2018-10-25 02:46:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ereport(WARNING,
|
2021-02-10 10:47:29 +01:00
|
|
|
(errmsg_plural("server did not promote within %d second",
|
|
|
|
"server did not promote within %d seconds",
|
|
|
|
wait_seconds,
|
|
|
|
wait_seconds)));
|
2018-10-25 02:46:00 +02:00
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
}
|